diff options
author | Nassim Jahnke <[email protected]> | 2024-12-21 13:45:04 +0100 |
---|---|---|
committer | Nassim Jahnke <[email protected]> | 2024-12-21 13:45:04 +0100 |
commit | 3b0b3a0aef5863b37f252bfffef7ff5b9b266445 (patch) | |
tree | d6088aef454eff0d163847ebdcc5eb349fcac9bb /paper-server/patches/features/0004-Anti-Xray.patch | |
parent | 82216a59fef17863c86192c2754417480baa71c1 (diff) | |
download | Paper-3b0b3a0aef5863b37f252bfffef7ff5b9b266445.tar.gz Paper-3b0b3a0aef5863b37f252bfffef7ff5b9b266445.zip |
and some more
Diffstat (limited to 'paper-server/patches/features/0004-Anti-Xray.patch')
-rw-r--r-- | paper-server/patches/features/0004-Anti-Xray.patch | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/paper-server/patches/features/0004-Anti-Xray.patch b/paper-server/patches/features/0004-Anti-Xray.patch new file mode 100644 index 0000000000..1991ec6d25 --- /dev/null +++ b/paper-server/patches/features/0004-Anti-Xray.patch @@ -0,0 +1,623 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: stonar96 <[email protected]> +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 + |