aboutsummaryrefslogtreecommitdiffhomepage
path: root/paper-server/patches/features/0004-Anti-Xray.patch
blob: 1991ec6d25215845f7f1014beb529b29e2d9275e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: stonar96 <minecraft.stonar96@gmail.com>
Date: Thu, 25 Nov 2021 13:27:51 +0100
Subject: [PATCH] Anti-Xray


diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java
index b97e0a8d4c429776b86def10739faee089e2bc9b..184e6c6fe2ba522d0ea0774604839320c4152371 100644
--- a/io/papermc/paper/FeatureHooks.java
+++ b/io/papermc/paper/FeatureHooks.java
@@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.longs.LongSets;
 import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
 import it.unimi.dsi.fastutil.objects.ObjectSet;
 import it.unimi.dsi.fastutil.objects.ObjectSets;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -36,20 +37,25 @@ public final class FeatureHooks {
     }
 
     public static LevelChunkSection createSection(final Registry<Biome> biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) {
-        return new LevelChunkSection(biomeRegistry);
+        return new LevelChunkSection(biomeRegistry, level, chunkPos, chunkSection); // Paper - Anti-Xray - Add parameters
     }
 
     public static void sendChunkRefreshPackets(final List<ServerPlayer> playersInRange, final LevelChunk chunk) {
-        final ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null);
+        // Paper start - Anti-Xray
+        final Map<Object, ClientboundLevelChunkWithLightPacket> refreshPackets = new HashMap<>();
         for (final ServerPlayer player : playersInRange) {
             if (player.connection == null) continue;
 
-            player.connection.send(refreshPacket);
+            final Boolean shouldModify = chunk.getLevel().chunkPacketBlockController.shouldModify(player, chunk);
+            player.connection.send(refreshPackets.computeIfAbsent(shouldModify, s -> { // Use connection to prevent creating firing event
+                return new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, (Boolean) s);
+            }));
         }
+        // Paper end - Anti-Xray
     }
 
     public static PalettedContainer<BlockState> emptyPalettedBlockContainer() {
-        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
+        return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); // Paper - Anti-Xray - Add preset block states
     }
 
     public static Set<Long> getSentChunkKeys(final ServerPlayer player) {
diff --git a/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java b/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
index d4872b7f4e9591b3b1c67406312905851303f521..cb41460e94161675e2ab43f4b1b5286ee38e2e13 100644
--- a/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
@@ -70,8 +70,10 @@ public record ClientboundChunksBiomesPacket(List<ClientboundChunksBiomesPacket.C
         }
 
         public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
+            int chunkSectionIndex = 0; // Paper - Anti-Xray
             for (LevelChunkSection levelChunkSection : chunk.getSections()) {
-                levelChunkSection.getBiomes().write(buffer);
+                levelChunkSection.getBiomes().write(buffer, null, chunkSectionIndex); // Paper - Anti-Xray
+                chunkSectionIndex++; // Paper - Anti-Xray
             }
         }
 
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
index 5d1943d37dfad0c12e77179f0866851532d983e9..3aea76690bc3e35758d3bf274777130af17d8a0f 100644
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
@@ -28,7 +28,13 @@ public class ClientboundLevelChunkPacketData {
     private final byte[] buffer;
     private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
 
+    // Paper start - Anti-Xray - Add chunk packet info
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public ClientboundLevelChunkPacketData(LevelChunk levelChunk) {
+        this(levelChunk, null);
+    }
+    public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
+        // Paper end
         this.heightmaps = new CompoundTag();
 
         for (Entry<Heightmap.Types, Heightmap> entry : levelChunk.getHeightmaps()) {
@@ -38,7 +44,11 @@ public class ClientboundLevelChunkPacketData {
         }
 
         this.buffer = new byte[calculateChunkSize(levelChunk)];
-        extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk);
+        // Paper start - Anti-Xray - Add chunk packet info
+        if (chunkPacketInfo != null) {
+            chunkPacketInfo.setBuffer(this.buffer);
+        }
+        extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
         this.blockEntitiesData = Lists.newArrayList();
 
         for (Entry<BlockPos, BlockEntity> entryx : levelChunk.getBlockEntities().entrySet()) {
@@ -85,9 +95,17 @@ public class ClientboundLevelChunkPacketData {
         return byteBuf;
     }
 
+    // Paper start - Anti-Xray - Add chunk packet info
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk) {
+        ClientboundLevelChunkPacketData.extractChunkData(buffer, chunk, null);
+    }
+    public static void extractChunkData(FriendlyByteBuf buffer, LevelChunk chunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
+        int chunkSectionIndex = 0;
         for (LevelChunkSection levelChunkSection : chunk.getSections()) {
-            levelChunkSection.write(buffer);
+            levelChunkSection.write(buffer, chunkPacketInfo, chunkSectionIndex);
+            chunkSectionIndex++;
+            // Paper end  - Anti-Xray - Add chunk packet info
         }
     }
 
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
index 3a384175f8e7f204234bbaf3081bdc20c47a0d4b..5699bc15eba92e22433a20cb8326b59f2ebd3036 100644
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
@@ -18,18 +18,31 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
     private final int z;
     private final ClientboundLevelChunkPacketData chunkData;
     private final ClientboundLightUpdatePacketData lightData;
-    // Paper start - Anti-Xray
+    // Paper start - Async-Anti-Xray - Ready flag for the connection, add chunk packet info
+    private volatile boolean ready;
+
+    @Override
+    public boolean isReady() {
+        return this.ready;
+    }
+
     public void setReady(final boolean ready) {
-        // Empty hook, updated by feature patch
+        this.ready = ready;
     }
-    // Paper end - Anti-Xray
 
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight) {
+        this(chunk, lightEngine, skyLight, blockLight, true);
+    }
+    public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight, boolean modifyBlocks) {
+        // Paper end - Anti-Xray
         ChunkPos pos = chunk.getPos();
         this.x = pos.x;
         this.z = pos.z;
-        this.chunkData = new ClientboundLevelChunkPacketData(chunk);
+        io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray
+        this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo); // Paper - Anti-Xray
         this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
+        chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
     }
 
     private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index da8848e2a3e3745949eb2356a049451d30f763a7..192977dd661ee795ada13db895db770293e9b402 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -348,7 +348,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
         org.bukkit.generator.BiomeProvider biomeProvider // CraftBukkit
     ) {
         // CraftBukkit start
-        super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules()))); // Paper - create paper world configs
+        super(serverLevelData, dimension, server.registryAccess(), levelStem.type(), false, isDebug, biomeZoomSeed, server.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> server.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(levelStorageAccess.levelDirectory.path(), serverLevelData.getLevelName(), dimension.location(), spigotConfig, server.registryAccess(), serverLevelData.getGameRules())), dispatcher); // Paper - create paper world configs; Async-Anti-Xray: Pass executor
         this.pvpMode = server.isPvpAllowed();
         this.levelStorageAccess = levelStorageAccess;
         this.uuid = org.bukkit.craftbukkit.util.WorldUUID.getUUID(levelStorageAccess.levelDirectory.path().toFile());
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
index 47ed3ad5c0b4753f58e0bafff5e5e70b2f0bb40b..623c069f1fe079e020c6391a3db1a3d95cd3dbf5 100644
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -299,6 +299,7 @@ public class ServerPlayerGameMode {
                 org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelected()); // CraftBukkit
             }
         }
+        this.level.chunkPacketBlockController.onPlayerLeftClickBlock(this, pos, action, face, maxBuildHeight, sequence); // Paper - Anti-Xray
     }
 
     public void destroyAndAck(BlockPos pos, int sequence, String message) {
diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java
index 342bc843c384761e883de861044f4f8930ae8763..14878690a88fd4de3e2c127086607e6c819c636c 100644
--- a/net/minecraft/server/network/PlayerChunkSender.java
+++ b/net/minecraft/server/network/PlayerChunkSender.java
@@ -78,8 +78,11 @@ public class PlayerChunkSender {
         }
     }
 
-    private static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
-        packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null));
+    // Paper start - Anti-Xray
+    public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
+        final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk);
+        packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
+        // Paper end - Anti-Xray
         // Paper start - PlayerChunkLoadEvent
         if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
             new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), packetListener.getPlayer().getBukkitEntity()).callEvent();
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 38fb0f569ffcd96e0eb6cb6f0769155a17d62874..3d5d84c1c1d431e9b369aa727ab0876f90ff5d61 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -403,7 +403,7 @@ public abstract class PlayerList {
                     .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
             player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
                     new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, player.chunkPosition(), plains),
-                    serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null)
+                    serverLevel.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null, true) // Paper - Anti-Xray
             );
         }
         // Paper end - Send empty chunk
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 0f346faa82b988e86834c38837f6f11bea7f31c6..771d6ed6a7c889c09efd4ff6e20298c851eaa79f 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -168,6 +168,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
     }
     // Paper end - add paper world config
 
+    public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
     public static BlockPos lastPhysicsProblem; // Spigot
     private org.spigotmc.TickLimiter entityLimiter;
     private org.spigotmc.TickLimiter tileLimiter;
@@ -214,7 +215,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
         org.bukkit.generator.BiomeProvider biomeProvider, // CraftBukkit
         org.bukkit.World.Environment env, // CraftBukkit
         java.util.function.Function<org.spigotmc.SpigotWorldConfig, // Spigot - create per world config
-        io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator // Paper - create paper world config
+        io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, // Paper - create paper world config
+        java.util.concurrent.Executor executor // Paper - Anti-Xray
     ) {
         this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
         this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
@@ -295,6 +297,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
         // CraftBukkit end
         this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime);
         this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime);
+        this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
     }
 
     // Paper start - Cancel hit for vanished players
@@ -495,6 +498,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
             // CraftBukkit end
 
             BlockState blockState = chunkAt.setBlockState(pos, state, (flags & 64) != 0, (flags & 1024) == 0); // CraftBukkit custom NO_PLACE flag
+            this.chunkPacketBlockController.onBlockChange(this, pos, state, blockState, flags, recursionLeft); // Paper - Anti-Xray
 
             if (blockState == null) {
                 // CraftBukkit start - remove blockstate if failed (or the same)
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
index 809b3c37d3749c76c3c243cd91c593d03693e9b3..860d1c9729c4ee97ec6f40f7aa969829070b27c0 100644
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -114,14 +114,14 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
             }
         }
 
-        replaceMissingSections(biomeRegistry, this.sections);
+        this.replaceMissingSections(biomeRegistry, this.sections); // Paper - Anti-Xray - make it a non-static method
         this.biomeRegistry = biomeRegistry; // CraftBukkit
     }
 
-    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
             }
         }
     }
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 51a136cf015de730ca0d1b48cf618a2ed69ea89f..96b0342ab7b922aa16d07b6c00542e6cb66c974a 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -109,7 +109,7 @@ public class LevelChunk extends ChunkAccess {
         @Nullable LevelChunk.PostLoadProcessor postLoad,
         @Nullable BlendingData blendingData
     ) {
-        super(pos, data, level, level.registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData);
+        super(pos, data, level, net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry
         this.level = (net.minecraft.server.level.ServerLevel) level; // CraftBukkit - type
         this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
 
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
index baa9f3e2e6e45c250930658e82bad70a3a292b05..fc21c3268c4b4fda2933d71f0913db28e3796653 100644
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -38,9 +38,15 @@ public class LevelChunkSection {
         this.recalcBlockCounts();
     }
 
+    // Paper start - Anti-Xray - Add parameters
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public LevelChunkSection(Registry<Biome> biomeRegistry) {
-        this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
-        this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
+        this(biomeRegistry, null, null, 0);
+    }
+    public LevelChunkSection(Registry<Biome> biomeRegistry, net.minecraft.world.level.Level level, net.minecraft.world.level.ChunkPos chunkPos, int chunkSectionY) {
+        // Paper end - Anti-Xray
+        this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, level == null || level.chunkPacketBlockController == null ? null : level.chunkPacketBlockController.getPresetBlockStates(level, chunkPos, chunkSectionY)); // Paper - Anti-Xray - Add preset block states
+        this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null); // Paper - Anti-Xray - Add preset biomes
     }
 
     public BlockState getBlockState(int x, int y, int z) {
@@ -168,10 +174,16 @@ public class LevelChunkSection {
         this.biomes = palettedContainer;
     }
 
+    // Paper start - Anti-Xray - Add chunk packet info
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public void write(FriendlyByteBuf buffer) {
+        this.write(buffer, null, 0);
+    }
+    public void write(FriendlyByteBuf buffer, io.papermc.paper.antixray.ChunkPacketInfo<BlockState> chunkPacketInfo, int chunkSectionIndex) {
         buffer.writeShort(this.nonEmptyBlockCount);
-        this.states.write(buffer);
-        this.biomes.write(buffer);
+        this.states.write(buffer, chunkPacketInfo, chunkSectionIndex);
+        this.biomes.write(buffer, null, chunkSectionIndex);
+        // Paper end - Anti-Xray
     }
 
     public int getSerializedSize() {
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
index e8ec28ce3fe13561b45c4654e174776d9d2d7b71..a6028a54c75de068515e95913b21160ab4326985 100644
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -28,6 +28,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
     private static final int MIN_PALETTE_BITS = 0;
     private final PaletteResize<T> dummyPaletteResize = (bits, objectAdded) -> 0;
     public final IdMap<T> registry;
+    private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values
     private volatile PalettedContainer.Data<T> data;
     private final PalettedContainer.Strategy strategy;
     //private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
@@ -40,13 +41,21 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
         // this.threadingDetector.checkAndUnlock(); // Paper - disable this - use proper synchronization
     }
 
+    // Paper start - Anti-Xray - Add preset values
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
-        PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = PalettedContainer::unpack;
+        return PalettedContainer.codecRW(registry, codec, strategy, value, null);
+    }
+    public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value, T @org.jetbrains.annotations.Nullable [] presetValues) {
+        PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = (idListx, paletteProviderx, serialized) -> {
+            return unpack(idListx, paletteProviderx, serialized, value, presetValues);
+        };
+        // Paper end
         return codec(registry, codec, strategy, value, unpacker);
     }
 
     public static <T> Codec<PalettedContainerRO<T>> codecRO(IdMap<T> registry, Codec<T> codec, PalettedContainer.Strategy strategy, T value) {
-        PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData)
+        PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData, value, null) // Paper - Anti-Xray - Add preset values
             .map(container -> (PalettedContainerRO<T>)container);
         return codec(registry, codec, strategy, value, unpacker);
     }
@@ -66,27 +75,66 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
             );
     }
 
+    // Paper start - Anti-Xray - Add preset values
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
+    public PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values) {
+        this(registry, strategy, configuration, storage, values, null, null);
+    }
     public PalettedContainer(
-        IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values
+        IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration<T> configuration, BitStorage storage, List<T> values, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues
     ) {
+        this.presetValues = presetValues;
         this.registry = registry;
         this.strategy = strategy;
         this.data = new PalettedContainer.Data<>(configuration, storage, configuration.factory().create(configuration.bits(), registry, this, values));
+        if (presetValues != null && (configuration.factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY ? this.data.palette.valueFor(0) != defaultValue : configuration.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 << configuration.bits();
+
+            for (T presetValue : presetValues) {
+                if (this.data.palette.getSize() >= maxSize) {
+                    java.util.Set<T> allValues = new java.util.HashSet<>(values);
+                    allValues.addAll(Arrays.asList(presetValues));
+                    int newBits = Mth.ceillog2(allValues.size());
+
+                    if (newBits > configuration.bits()) {
+                        this.onResize(newBits, null);
+                    }
+
+                    break;
+                }
+
+                this.data.palette.idFor(presetValue);
+            }
+        }
+        // Paper end
     }
 
-    private PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Data<T> data) {
+    // Paper start - Anti-Xray - Add preset values
+    private PalettedContainer(IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainer.Data<T> data, T @org.jetbrains.annotations.Nullable [] presetValues) {
+        this.presetValues = presetValues;
+        // Paper end - Anti-Xray
         this.registry = registry;
         this.strategy = strategy;
         this.data = data;
     }
 
-    private PalettedContainer(PalettedContainer<T> other) {
+    private PalettedContainer(PalettedContainer<T> other, T @org.jetbrains.annotations.Nullable [] presetValues) { // Paper - Anti-Xray - Add preset values
+        this.presetValues = presetValues; // Paper - Anti-Xray - Add preset values
         this.registry = other.registry;
         this.strategy = other.strategy;
         this.data = other.data.copy(this);
     }
 
+    // Paper start - Anti-Xray - Add preset values
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
     public PalettedContainer(IdMap<T> registry, T palette, PalettedContainer.Strategy strategy) {
+        this(registry, palette, strategy, null);
+    }
+    public PalettedContainer(IdMap<T> registry, T palette, PalettedContainer.Strategy strategy, T @org.jetbrains.annotations.Nullable [] presetValues) {
+        this.presetValues = presetValues;
+        // Paper end - Anti-Xray
         this.strategy = strategy;
         this.registry = registry;
         this.data = this.createOrReuseData(null, 0);
@@ -101,11 +149,30 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
     @Override
     public synchronized int onResize(int bits, T objectAdded) { // Paper - synchronize
         PalettedContainer.Data<T> data = this.data;
+        // Paper start - Anti-Xray - Add preset values
+        if (this.presetValues != null && objectAdded != null && data.configuration().factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY) {
+            int duplicates = 0;
+            List<T> presetValues = Arrays.asList(this.presetValues);
+            duplicates += presetValues.contains(objectAdded) ? 1 : 0;
+            duplicates += presetValues.contains(data.palette.valueFor(0)) ? 1 : 0;
+            bits = Mth.ceillog2((1 << this.strategy.calculateBitsForSerialization(this.registry, 1 << bits)) + presetValues.size() - duplicates);
+        }
+        // Paper end - Anti-Xray
         PalettedContainer.Data<T> data1 = this.createOrReuseData(data, bits);
         data1.copyFrom(data.palette, data.storage);
         this.data = data1;
-        return data1.palette.idFor(objectAdded);
+        // Paper start - Anti-Xray
+        this.addPresetValues();
+        return objectAdded == null ? -1 : data1.palette.idFor(objectAdded);
+    }
+    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 - Anti-Xray
 
     public synchronized T getAndSet(int x, int y, int z, T state) { // Paper - synchronize
         this.acquire();
@@ -172,24 +239,35 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
             data.palette.read(buffer);
             buffer.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 synchronized void write(FriendlyByteBuf buffer) { // Paper - synchronize
+    @Deprecated @io.papermc.paper.annotation.DoNotUse
+    public void write(FriendlyByteBuf buffer) {
+        this.write(buffer, null, 0);
+    }
+    @Override
+    public synchronized void write(FriendlyByteBuf buffer, @Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { // Paper - Synchronize
         this.acquire();
 
         try {
-            this.data.write(buffer);
+            this.data.write(buffer, chunkPacketInfo, chunkSectionIndex);
+            if (chunkPacketInfo != null) {
+                chunkPacketInfo.setPresetValues(chunkSectionIndex, this.presetValues);
+            }
+            // Paper end - Anti-Xray
         } finally {
             this.release();
         }
     }
 
     private static <T> DataResult<PalettedContainer<T>> unpack(
-        IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData<T> packedData
+        IdMap<T> registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData<T> packedData, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues // Paper - Anti-Xray - Add preset values
     ) {
         List<T> list = packedData.paletteEntries();
         int size = strategy.size();
@@ -222,7 +300,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
             }
         }
 
-        return DataResult.success(new PalettedContainer<>(registry, strategy, configuration, bitStorage, list));
+        return DataResult.success(new PalettedContainer<>(registry, strategy, configuration, bitStorage, list, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
     }
 
     @Override
@@ -280,12 +358,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
 
     @Override
     public PalettedContainer<T> copy() {
-        return new PalettedContainer<>(this);
+        return new PalettedContainer<>(this, 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
@@ -324,9 +402,16 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
             return 1 + this.palette.getSerializedSize() + VarInt.getByteSize(this.storage.getRaw().length) + this.storage.getRaw().length * 8;
         }
 
-        public void write(FriendlyByteBuf buffer) {
+        // Paper start - Anti-Xray - Add chunk packet info
+        public void write(FriendlyByteBuf buffer, @Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) {
             buffer.writeByte(this.storage.getBits());
             this.palette.write(buffer);
+            if (chunkPacketInfo != null) {
+                chunkPacketInfo.setBits(chunkSectionIndex, this.configuration.bits());
+                chunkPacketInfo.setPalette(chunkSectionIndex, this.palette);
+                chunkPacketInfo.setIndex(chunkSectionIndex, buffer.writerIndex() + VarInt.getByteSize(this.storage.getRaw().length));
+            }
+            // Paper end
             buffer.writeLongArray(this.storage.getRaw());
         }
 
diff --git a/net/minecraft/world/level/chunk/PalettedContainerRO.java b/net/minecraft/world/level/chunk/PalettedContainerRO.java
index bfbb1a2bb4abbb369a24f2f01439e9ea3e16794b..8d6ed8be4d93f7d4e6ea80c351020d88ee98aa4d 100644
--- a/net/minecraft/world/level/chunk/PalettedContainerRO.java
+++ b/net/minecraft/world/level/chunk/PalettedContainerRO.java
@@ -14,7 +14,10 @@ public interface PalettedContainerRO<T> {
 
     void getAll(Consumer<T> consumer);
 
-    void write(FriendlyByteBuf buffer);
+    // Paper start - Anti-Xray - Add chunk packet info
+    @Deprecated @io.papermc.paper.annotation.DoNotUse void write(FriendlyByteBuf buffer);
+    void write(FriendlyByteBuf buffer, @javax.annotation.Nullable io.papermc.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex);
+    // Paper end
 
     int getSerializedSize();
 
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
index 37437a86d74291fab1de9495008aafb15dfadce0..cf6e2053d81f7b0f8c8e58b9c0fad3285ebc047d 100644
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
@@ -94,7 +94,7 @@ public record SerializableChunkData(
     , @Nullable net.minecraft.nbt.Tag persistentDataContainer // CraftBukkit - persistentDataContainer
 ) {
     public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(
-        Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()
+        Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null // Paper - Anti-Xray
     );
     private static final Logger LOGGER = LogUtils.getLogger();
     private static final String TAG_UPGRADE_DATA = "UpgradeData";
@@ -128,6 +128,7 @@ public record SerializableChunkData(
 
     @Nullable
     public static SerializableChunkData parse(LevelHeightAccessor levelHeightAccessor, RegistryAccess registries, CompoundTag tag) {
+        net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) levelHeightAccessor; // Paper - Anti-Xray This is is seemingly only called from ChunkMap, where, we have a server level. We'll fight this later if needed.
         if (!tag.contains("Status", 8)) {
             return null;
         } else {
@@ -212,18 +213,21 @@ public record SerializableChunkData(
             Codec<PalettedContainer<Holder<Biome>>> codec = makeBiomeCodecRW(registry); // CraftBukkit - read/write
 
             for (int i2 = 0; i2 < list7.size(); i2++) {
-                CompoundTag compound2 = list7.getCompound(i2);
+                CompoundTag compound2 = list7.getCompound(i2); final CompoundTag sectionData = compound2; // Paper - Anti-Xray - OBFHELPER
                 int _byte = compound2.getByte("Y");
                 LevelChunkSection levelChunkSection;
                 if (_byte >= levelHeightAccessor.getMinSectionY() && _byte <= levelHeightAccessor.getMaxSectionY()) {
+                    // Paper start - Anti-Xray - Add preset block states
+                    BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, _byte);
                     PalettedContainer<BlockState> palettedContainer;
                     if (compound2.contains("block_states", 10)) {
-                        palettedContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, compound2.getCompound("block_states"))
+                        Codec<PalettedContainer<BlockState>> blockStateCodec = presetBlockStates == null ? BLOCK_STATE_CODEC : PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray
+                        palettedContainer = blockStateCodec.parse(NbtOps.INSTANCE, sectionData.getCompound("block_states")) // Paper - Anti-Xray
                             .promotePartial(string -> logErrors(chunkPos, _byte, string))
                             .getOrThrow(SerializableChunkData.ChunkReadException::new);
                     } else {
                         palettedContainer = new PalettedContainer<>(
-                            Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES
+                            Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, presetBlockStates // Paper - Anti-Xray
                         );
                     }
 
@@ -234,7 +238,7 @@ public record SerializableChunkData(
                             .getOrThrow(SerializableChunkData.ChunkReadException::new);
                     } else {
                         palettedContainerRo = new PalettedContainer<>(
-                            registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES
+                            registry.asHolderIdMap(), registry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null // Paper - Anti-Xray - Add preset biomes
                         );
                     }
 
@@ -414,7 +418,7 @@ public record SerializableChunkData(
 
     // CraftBukkit start - read/write
     private static Codec<PalettedContainer<Holder<Biome>>> makeBiomeCodecRW(Registry<Biome> iregistry) {
-        return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS));
+        return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getOrThrow(Biomes.PLAINS), null); // Paper - Anti-Xray - Add preset biomes
     }
     // CraftBukkit end