From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: stonar96 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 81ff677e970ffbe7ad5381e56852e33cf7a8ea45..184e6c6fe2ba522d0ea0774604839320c4152371 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -37,20 +37,25 @@ public final class FeatureHooks { } public static LevelChunkSection createSection(final Registry 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 playersInRange, final LevelChunk chunk) { - final ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null); + // Paper start - Anti-Xray + final Map 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 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 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 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 chunkPacketInfo) { + // Paper end this.heightmaps = new CompoundTag(); for (Entry 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 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 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 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 600a08d6b45cb19dbe551cefbf726e68684a0837..ff0315cffdb282fdc0a1ffd15e2954caa76835c9 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 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 c82780db7fe5b1557a7802d3111f38099be55ac1..d63d745a0220963a297cfedf1e8983aeb471a045 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 biomeRegistry, LevelChunkSection[] sections) { + private void replaceMissingSections(Registry 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 ce781ba2c8b3f9f051201d3809a9cb041036f93a..cad71ac79fc52225a192aa5c5d07b13c831fc2c1 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 = (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 b3d600b0d6deaf44f232dfc86e1456c867e1c07f..a7fabde0f32f09d7f7bed65576ce469f069a21fa 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 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 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 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 implements PaletteResize, PalettedContainer private static final int MIN_PALETTE_BITS = 0; private final PaletteResize dummyPaletteResize = (bits, objectAdded) -> 0; public final IdMap registry; + private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values private volatile PalettedContainer.Data data; private final PalettedContainer.Strategy strategy; //private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused @@ -40,13 +41,21 @@ public class PalettedContainer implements PaletteResize, 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 Codec> codecRW(IdMap registry, Codec codec, PalettedContainer.Strategy strategy, T value) { - PalettedContainerRO.Unpacker> unpacker = PalettedContainer::unpack; + return PalettedContainer.codecRW(registry, codec, strategy, value, null); + } + public static Codec> codecRW(IdMap registry, Codec codec, PalettedContainer.Strategy strategy, T value, T @org.jetbrains.annotations.Nullable [] presetValues) { + PalettedContainerRO.Unpacker> unpacker = (idListx, paletteProviderx, serialized) -> { + return unpack(idListx, paletteProviderx, serialized, value, presetValues); + }; + // Paper end return codec(registry, codec, strategy, value, unpacker); } public static Codec> codecRO(IdMap registry, Codec codec, PalettedContainer.Strategy strategy, T value) { - PalettedContainerRO.Unpacker> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData) + PalettedContainerRO.Unpacker> unpacker = (registry1, strategy1, packedData) -> unpack(registry1, strategy1, packedData, value, null) // Paper - Anti-Xray - Add preset values .map(container -> (PalettedContainerRO)container); return codec(registry, codec, strategy, value, unpacker); } @@ -66,27 +75,66 @@ public class PalettedContainer implements PaletteResize, PalettedContainer ); } + // Paper start - Anti-Xray - Add preset values + @Deprecated @io.papermc.paper.annotation.DoNotUse + public PalettedContainer(IdMap registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration configuration, BitStorage storage, List values) { + this(registry, strategy, configuration, storage, values, null, null); + } public PalettedContainer( - IdMap registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration configuration, BitStorage storage, List values + IdMap registry, PalettedContainer.Strategy strategy, PalettedContainer.Configuration configuration, BitStorage storage, List 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 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 registry, PalettedContainer.Strategy strategy, PalettedContainer.Data data) { + // Paper start - Anti-Xray - Add preset values + private PalettedContainer(IdMap registry, PalettedContainer.Strategy strategy, PalettedContainer.Data 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 other) { + private PalettedContainer(PalettedContainer 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 registry, T palette, PalettedContainer.Strategy strategy) { + this(registry, palette, strategy, null); + } + public PalettedContainer(IdMap 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 implements PaletteResize, PalettedContainer @Override public synchronized int onResize(int bits, T objectAdded) { // Paper - synchronize PalettedContainer.Data 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 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 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 implements PaletteResize, 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 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 DataResult> unpack( - IdMap registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData packedData + IdMap registry, PalettedContainer.Strategy strategy, PalettedContainerRO.PackedData packedData, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues // Paper - Anti-Xray - Add preset values ) { List list = packedData.paletteEntries(); int size = strategy.size(); @@ -222,7 +300,7 @@ public class PalettedContainer implements PaletteResize, 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 implements PaletteResize, PalettedContainer @Override public PalettedContainer copy() { - return new PalettedContainer<>(this); + return new PalettedContainer<>(this, this.presetValues); // Paper - Anti-Xray - Add preset values } @Override public PalettedContainer 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 implements PaletteResize, 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 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 { void getAll(Consumer 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 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 c7c87bc8df86ceeef3e15a8f23fc252d4cee1984..3b55e7fb27d680204b8621666ae9200870def3eb 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> 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>> 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 palettedContainer; if (compound2.contains("block_states", 10)) { - palettedContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, compound2.getCompound("block_states")) + Codec> 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>> makeBiomeCodecRW(Registry biomeRegistry) { - return PalettedContainer.codecRW(biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS)); + return PalettedContainer.codecRW(biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS), null); // Paper - Anti-Xray - Add preset biomes } // CraftBukkit end