2021-11-29 12:55:13 +01:00
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/src/main/java/com/destroystokyo/paper/antixray/BitStorageReader.java b/src/main/java/com/destroystokyo/paper/antixray/BitStorageReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..e448c26327b5f6189c3c52e698cff66c8f9ad81a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/antixray/BitStorageReader.java
@@ -0,0 +1,51 @@
+package com.destroystokyo.paper.antixray;
+
+public final class BitStorageReader {
+
+ private byte[] buffer;
+ private int bits;
+ private int mask;
+ private int longInBufferIndex;
+ private int bitInLongIndex;
+ private long current;
+
+ public void setBuffer(byte[] buffer) {
+ this.buffer = buffer;
+ }
+
+ public void setBits(int bits) {
+ this.bits = bits;
+ mask = (1 << bits) - 1;
+ }
+
+ public void setIndex(int index) {
+ longInBufferIndex = index;
+ bitInLongIndex = 0;
+ init();
+ }
+
+ private void init() {
+ if (buffer.length > longInBufferIndex + 7) {
+ current = ((((long) buffer[longInBufferIndex]) << 56)
+ | (((long) buffer[longInBufferIndex + 1] & 0xff) << 48)
+ | (((long) buffer[longInBufferIndex + 2] & 0xff) << 40)
+ | (((long) buffer[longInBufferIndex + 3] & 0xff) << 32)
+ | (((long) buffer[longInBufferIndex + 4] & 0xff) << 24)
+ | (((long) buffer[longInBufferIndex + 5] & 0xff) << 16)
+ | (((long) buffer[longInBufferIndex + 6] & 0xff) << 8)
+ | (((long) buffer[longInBufferIndex + 7] & 0xff)));
+ }
+ }
+
+ public int read() {
+ if (bitInLongIndex + bits > 64) {
+ bitInLongIndex = 0;
+ longInBufferIndex += 8;
+ init();
+ }
+
+ int value = (int) (current >>> bitInLongIndex) & mask;
+ bitInLongIndex += bits;
+ return value;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/antixray/BitStorageWriter.java b/src/main/java/com/destroystokyo/paper/antixray/BitStorageWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4540ea278f2dc871cb6a3cb8897559bfd65e134
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/antixray/BitStorageWriter.java
@@ -0,0 +1,79 @@
+package com.destroystokyo.paper.antixray;
+
+public final class BitStorageWriter {
+
+ private byte[] buffer;
+ private int bits;
+ private long mask;
+ private int longInBufferIndex;
+ private int bitInLongIndex;
+ private long current;
+ private boolean dirty;
+
+ public void setBuffer(byte[] buffer) {
+ this.buffer = buffer;
+ }
+
+ public void setBits(int bits) {
+ this.bits = bits;
+ mask = (1L << bits) - 1;
+ }
+
+ public void setIndex(int index) {
+ longInBufferIndex = index;
+ bitInLongIndex = 0;
+ init();
+ }
+
+ private void init() {
+ if (buffer.length > longInBufferIndex + 7) {
+ current = ((((long) buffer[longInBufferIndex]) << 56)
+ | (((long) buffer[longInBufferIndex + 1] & 0xff) << 48)
+ | (((long) buffer[longInBufferIndex + 2] & 0xff) << 40)
+ | (((long) buffer[longInBufferIndex + 3] & 0xff) << 32)
+ | (((long) buffer[longInBufferIndex + 4] & 0xff) << 24)
+ | (((long) buffer[longInBufferIndex + 5] & 0xff) << 16)
+ | (((long) buffer[longInBufferIndex + 6] & 0xff) << 8)
+ | (((long) buffer[longInBufferIndex + 7] & 0xff)));
+ }
+
+ dirty = false;
+ }
+
+ public void flush() {
+ if (dirty && buffer.length > longInBufferIndex + 7) {
+ buffer[longInBufferIndex] = (byte) (current >> 56 & 0xff);
+ buffer[longInBufferIndex + 1] = (byte) (current >> 48 & 0xff);
+ buffer[longInBufferIndex + 2] = (byte) (current >> 40 & 0xff);
+ buffer[longInBufferIndex + 3] = (byte) (current >> 32 & 0xff);
+ buffer[longInBufferIndex + 4] = (byte) (current >> 24 & 0xff);
+ buffer[longInBufferIndex + 5] = (byte) (current >> 16 & 0xff);
+ buffer[longInBufferIndex + 6] = (byte) (current >> 8 & 0xff);
+ buffer[longInBufferIndex + 7] = (byte) (current & 0xff);
+ }
+ }
+
+ public void write(int value) {
+ if (bitInLongIndex + bits > 64) {
+ flush();
+ bitInLongIndex = 0;
+ longInBufferIndex += 8;
+ init();
+ }
+
+ current = current & ~(mask << bitInLongIndex) | (value & mask) << bitInLongIndex;
+ dirty = true;
+ bitInLongIndex += bits;
+ }
+
+ public void skip() {
+ bitInLongIndex += bits;
+
+ if (bitInLongIndex > 64) {
+ flush();
+ bitInLongIndex = bits;
+ longInBufferIndex += 8;
+ init();
+ }
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockController.java b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockController.java
new file mode 100644
2023-06-09 06:29:58 +02:00
index 0000000000000000000000000000000000000000..52d2e2b744f91914802506e52a07161729bbcf3a
2021-11-29 12:55:13 +01:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockController.java
@@ -0,0 +1,45 @@
+package com.destroystokyo.paper.antixray;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
+import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.level.ServerPlayerGameMode;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.LevelChunk;
+
+public class ChunkPacketBlockController {
+
+ public static final ChunkPacketBlockController NO_OPERATION_INSTANCE = new ChunkPacketBlockController();
+
+ protected ChunkPacketBlockController() {
+
+ }
+
2023-06-09 06:29:58 +02:00
+ public BlockState[] getPresetBlockStates(Level level, ChunkPos chunkPos, int chunkSectionY) {
2021-11-29 12:55:13 +01:00
+ return null;
+ }
+
+ public boolean shouldModify(ServerPlayer player, LevelChunk chunk) {
+ return false;
+ }
+
+ public ChunkPacketInfo<BlockState> getChunkPacketInfo(ClientboundLevelChunkWithLightPacket chunkPacket, LevelChunk chunk) {
+ return null;
+ }
+
+ public void modifyBlocks(ClientboundLevelChunkWithLightPacket chunkPacket, ChunkPacketInfo<BlockState> chunkPacketInfo) {
+ chunkPacket.setReady(true);
+ }
+
+ public void onBlockChange(Level level, BlockPos blockPos, BlockState newBlockState, BlockState oldBlockState, int flags, int maxUpdateDepth) {
+
+ }
+
2022-07-18 12:30:31 +02:00
+ public void onPlayerLeftClickBlock(ServerPlayerGameMode serverPlayerGameMode, BlockPos blockPos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int sequence) {
2021-11-29 12:55:13 +01:00
+
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java
new file mode 100644
2023-11-19 01:29:14 +01:00
index 0000000000000000000000000000000000000000..e7fe98ea30ae6d0baea3ec1f9f98a89502a49a12
2021-11-29 12:55:13 +01:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java
2023-11-19 01:29:14 +01:00
@@ -0,0 +1,676 @@
2021-11-29 12:55:13 +01:00
+package com.destroystokyo.paper.antixray;
+
2022-06-09 10:51:45 +02:00
+import io.papermc.paper.configuration.WorldConfiguration;
2022-07-18 12:30:31 +02:00
+import io.papermc.paper.configuration.type.EngineMode;
2023-11-19 01:29:14 +01:00
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.IntSupplier;
2021-11-29 12:55:13 +01:00
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
2022-12-08 00:49:41 +01:00
+import net.minecraft.core.registries.Registries;
2021-11-29 12:55:13 +01:00
+import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
+import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.level.ServerPlayerGameMode;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.Level;
2022-02-28 23:02:20 +01:00
+import net.minecraft.world.level.biome.Biomes;
2021-11-29 12:55:13 +01:00
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.EntityBlock;
+import net.minecraft.world.level.block.state.BlockState;
2023-11-19 01:29:14 +01:00
+import net.minecraft.world.level.chunk.EmptyLevelChunk;
+import net.minecraft.world.level.chunk.GlobalPalette;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.MissingPaletteEntryException;
+import net.minecraft.world.level.chunk.Palette;
2021-11-29 12:55:13 +01:00
+import org.bukkit.Bukkit;
+
+public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockController {
+
+ private static final Palette<BlockState> GLOBAL_BLOCKSTATE_PALETTE = new GlobalPalette<>(Block.BLOCK_STATE_REGISTRY);
+ private static final LevelChunkSection EMPTY_SECTION = null;
+ private final Executor executor;
+ private final EngineMode engineMode;
+ private final int maxBlockHeight;
+ private final int updateRadius;
+ private final boolean usePermission;
+ private final BlockState[] presetBlockStates;
+ private final BlockState[] presetBlockStatesFull;
+ private final BlockState[] presetBlockStatesStone;
2022-05-18 22:16:12 +02:00
+ private final BlockState[] presetBlockStatesDeepslate;
2021-11-29 12:55:13 +01:00
+ private final BlockState[] presetBlockStatesNetherrack;
+ private final BlockState[] presetBlockStatesEndStone;
+ private final int[] presetBlockStateBitsGlobal;
+ private final int[] presetBlockStateBitsStoneGlobal;
2022-05-18 22:16:12 +02:00
+ private final int[] presetBlockStateBitsDeepslateGlobal;
2021-11-29 12:55:13 +01:00
+ private final int[] presetBlockStateBitsNetherrackGlobal;
+ private final int[] presetBlockStateBitsEndStoneGlobal;
+ private final boolean[] solidGlobal = new boolean[Block.BLOCK_STATE_REGISTRY.size()];
+ private final boolean[] obfuscateGlobal = new boolean[Block.BLOCK_STATE_REGISTRY.size()];
+ private final LevelChunkSection[] emptyNearbyChunkSections = {EMPTY_SECTION, EMPTY_SECTION, EMPTY_SECTION, EMPTY_SECTION};
+ private final int maxBlockHeightUpdatePosition;
+
+ public ChunkPacketBlockControllerAntiXray(Level level, Executor executor) {
+ this.executor = executor;
2022-07-18 12:30:31 +02:00
+ WorldConfiguration.Anticheat.AntiXray paperWorldConfig = level.paperConfig().anticheat.antiXray;
2021-11-29 12:55:13 +01:00
+ engineMode = paperWorldConfig.engineMode;
+ maxBlockHeight = paperWorldConfig.maxBlockHeight >> 4 << 4;
+ updateRadius = paperWorldConfig.updateRadius;
+ usePermission = paperWorldConfig.usePermission;
2023-11-19 01:29:14 +01:00
+ List<Block> toObfuscate;
2021-11-29 12:55:13 +01:00
+
+ if (engineMode == EngineMode.HIDE) {
+ toObfuscate = paperWorldConfig.hiddenBlocks;
+ presetBlockStates = null;
+ presetBlockStatesFull = null;
+ presetBlockStatesStone = new BlockState[]{Blocks.STONE.defaultBlockState()};
2022-05-18 22:16:12 +02:00
+ presetBlockStatesDeepslate = new BlockState[]{Blocks.DEEPSLATE.defaultBlockState()};
2021-11-29 12:55:13 +01:00
+ presetBlockStatesNetherrack = new BlockState[]{Blocks.NETHERRACK.defaultBlockState()};
+ presetBlockStatesEndStone = new BlockState[]{Blocks.END_STONE.defaultBlockState()};
+ presetBlockStateBitsGlobal = null;
+ presetBlockStateBitsStoneGlobal = new int[]{GLOBAL_BLOCKSTATE_PALETTE.idFor(Blocks.STONE.defaultBlockState())};
2022-05-18 22:16:12 +02:00
+ presetBlockStateBitsDeepslateGlobal = new int[]{GLOBAL_BLOCKSTATE_PALETTE.idFor(Blocks.DEEPSLATE.defaultBlockState())};
2021-11-29 12:55:13 +01:00
+ presetBlockStateBitsNetherrackGlobal = new int[]{GLOBAL_BLOCKSTATE_PALETTE.idFor(Blocks.NETHERRACK.defaultBlockState())};
+ presetBlockStateBitsEndStoneGlobal = new int[]{GLOBAL_BLOCKSTATE_PALETTE.idFor(Blocks.END_STONE.defaultBlockState())};
+ } else {
+ toObfuscate = new ArrayList<>(paperWorldConfig.replacementBlocks);
+ List<BlockState> presetBlockStateList = new LinkedList<>();
+
2023-11-19 01:29:14 +01:00
+ for (Block block : paperWorldConfig.hiddenBlocks) {
2021-11-29 12:55:13 +01:00
+
2023-11-19 01:29:14 +01:00
+ if (!(block instanceof EntityBlock)) {
+ toObfuscate.add(block);
2021-11-29 12:55:13 +01:00
+ presetBlockStateList.add(block.defaultBlockState());
+ }
+ }
+
+ // The doc of the LinkedHashSet(Collection<? extends E>) constructor doesn't specify that the insertion order is the predictable iteration order of the specified Collection, although it is in the implementation
+ Set<BlockState> presetBlockStateSet = new LinkedHashSet<>();
+ // Therefore addAll(Collection<? extends E>) is used, which guarantees this order in the doc
+ presetBlockStateSet.addAll(presetBlockStateList);
+ presetBlockStates = presetBlockStateSet.isEmpty() ? new BlockState[]{Blocks.DIAMOND_ORE.defaultBlockState()} : presetBlockStateSet.toArray(new BlockState[0]);
+ presetBlockStatesFull = presetBlockStateSet.isEmpty() ? new BlockState[]{Blocks.DIAMOND_ORE.defaultBlockState()} : presetBlockStateList.toArray(new BlockState[0]);
+ presetBlockStatesStone = null;
2022-05-18 22:16:12 +02:00
+ presetBlockStatesDeepslate = null;
2021-11-29 12:55:13 +01:00
+ presetBlockStatesNetherrack = null;
+ presetBlockStatesEndStone = null;
+ presetBlockStateBitsGlobal = new int[presetBlockStatesFull.length];
+
+ for (int i = 0; i < presetBlockStatesFull.length; i++) {
+ presetBlockStateBitsGlobal[i] = GLOBAL_BLOCKSTATE_PALETTE.idFor(presetBlockStatesFull[i]);
+ }
+
+ presetBlockStateBitsStoneGlobal = null;
2022-05-18 22:16:12 +02:00
+ presetBlockStateBitsDeepslateGlobal = null;
2021-11-29 12:55:13 +01:00
+ presetBlockStateBitsNetherrackGlobal = null;
+ presetBlockStateBitsEndStoneGlobal = null;
+ }
+
2023-11-19 01:29:14 +01:00
+ for (Block block : toObfuscate) {
2021-11-29 12:55:13 +01:00
+
+ // Don't obfuscate air because air causes unnecessary block updates and causes block updates to fail in the void
+ if (block != null && !block.defaultBlockState().isAir()) {
+ // Replace all block states of a specified block
+ for (BlockState blockState : block.getStateDefinition().getPossibleStates()) {
+ obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = true;
+ }
+ }
+ }
+
2022-12-08 00:49:41 +01:00
+ EmptyLevelChunk emptyChunk = new EmptyLevelChunk(level, new ChunkPos(0, 0), MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.PLAINS));
2021-11-29 12:55:13 +01:00
+ BlockPos zeroPos = new BlockPos(0, 0, 0);
+
+ for (int i = 0; i < solidGlobal.length; i++) {
+ BlockState blockState = GLOBAL_BLOCKSTATE_PALETTE.valueFor(i);
+
+ if (blockState != null) {
+ solidGlobal[i] = blockState.isRedstoneConductor(emptyChunk, zeroPos)
2022-07-18 12:30:31 +02:00
+ && blockState.getBlock() != Blocks.SPAWNER && blockState.getBlock() != Blocks.BARRIER && blockState.getBlock() != Blocks.SHULKER_BOX && blockState.getBlock() != Blocks.SLIME_BLOCK && blockState.getBlock() != Blocks.MANGROVE_ROOTS || paperWorldConfig.lavaObscures && blockState == Blocks.LAVA.defaultBlockState();
2021-11-29 12:55:13 +01:00
+ // Comparing blockState == Blocks.LAVA.defaultBlockState() instead of blockState.getBlock() == Blocks.LAVA ensures that only "stationary lava" is used
+ // shulker box checks TE.
+ }
+ }
+
+ maxBlockHeightUpdatePosition = maxBlockHeight + updateRadius - 1;
+ }
+
+ private int getPresetBlockStatesFullLength() {
+ return engineMode == EngineMode.HIDE ? 1 : presetBlockStatesFull.length;
+ }
+
+ @Override
2023-06-09 06:29:58 +02:00
+ public BlockState[] getPresetBlockStates(Level level, ChunkPos chunkPos, int chunkSectionY) {
2021-11-29 12:55:13 +01:00
+ // Return the block states to be added to the paletted containers so that they can be used for obfuscation
2023-06-09 06:29:58 +02:00
+ int bottomBlockY = chunkSectionY << 4;
+
2021-11-29 12:55:13 +01:00
+ if (bottomBlockY < maxBlockHeight) {
+ if (engineMode == EngineMode.HIDE) {
+ return switch (level.getWorld().getEnvironment()) {
+ case NETHER -> presetBlockStatesNetherrack;
+ case THE_END -> presetBlockStatesEndStone;
2022-05-18 22:16:12 +02:00
+ default -> bottomBlockY < 0 ? presetBlockStatesDeepslate : presetBlockStatesStone;
2021-11-29 12:55:13 +01:00
+ };
+ }
+
+ return presetBlockStates;
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean shouldModify(ServerPlayer player, LevelChunk chunk) {
+ return !usePermission || !player.getBukkitEntity().hasPermission("paper.antixray.bypass");
+ }
+
+ @Override
+ public ChunkPacketInfoAntiXray getChunkPacketInfo(ClientboundLevelChunkWithLightPacket chunkPacket, LevelChunk chunk) {
+ // Return a new instance to collect data and objects in the right state while creating the chunk packet for thread safe access later
+ return new ChunkPacketInfoAntiXray(chunkPacket, chunk, this);
+ }
+
+ @Override
+ public void modifyBlocks(ClientboundLevelChunkWithLightPacket chunkPacket, ChunkPacketInfo<BlockState> chunkPacketInfo) {
+ if (!(chunkPacketInfo instanceof ChunkPacketInfoAntiXray)) {
+ chunkPacket.setReady(true);
+ return;
+ }
+
+ if (!Bukkit.isPrimaryThread()) {
+ // Plugins?
+ MinecraftServer.getServer().scheduleOnMain(() -> modifyBlocks(chunkPacket, chunkPacketInfo));
+ return;
+ }
+
+ LevelChunk chunk = chunkPacketInfo.getChunk();
+ int x = chunk.getPos().x;
+ int z = chunk.getPos().z;
+ Level level = chunk.getLevel();
+ ((ChunkPacketInfoAntiXray) chunkPacketInfo).setNearbyChunks(level.getChunkIfLoaded(x - 1, z), level.getChunkIfLoaded(x + 1, z), level.getChunkIfLoaded(x, z - 1), level.getChunkIfLoaded(x, z + 1));
+ executor.execute((Runnable) chunkPacketInfo);
+ }
+
+ // Actually these fields should be variables inside the obfuscate method but in sync mode or with SingleThreadExecutor in async mode it's okay (even without ThreadLocal)
+ // If an ExecutorService with multiple threads is used, ThreadLocal must be used here
+ private final ThreadLocal<int[]> presetBlockStateBits = ThreadLocal.withInitial(() -> new int[getPresetBlockStatesFullLength()]);
+ private static final ThreadLocal<boolean[]> SOLID = ThreadLocal.withInitial(() -> new boolean[Block.BLOCK_STATE_REGISTRY.size()]);
+ private static final ThreadLocal<boolean[]> OBFUSCATE = ThreadLocal.withInitial(() -> new boolean[Block.BLOCK_STATE_REGISTRY.size()]);
+ // These boolean arrays represent chunk layers, true means don't obfuscate, false means obfuscate
+ private static final ThreadLocal<boolean[][]> CURRENT = ThreadLocal.withInitial(() -> new boolean[16][16]);
+ private static final ThreadLocal<boolean[][]> NEXT = ThreadLocal.withInitial(() -> new boolean[16][16]);
+ private static final ThreadLocal<boolean[][]> NEXT_NEXT = ThreadLocal.withInitial(() -> new boolean[16][16]);
+
+ public void obfuscate(ChunkPacketInfoAntiXray chunkPacketInfoAntiXray) {
+ int[] presetBlockStateBits = this.presetBlockStateBits.get();
+ boolean[] solid = SOLID.get();
+ boolean[] obfuscate = OBFUSCATE.get();
+ boolean[][] current = CURRENT.get();
+ boolean[][] next = NEXT.get();
+ boolean[][] nextNext = NEXT_NEXT.get();
+ // bitStorageReader, bitStorageWriter and nearbyChunkSections could also be reused (with ThreadLocal if necessary) but it's not worth it
+ BitStorageReader bitStorageReader = new BitStorageReader();
+ BitStorageWriter bitStorageWriter = new BitStorageWriter();
+ LevelChunkSection[] nearbyChunkSections = new LevelChunkSection[4];
+ LevelChunk chunk = chunkPacketInfoAntiXray.getChunk();
+ Level level = chunk.getLevel();
2022-05-18 22:16:12 +02:00
+ int maxChunkSectionIndex = Math.min((maxBlockHeight >> 4) - chunk.getMinSection(), chunk.getSectionsCount()) - 1;
2021-11-29 12:55:13 +01:00
+ boolean[] solidTemp = null;
+ boolean[] obfuscateTemp = null;
+ bitStorageReader.setBuffer(chunkPacketInfoAntiXray.getBuffer());
+ bitStorageWriter.setBuffer(chunkPacketInfoAntiXray.getBuffer());
+ int numberOfBlocks = presetBlockStateBits.length;
+ // Keep the lambda expressions as simple as possible. They are used very frequently.
2023-02-09 18:38:00 +01:00
+ LayeredIntSupplier random = numberOfBlocks == 1 ? (() -> 0) : engineMode == EngineMode.OBFUSCATE_LAYER ? new LayeredIntSupplier() {
+ // engine-mode: 3
+ private int state;
+ private int next;
+
+ {
+ while ((state = ThreadLocalRandom.current().nextInt()) == 0) ;
+ }
+
+ @Override
+ public void nextLayer() {
+ // https://en.wikipedia.org/wiki/Xorshift
+ state ^= state << 13;
+ state ^= state >>> 17;
+ state ^= state << 5;
+ // https://www.pcg-random.org/posts/bounded-rands.html
+ next = (int) ((Integer.toUnsignedLong(state) * numberOfBlocks) >>> 32);
+ }
+
+ @Override
+ public int getAsInt() {
+ return next;
+ }
+ } : new LayeredIntSupplier() {
+ // engine-mode: 2
2021-11-29 12:55:13 +01:00
+ private int state;
+
+ {
+ while ((state = ThreadLocalRandom.current().nextInt()) == 0) ;
+ }
+
+ @Override
+ public int getAsInt() {
+ // https://en.wikipedia.org/wiki/Xorshift
+ state ^= state << 13;
+ state ^= state >>> 17;
+ state ^= state << 5;
+ // https://www.pcg-random.org/posts/bounded-rands.html
+ return (int) ((Integer.toUnsignedLong(state) * numberOfBlocks) >>> 32);
+ }
+ };
+
+ for (int chunkSectionIndex = 0; chunkSectionIndex <= maxChunkSectionIndex; chunkSectionIndex++) {
+ if (chunkPacketInfoAntiXray.isWritten(chunkSectionIndex) && chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex) != null) {
+ int[] presetBlockStateBitsTemp;
+
+ if (chunkPacketInfoAntiXray.getPalette(chunkSectionIndex) instanceof GlobalPalette) {
+ if (engineMode == EngineMode.HIDE) {
+ presetBlockStateBitsTemp = switch (level.getWorld().getEnvironment()) {
+ case NETHER -> presetBlockStateBitsNetherrackGlobal;
+ case THE_END -> presetBlockStateBitsEndStoneGlobal;
2022-05-18 22:16:12 +02:00
+ default -> chunkSectionIndex + chunk.getMinSection() < 0 ? presetBlockStateBitsDeepslateGlobal : presetBlockStateBitsStoneGlobal;
2021-11-29 12:55:13 +01:00
+ };
+ } else {
+ presetBlockStateBitsTemp = presetBlockStateBitsGlobal;
+ }
+ } else {
+ // If it's presetBlockStates, use this.presetBlockStatesFull instead
+ BlockState[] presetBlockStatesFull = chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex) == presetBlockStates ? this.presetBlockStatesFull : chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex);
+ presetBlockStateBitsTemp = presetBlockStateBits;
+
+ for (int i = 0; i < presetBlockStateBitsTemp.length; i++) {
+ // This is thread safe because we only request IDs that are guaranteed to be in the palette and are visible
+ // For more details see the comments in the readPalette method
+ presetBlockStateBitsTemp[i] = chunkPacketInfoAntiXray.getPalette(chunkSectionIndex).idFor(presetBlockStatesFull[i]);
+ }
+ }
+
+ bitStorageWriter.setIndex(chunkPacketInfoAntiXray.getIndex(chunkSectionIndex));
+
+ // Check if the chunk section below was not obfuscated
+ if (chunkSectionIndex == 0 || !chunkPacketInfoAntiXray.isWritten(chunkSectionIndex - 1) || chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex - 1) == null) {
+ // If so, initialize some stuff
+ bitStorageReader.setBits(chunkPacketInfoAntiXray.getBits(chunkSectionIndex));
+ bitStorageReader.setIndex(chunkPacketInfoAntiXray.getIndex(chunkSectionIndex));
+ solidTemp = readPalette(chunkPacketInfoAntiXray.getPalette(chunkSectionIndex), solid, solidGlobal);
+ obfuscateTemp = readPalette(chunkPacketInfoAntiXray.getPalette(chunkSectionIndex), obfuscate, obfuscateGlobal);
+ // Read the blocks of the upper layer of the chunk section below if it exists
+ LevelChunkSection belowChunkSection = null;
+ boolean skipFirstLayer = chunkSectionIndex == 0 || (belowChunkSection = chunk.getSections()[chunkSectionIndex - 1]) == EMPTY_SECTION;
+
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ current[z][x] = true;
+ next[z][x] = skipFirstLayer || isTransparent(belowChunkSection, x, 15, z);
+ }
+ }
+
+ // Abuse the obfuscateLayer method to read the blocks of the first layer of the current chunk section
+ bitStorageWriter.setBits(0);
+ obfuscateLayer(-1, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, presetBlockStateBitsTemp, current, next, nextNext, emptyNearbyChunkSections, random);
+ }
+
+ bitStorageWriter.setBits(chunkPacketInfoAntiXray.getBits(chunkSectionIndex));
+ nearbyChunkSections[0] = chunkPacketInfoAntiXray.getNearbyChunks()[0] == null ? EMPTY_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[0].getSections()[chunkSectionIndex];
+ nearbyChunkSections[1] = chunkPacketInfoAntiXray.getNearbyChunks()[1] == null ? EMPTY_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[1].getSections()[chunkSectionIndex];
+ nearbyChunkSections[2] = chunkPacketInfoAntiXray.getNearbyChunks()[2] == null ? EMPTY_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[2].getSections()[chunkSectionIndex];
+ nearbyChunkSections[3] = chunkPacketInfoAntiXray.getNearbyChunks()[3] == null ? EMPTY_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[3].getSections()[chunkSectionIndex];
+
+ // Obfuscate all layers of the current chunk section except the upper one
+ for (int y = 0; y < 15; y++) {
+ boolean[][] temp = current;
+ current = next;
+ next = nextNext;
+ nextNext = temp;
2023-02-09 18:38:00 +01:00
+ random.nextLayer();
2021-11-29 12:55:13 +01:00
+ obfuscateLayer(y, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, presetBlockStateBitsTemp, current, next, nextNext, nearbyChunkSections, random);
+ }
+
+ // Check if the chunk section above doesn't need obfuscation
+ if (chunkSectionIndex == maxChunkSectionIndex || !chunkPacketInfoAntiXray.isWritten(chunkSectionIndex + 1) || chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex + 1) == null) {
+ // If so, obfuscate the upper layer of the current chunk section by reading blocks of the first layer from the chunk section above if it exists
+ LevelChunkSection aboveChunkSection;
+
+ if (chunkSectionIndex != chunk.getSectionsCount() - 1 && (aboveChunkSection = chunk.getSections()[chunkSectionIndex + 1]) != EMPTY_SECTION) {
+ boolean[][] temp = current;
+ current = next;
+ next = nextNext;
+ nextNext = temp;
+
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ if (isTransparent(aboveChunkSection, x, 0, z)) {
+ current[z][x] = true;
+ }
+ }
+ }
+
+ // There is nothing to read anymore
+ bitStorageReader.setBits(0);
+ solid[0] = true;
2023-02-09 18:38:00 +01:00
+ random.nextLayer();
2021-11-29 12:55:13 +01:00
+ obfuscateLayer(15, bitStorageReader, bitStorageWriter, solid, obfuscateTemp, presetBlockStateBitsTemp, current, next, nextNext, nearbyChunkSections, random);
+ }
+ } else {
+ // If not, initialize the reader and other stuff for the chunk section above to obfuscate the upper layer of the current chunk section
+ bitStorageReader.setBits(chunkPacketInfoAntiXray.getBits(chunkSectionIndex + 1));
+ bitStorageReader.setIndex(chunkPacketInfoAntiXray.getIndex(chunkSectionIndex + 1));
+ solidTemp = readPalette(chunkPacketInfoAntiXray.getPalette(chunkSectionIndex + 1), solid, solidGlobal);
+ obfuscateTemp = readPalette(chunkPacketInfoAntiXray.getPalette(chunkSectionIndex + 1), obfuscate, obfuscateGlobal);
+ boolean[][] temp = current;
+ current = next;
+ next = nextNext;
+ nextNext = temp;
2023-02-09 18:38:00 +01:00
+ random.nextLayer();
2021-11-29 12:55:13 +01:00
+ obfuscateLayer(15, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, presetBlockStateBitsTemp, current, next, nextNext, nearbyChunkSections, random);
+ }
+
+ bitStorageWriter.flush();
+ }
+ }
+
+ chunkPacketInfoAntiXray.getChunkPacket().setReady(true);
+ }
+
+ private void obfuscateLayer(int y, BitStorageReader bitStorageReader, BitStorageWriter bitStorageWriter, boolean[] solid, boolean[] obfuscate, int[] presetBlockStateBits, boolean[][] current, boolean[][] next, boolean[][] nextNext, LevelChunkSection[] nearbyChunkSections, IntSupplier random) {
+ // First block of first line
+ int bits = bitStorageReader.read();
+
+ if (nextNext[0][0] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[0][1] = true;
+ next[1][0] = true;
+ } else {
+ if (current[0][0] || isTransparent(nearbyChunkSections[2], 0, y, 15) || isTransparent(nearbyChunkSections[0], 15, y, 0)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[0][0] = true;
+ }
+
+ // First line
+ for (int x = 1; x < 15; x++) {
+ bits = bitStorageReader.read();
+
+ if (nextNext[0][x] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[0][x - 1] = true;
+ next[0][x + 1] = true;
+ next[1][x] = true;
+ } else {
+ if (current[0][x] || isTransparent(nearbyChunkSections[2], x, y, 15)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[0][x] = true;
+ }
+ }
+
+ // Last block of first line
+ bits = bitStorageReader.read();
+
+ if (nextNext[0][15] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[0][14] = true;
+ next[1][15] = true;
+ } else {
+ if (current[0][15] || isTransparent(nearbyChunkSections[2], 15, y, 15) || isTransparent(nearbyChunkSections[1], 0, y, 0)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[0][15] = true;
+ }
+
+ // All inner lines
+ for (int z = 1; z < 15; z++) {
+ // First block
+ bits = bitStorageReader.read();
+
+ if (nextNext[z][0] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[z][1] = true;
+ next[z - 1][0] = true;
+ next[z + 1][0] = true;
+ } else {
+ if (current[z][0] || isTransparent(nearbyChunkSections[0], 15, y, z)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[z][0] = true;
+ }
+
+ // All inner blocks
+ for (int x = 1; x < 15; x++) {
+ bits = bitStorageReader.read();
+
+ if (nextNext[z][x] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[z][x - 1] = true;
+ next[z][x + 1] = true;
+ next[z - 1][x] = true;
+ next[z + 1][x] = true;
+ } else {
+ if (current[z][x]) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[z][x] = true;
+ }
+ }
+
+ // Last block
+ bits = bitStorageReader.read();
+
+ if (nextNext[z][15] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[z][14] = true;
+ next[z - 1][15] = true;
+ next[z + 1][15] = true;
+ } else {
+ if (current[z][15] || isTransparent(nearbyChunkSections[1], 0, y, z)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[z][15] = true;
+ }
+ }
+
+ // First block of last line
+ bits = bitStorageReader.read();
+
+ if (nextNext[15][0] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[15][1] = true;
+ next[14][0] = true;
+ } else {
+ if (current[15][0] || isTransparent(nearbyChunkSections[3], 0, y, 0) || isTransparent(nearbyChunkSections[0], 15, y, 15)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[15][0] = true;
+ }
+
+ // Last line
+ for (int x = 1; x < 15; x++) {
+ bits = bitStorageReader.read();
+
+ if (nextNext[15][x] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[15][x - 1] = true;
+ next[15][x + 1] = true;
+ next[14][x] = true;
+ } else {
+ if (current[15][x] || isTransparent(nearbyChunkSections[3], x, y, 0)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[15][x] = true;
+ }
+ }
+
+ // Last block of last line
+ bits = bitStorageReader.read();
+
+ if (nextNext[15][15] = !solid[bits]) {
+ bitStorageWriter.skip();
+ next[15][14] = true;
+ next[14][15] = true;
+ } else {
+ if (current[15][15] || isTransparent(nearbyChunkSections[3], 15, y, 0) || isTransparent(nearbyChunkSections[1], 0, y, 15)) {
+ bitStorageWriter.skip();
+ } else {
+ bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]);
+ }
+ }
+
+ if (!obfuscate[bits]) {
+ next[15][15] = true;
+ }
+ }
+
+ private boolean isTransparent(LevelChunkSection chunkSection, int x, int y, int z) {
+ if (chunkSection == EMPTY_SECTION) {
+ return true;
+ }
+
+ try {
+ return !solidGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(chunkSection.getBlockState(x, y, z))];
+ } catch (MissingPaletteEntryException e) {
+ // Race condition / visibility issue / no happens-before relationship
+ // We don't care and treat the block as transparent
+ // Internal implementation details of PalettedContainer, LinearPalette, HashMapPalette, CrudeIncrementalIntIdentityHashBiMap, ... guarantee us that no (other) exceptions will occur
+ return true;
+ }
+ }
+
+ private boolean[] readPalette(Palette<BlockState> palette, boolean[] temp, boolean[] global) {
+ if (palette instanceof GlobalPalette) {
+ return global;
+ }
+
+ try {
+ for (int i = 0; i < palette.getSize(); i++) {
+ temp[i] = global[GLOBAL_BLOCKSTATE_PALETTE.idFor(palette.valueFor(i))];
+ }
+ } catch (MissingPaletteEntryException e) {
+ // Race condition / visibility issue / no happens-before relationship
+ // We don't care because we at least see the state as it was when the chunk packet was created
+ // Internal implementation details of PalettedContainer, LinearPalette, HashMapPalette, CrudeIncrementalIntIdentityHashBiMap, ... guarantee us that no (other) exceptions will occur until we have all the data that we need here
+ // Since all palettes have a fixed initial maximum size and there is no internal restructuring and no values are removed from palettes, we are also guaranteed to see the data
+ }
+
+ return temp;
+ }
+
+ @Override
+ public void onBlockChange(Level level, BlockPos blockPos, BlockState newBlockState, BlockState oldBlockState, int flags, int maxUpdateDepth) {
+ if (oldBlockState != null && solidGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(oldBlockState)] && !solidGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(newBlockState)] && blockPos.getY() <= maxBlockHeightUpdatePosition) {
+ updateNearbyBlocks(level, blockPos);
+ }
+ }
+
+ @Override
2022-07-18 12:30:31 +02:00
+ public void onPlayerLeftClickBlock(ServerPlayerGameMode serverPlayerGameMode, BlockPos blockPos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int sequence) {
2021-11-29 12:55:13 +01:00
+ if (blockPos.getY() <= maxBlockHeightUpdatePosition) {
+ updateNearbyBlocks(serverPlayerGameMode.level, blockPos);
+ }
+ }
+
+ private void updateNearbyBlocks(Level level, BlockPos blockPos) {
+ if (updateRadius >= 2) {
+ BlockPos temp = blockPos.west();
+ updateBlock(level, temp);
+ updateBlock(level, temp.west());
+ updateBlock(level, temp.below());
+ updateBlock(level, temp.above());
+ updateBlock(level, temp.north());
+ updateBlock(level, temp.south());
+ updateBlock(level, temp = blockPos.east());
+ updateBlock(level, temp.east());
+ updateBlock(level, temp.below());
+ updateBlock(level, temp.above());
+ updateBlock(level, temp.north());
+ updateBlock(level, temp.south());
+ updateBlock(level, temp = blockPos.below());
+ updateBlock(level, temp.below());
+ updateBlock(level, temp.north());
+ updateBlock(level, temp.south());
+ updateBlock(level, temp = blockPos.above());
+ updateBlock(level, temp.above());
+ updateBlock(level, temp.north());
+ updateBlock(level, temp.south());
+ updateBlock(level, temp = blockPos.north());
+ updateBlock(level, temp.north());
+ updateBlock(level, temp = blockPos.south());
+ updateBlock(level, temp.south());
+ } else if (updateRadius == 1) {
+ updateBlock(level, blockPos.west());
+ updateBlock(level, blockPos.east());
+ updateBlock(level, blockPos.below());
+ updateBlock(level, blockPos.above());
+ updateBlock(level, blockPos.north());
+ updateBlock(level, blockPos.south());
+ } else {
+ // Do nothing if updateRadius <= 0 (test mode)
+ }
+ }
+
+ private void updateBlock(Level level, BlockPos blockPos) {
2021-12-06 00:32:02 +01:00
+ BlockState blockState = level.getBlockStateIfLoaded(blockPos);
2021-11-29 12:55:13 +01:00
+
+ if (blockState != null && obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)]) {
+ ((ServerLevel) level).getChunkSource().blockChanged(blockPos);
+ }
+ }
2023-02-09 18:38:00 +01:00
+
+ @FunctionalInterface
+ private interface LayeredIntSupplier extends IntSupplier {
+ default void nextLayer() {
+
+ }
+ }
2021-11-29 12:55:13 +01:00
+}
diff --git a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfo.java b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..d98a3f5c54c67a673eb7dc456dd039cd78f9c34d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfo.java
@@ -0,0 +1,80 @@
+package com.destroystokyo.paper.antixray;
+
+import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.chunk.Palette;
+
+public class ChunkPacketInfo<T> {
+
+ private final ClientboundLevelChunkWithLightPacket chunkPacket;
+ private final LevelChunk chunk;
+ private final int[] bits;
+ private final Object[] palettes;
+ private final int[] indexes;
+ private final Object[][] presetValues;
+ private byte[] buffer;
+
+ public ChunkPacketInfo(ClientboundLevelChunkWithLightPacket chunkPacket, LevelChunk chunk) {
+ this.chunkPacket = chunkPacket;
+ this.chunk = chunk;
+ int sections = chunk.getSectionsCount();
+ bits = new int[sections];
+ palettes = new Object[sections];
+ indexes = new int[sections];
+ presetValues = new Object[sections][];
+ }
+
+ public ClientboundLevelChunkWithLightPacket getChunkPacket() {
+ return chunkPacket;
+ }
+
+ public LevelChunk getChunk() {
+ return chunk;
+ }
+
+ public byte[] getBuffer() {
+ return buffer;
+ }
+
+ public void setBuffer(byte[] buffer) {
+ this.buffer = buffer;
+ }
+
+ public int getBits(int chunkSectionIndex) {
+ return bits[chunkSectionIndex];
+ }
+
+ public void setBits(int chunkSectionIndex, int bits) {
+ this.bits[chunkSectionIndex] = bits;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Palette<T> getPalette(int chunkSectionIndex) {
+ return (Palette<T>) palettes[chunkSectionIndex];
+ }
+
+ public void setPalette(int chunkSectionIndex, Palette<T> palette) {
+ palettes[chunkSectionIndex] = palette;
+ }
+
+ public int getIndex(int chunkSectionIndex) {
+ return indexes[chunkSectionIndex];
+ }
+
+ public void setIndex(int chunkSectionIndex, int index) {
+ indexes[chunkSectionIndex] = index;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T[] getPresetValues(int chunkSectionIndex) {
+ return (T[]) presetValues[chunkSectionIndex];
+ }
+
+ public void setPresetValues(int chunkSectionIndex, T[] presetValues) {
+ this.presetValues[chunkSectionIndex] = presetValues;
+ }
+
+ public boolean isWritten(int chunkSectionIndex) {
+ return bits[chunkSectionIndex] != 0;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfoAntiXray.java b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfoAntiXray.java
new file mode 100644
index 0000000000000000000000000000000000000000..80a2dfb266ae1221680a7b24fee2f7e2a8330b7d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfoAntiXray.java
@@ -0,0 +1,29 @@
+package com.destroystokyo.paper.antixray;
+
+import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.LevelChunk;
+
+public final class ChunkPacketInfoAntiXray extends ChunkPacketInfo<BlockState> implements Runnable {
+
+ private final ChunkPacketBlockControllerAntiXray chunkPacketBlockControllerAntiXray;
+ private LevelChunk[] nearbyChunks;
+
+ public ChunkPacketInfoAntiXray(ClientboundLevelChunkWithLightPacket chunkPacket, LevelChunk chunk, ChunkPacketBlockControllerAntiXray chunkPacketBlockControllerAntiXray) {
+ super(chunkPacket, chunk);
+ this.chunkPacketBlockControllerAntiXray = chunkPacketBlockControllerAntiXray;
+ }
+
+ public LevelChunk[] getNearbyChunks() {
+ return nearbyChunks;
+ }
+
+ public void setNearbyChunks(LevelChunk... nearbyChunks) {
+ this.nearbyChunks = nearbyChunks;
+ }
+
+ @Override
+ public void run() {
+ chunkPacketBlockControllerAntiXray.obfuscate(this);
+ }
+}
2023-03-15 01:21:35 +01:00
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
2023-06-09 06:29:58 +02:00
index 6cff1a98dc7cf33947ec760dbc3d3d0ec5db5f6c..51f647de153255c919b1440338cf1b3e2d6b5dbf 100644
2023-03-15 01:21:35 +01:00
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundChunksBiomesPacket.java
2023-06-09 06:29:58 +02:00
@@ -63,8 +63,10 @@ public record ClientboundChunksBiomesPacket(List<ClientboundChunksBiomesPacket.C
}
2023-03-15 01:21:35 +01:00
public static void extractChunkData(FriendlyByteBuf buf, LevelChunk chunk) {
2023-06-09 06:29:58 +02:00
+ int chunkSectionIndex = 0; // Paper - Anti-Xray
2023-03-15 01:21:35 +01:00
for(LevelChunkSection levelChunkSection : chunk.getSections()) {
- levelChunkSection.getBiomes().write(buf);
2023-06-09 06:29:58 +02:00
+ levelChunkSection.getBiomes().write(buf, null, chunkSectionIndex); // Paper - Anti-Xray
+ chunkSectionIndex++; // Paper - Anti-Xray
2023-03-15 01:21:35 +01:00
}
}
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
2024-01-23 18:01:39 +01:00
index 89e3163b0301f8414c9400a6e00cdd85841fe2e8..74b5cec09d953a247bc5aba3c4232a4c28ea1046 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
2024-01-23 18:01:39 +01:00
@@ -25,7 +25,10 @@ public class ClientboundLevelChunkPacketData {
private final byte[] buffer;
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
2021-11-29 12:55:13 +01:00
- public ClientboundLevelChunkPacketData(LevelChunk chunk) {
+ // Paper start - Anti-Xray - Add chunk packet info
2022-07-18 12:30:31 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public ClientboundLevelChunkPacketData(LevelChunk chunk) { this(chunk, null); }
2021-11-29 12:55:13 +01:00
+ public ClientboundLevelChunkPacketData(LevelChunk chunk, com.destroystokyo.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
+ // Paper end
this.heightmaps = new CompoundTag();
2022-05-29 21:54:25 +02:00
for(Map.Entry<Heightmap.Types, Heightmap> entry : chunk.getHeightmaps()) {
2024-01-23 18:01:39 +01:00
@@ -35,7 +38,14 @@ public class ClientboundLevelChunkPacketData {
2021-11-29 12:55:13 +01:00
}
this.buffer = new byte[calculateChunkSize(chunk)];
- extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk);
2022-07-18 12:30:31 +02:00
+
2021-11-29 12:55:13 +01:00
+ // Paper start - Anti-Xray - Add chunk packet info
+ if (chunkPacketInfo != null) {
+ chunkPacketInfo.setBuffer(this.buffer);
+ }
+
+ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk, chunkPacketInfo);
+ // Paper end
this.blockEntitiesData = Lists.newArrayList();
2024-01-23 18:01:39 +01:00
for(Map.Entry<BlockPos, BlockEntity> entry2 : chunk.getBlockEntities().entrySet()) {
@@ -85,9 +95,15 @@ public class ClientboundLevelChunkPacketData {
2021-11-29 12:55:13 +01:00
return byteBuf;
}
- public static void extractChunkData(FriendlyByteBuf buf, LevelChunk chunk) {
+ // Paper start - Anti-Xray - Add chunk packet info
2022-07-18 12:30:31 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public static void extractChunkData(FriendlyByteBuf buf, LevelChunk chunk) { ClientboundLevelChunkPacketData.extractChunkData(buf, chunk, null); }
2021-11-29 12:55:13 +01:00
+ public static void extractChunkData(FriendlyByteBuf buf, LevelChunk chunk, com.destroystokyo.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo) {
2023-06-09 06:29:58 +02:00
+ int chunkSectionIndex = 0;
+
2021-11-29 12:55:13 +01:00
for(LevelChunkSection levelChunkSection : chunk.getSections()) {
- levelChunkSection.write(buf);
2023-06-09 06:29:58 +02:00
+ levelChunkSection.write(buf, chunkPacketInfo, chunkSectionIndex);
+ chunkSectionIndex++;
2021-11-29 12:55:13 +01:00
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
2024-01-23 18:01:39 +01:00
index 26e46d751c8f8162c2bafe2fc109fc91dc4b7c0f..6412dff5ed0505f62dd5b71ab9606257858a7317 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
@@ -13,13 +13,30 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
private final int z;
private final ClientboundLevelChunkPacketData chunkData;
private final ClientboundLightUpdatePacketData lightData;
+ // Paper start - Async-Anti-Xray - Ready flag for the connection
+ private volatile boolean ready;
2023-06-09 06:29:58 +02:00
- public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightProvider, @Nullable BitSet skyBits, @Nullable BitSet blockBits) {
2021-11-29 12:55:13 +01:00
+ @Override
+ public boolean isReady() {
+ return this.ready;
+ }
+
+ public void setReady(boolean ready) {
+ this.ready = ready;
+ }
+ // Paper end
+
+ // Paper start - Anti-Xray - Add chunk packet info
2023-06-09 06:29:58 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightProvider, @Nullable BitSet skyBits, @Nullable BitSet blockBits) { this(chunk, lightProvider, skyBits, blockBits, true); }
+ public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightProvider, @Nullable BitSet skyBits, @Nullable BitSet blockBits, boolean modifyBlocks) {
2021-11-29 12:55:13 +01:00
ChunkPos chunkPos = chunk.getPos();
this.x = chunkPos.x;
this.z = chunkPos.z;
- this.chunkData = new ClientboundLevelChunkPacketData(chunk);
2022-07-18 12:30:31 +02:00
+ com.destroystokyo.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null;
2021-11-29 12:55:13 +01:00
+ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo);
+ // Paper end
2023-06-09 06:29:58 +02:00
this.lightData = new ClientboundLightUpdatePacketData(chunkPos, lightProvider, skyBits, blockBits);
2021-11-29 12:55:13 +01:00
+ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
}
public ClientboundLevelChunkWithLightPacket(FriendlyByteBuf buf) {
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
2024-01-24 11:45:17 +01:00
index 4357d45305cdf82659fcc0df9fa42b1ae1029cc1..811c9c7970dfef290acdf0bbd803b27ca81a4767 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
2024-01-23 15:43:48 +01:00
@@ -570,7 +570,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
2022-12-07 20:22:28 +01:00
// Holder holder = worlddimension.type(); // CraftBukkit - decompile error
2023-03-14 20:54:57 +01:00
2021-11-29 12:55:13 +01:00
// Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
2024-01-13 21:31:02 +01:00
- super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess()))); // Paper - create paper world configs
+ super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess())), executor); // Paper - create paper world configs; Async-Anti-Xray: Pass executor
2021-11-29 12:55:13 +01:00
this.pvpMode = minecraftserver.isPvpAllowed();
this.convertable = convertable_conversionsession;
2022-06-08 05:40:53 +02:00
this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile());
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
2024-02-01 10:15:57 +01:00
index 5063eb6d4a24600262c32d2c9eb5fb5bf8fa354e..692a01b52a71e26887ee42cbd5fd64b0a81bfc99 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
2022-06-08 05:40:53 +02:00
@@ -49,7 +49,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
2021-11-29 12:55:13 +01:00
public class ServerPlayerGameMode {
2022-03-01 06:43:03 +01:00
private static final Logger LOGGER = LogUtils.getLogger();
2021-11-29 12:55:13 +01:00
- protected ServerLevel level;
+ public ServerLevel level; // Paper - Anti-Xray - protected -> public
protected final ServerPlayer player;
private GameType gameModeForPlayer;
@Nullable
2024-01-23 15:43:48 +01:00
@@ -326,6 +326,8 @@ public class ServerPlayerGameMode {
2021-11-29 12:55:13 +01:00
}
}
+
2022-07-18 12:30:31 +02:00
+ this.level.chunkPacketBlockController.onPlayerLeftClickBlock(this, pos, action, direction, worldHeight, sequence); // Paper - Anti-Xray
2021-11-29 12:55:13 +01:00
}
2022-06-08 05:40:53 +02:00
public void destroyAndAck(BlockPos pos, int sequence, String reason) {
2023-09-24 04:35:16 +02:00
diff --git a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java
2024-01-24 15:57:53 +01:00
index f3b96a921e7d085b51da62fa5493384a7ded1f9d..12f2bf95d3ea3d29f6b4b9ec38a92f7102daa4a1 100644
2023-09-24 04:35:16 +02:00
--- a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java
+++ b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java
2024-01-24 15:57:53 +01:00
@@ -88,7 +88,10 @@ public class PlayerChunkSender {
2023-09-24 04:35:16 +02:00
public static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { // Paper - rewrite chunk loader - public
handler.player.serverLevel().chunkSource.chunkMap.getVisibleChunkIfPresent(chunk.getPos().toLong()).addPlayer(handler.player);
- handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), (BitSet)null, (BitSet)null));
+ // Paper start - Anti-Xray
+ final boolean shouldModify = world.chunkPacketBlockController.shouldModify(handler.player, chunk);
+ handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), (BitSet)null, (BitSet)null, shouldModify));
+ // Paper end - Anti-Xray
2024-01-23 15:43:48 +01:00
// 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), handler.getPlayer().getBukkitEntity()).callEvent();
2024-01-23 18:01:39 +01:00
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
2024-02-01 10:15:57 +01:00
index 23443444ae0c52392bd9cdd758057437d99e376a..10f2222c95362c41cab693410d0e7bb9746f3e4d 100644
2024-01-23 18:01:39 +01:00
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -418,7 +418,7 @@ public abstract class PlayerList {
.getHolderOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
new net.minecraft.world.level.chunk.EmptyLevelChunk(worldserver1, player.chunkPosition(), plains),
- worldserver1.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null)
+ worldserver1.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null, true)
);
}
// Paper end - Send empty chunk
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
2024-02-01 10:15:57 +01:00
index 6f2515d3476f7a5da898efb3c60e8f4aaad09b06..927c7948e567764e8cf75c7ce486e1ea6c9a8d87 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
2024-02-01 10:15:57 +01:00
@@ -172,6 +172,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
2022-06-09 10:51:45 +02:00
}
2024-01-13 21:31:02 +01:00
// Paper end - add paper world config
2021-11-29 12:55:13 +01:00
+ public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
public static BlockPos lastPhysicsProblem; // Spigot
2022-06-09 10:51:45 +02:00
private org.spigotmc.TickLimiter entityLimiter;
2024-02-01 10:15:57 +01:00
@@ -197,7 +198,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
2021-11-29 12:55:13 +01:00
public abstract ResourceKey<LevelStem> getTypeKey();
2024-01-13 21:31:02 +01:00
- protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator) { // Paper - create paper world config
+ protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config; Async-Anti-Xray: Pass executor
2021-11-29 12:55:13 +01:00
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
2024-01-13 21:31:02 +01:00
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
2021-11-29 12:55:13 +01:00
this.generator = gen;
2024-02-01 10:15:57 +01:00
@@ -283,6 +284,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
2024-01-24 11:45:17 +01:00
this.keepSpawnInMemory = this.paperConfig().spawn.keepSpawnLoaded; // Paper - Option to keep spawn chunks loaded
2023-10-27 01:34:58 +02:00
this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime);
2022-06-09 10:51:45 +02:00
+ this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
2021-11-29 12:55:13 +01:00
}
2024-01-21 17:39:05 +01:00
// Paper start - Cancel hit for vanished players
2024-02-01 10:15:57 +01:00
@@ -558,6 +560,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
2021-11-29 12:55:13 +01:00
// CraftBukkit end
BlockState iblockdata1 = chunk.setBlockState(pos, state, (flags & 64) != 0, (flags & 1024) == 0); // CraftBukkit custom NO_PLACE flag
+ this.chunkPacketBlockController.onBlockChange(this, pos, state, iblockdata1, flags, maxUpdateDepth); // Paper - Anti-Xray
if (iblockdata1 == null) {
// CraftBukkit start - remove blockstate if failed (or the same)
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
2023-10-17 03:57:45 +02:00
index 5e8d2e4245757a0889645ea79ee68afb53f7dde4..f7e5e016a7028a9196e689e950805b0d5b31fe38 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
2023-10-17 03:57:45 +02:00
@@ -152,17 +152,17 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
2022-07-18 12:30:31 +02:00
}
}
2023-06-09 06:29:58 +02:00
- ChunkAccess.replaceMissingSections(biomeRegistry, this.sections);
+ this.replaceMissingSections(biomeRegistry, this.sections); // Paper - Anti-Xray - make it a non-static method
2022-07-18 12:30:31 +02:00
// CraftBukkit start
2023-06-09 06:29:58 +02:00
this.biomeRegistry = biomeRegistry;
2022-07-18 12:30:31 +02:00
}
public final Registry<Biome> biomeRegistry;
// CraftBukkit end
2023-06-09 06:29:58 +02:00
- private static void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sectionArray) {
+ private void replaceMissingSections(Registry<Biome> biomeRegistry, LevelChunkSection[] sectionArray) { // Paper - Anti-Xray - static -> non-static
2021-11-29 12:55:13 +01:00
for (int i = 0; i < sectionArray.length; ++i) {
if (sectionArray[i] == null) {
2023-06-09 06:29:58 +02:00
- sectionArray[i] = new LevelChunkSection(biomeRegistry);
+ sectionArray[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 start - Anti-Xray - Add parameters
2021-11-29 12:55:13 +01:00
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
2024-01-24 11:45:17 +01:00
index 6a5756bd333d9b221e7770842e5114d295cb7f1d..2eeb0c78f2b717b59542b6b668371558ae2fcc25 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
2023-09-24 06:43:10 +02:00
@@ -91,7 +91,7 @@ public class LevelChunk extends ChunkAccess {
2021-11-29 12:55:13 +01:00
}
public LevelChunk(Level world, ChunkPos pos, UpgradeData upgradeData, LevelChunkTicks<Block> blockTickScheduler, LevelChunkTicks<Fluid> fluidTickScheduler, long inhabitedTime, @Nullable LevelChunkSection[] sectionArrayInitializer, @Nullable LevelChunk.PostLoadProcessor entityLoader, @Nullable BlendingData blendingData) {
2022-12-07 22:36:56 +01:00
- super(pos, upgradeData, world, world.registryAccess().registryOrThrow(Registries.BIOME), inhabitedTime, sectionArrayInitializer, blendingData);
2022-12-07 20:22:28 +01:00
+ super(pos, upgradeData, world, net.minecraft.server.MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME), inhabitedTime, sectionArrayInitializer, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry
2023-10-17 03:57:45 +02:00
this.tickersInLevel = Maps.newHashMap();
this.level = (ServerLevel) world; // CraftBukkit - type
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap();
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
2024-01-23 18:01:39 +01:00
index b606e33f8b64eaba28c008cc353d88aa45549e31..8852263cb6faec1b68326145aa30e5cd36d066e7 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
2023-06-09 06:29:58 +02:00
@@ -33,9 +33,12 @@ public class LevelChunkSection {
2021-11-29 12:55:13 +01:00
this.recalcBlockCounts();
}
2023-06-09 06:29:58 +02:00
- public LevelChunkSection(Registry<Biome> biomeRegistry) {
2021-11-29 12:55:13 +01:00
- this.states = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
2022-03-01 06:43:03 +01:00
- this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
2023-06-09 06:29:58 +02:00
+ // Paper start - Anti-Xray - Add parameters
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public LevelChunkSection(Registry<Biome> biomeRegistry) { 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
+ 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
2022-03-01 06:43:03 +01:00
+ this.biomes = new PalettedContainer<>(biomeRegistry.asHolderIdMap(), biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null); // Paper - Anti-Xray - Add preset biomes
2021-11-29 12:55:13 +01:00
}
2023-06-09 06:29:58 +02:00
public BlockState getBlockState(int x, int y, int z) {
@@ -172,10 +175,13 @@ public class LevelChunkSection {
2022-06-08 05:40:53 +02:00
this.biomes = datapaletteblock;
2021-11-29 12:55:13 +01:00
}
- public void write(FriendlyByteBuf buf) {
+ // Paper start - Anti-Xray - Add chunk packet info
2023-06-09 06:29:58 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public void write(FriendlyByteBuf buf) { this.write(buf, null, 0); }
+ public void write(FriendlyByteBuf buf, com.destroystokyo.paper.antixray.ChunkPacketInfo<BlockState> chunkPacketInfo, int chunkSectionIndex) {
2021-11-29 12:55:13 +01:00
buf.writeShort(this.nonEmptyBlockCount);
- this.states.write(buf);
- this.biomes.write(buf);
2023-06-09 06:29:58 +02:00
+ this.states.write(buf, chunkPacketInfo, chunkSectionIndex);
+ this.biomes.write(buf, null, chunkSectionIndex);
2021-11-29 12:55:13 +01:00
+ // Paper end
}
public int getSerializedSize() {
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
2024-01-23 15:43:48 +01:00
index dfae0918079425df92d958b04275be8ae60d4b60..0f930f8355ea99d1cb1a8d27edc1c224588f852f 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
2023-09-24 04:35:16 +02:00
@@ -30,6 +30,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2021-11-29 12:55:13 +01:00
return 0;
};
public final IdMap<T> registry;
2022-03-01 04:25:13 +01:00
+ private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values
2021-11-29 12:55:13 +01:00
private volatile PalettedContainer.Data<T> data;
private final PalettedContainer.Strategy strategy;
2024-01-23 15:43:48 +01:00
// private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
2023-09-24 04:35:16 +02:00
@@ -42,14 +43,19 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2024-01-23 15:43:48 +01:00
// this.threadingDetector.checkAndUnlock(); // Paper - disable this
2021-11-29 12:55:13 +01:00
}
2022-07-27 22:17:18 +02:00
- public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) {
2022-07-27 22:46:05 +02:00
- PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = PalettedContainer::unpack;
2022-07-18 12:30:31 +02:00
+ // Paper start - Anti-Xray - Add preset values
2022-07-28 10:30:32 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) { return PalettedContainer.codecRW(idList, entryCodec, paletteProvider, defaultValue, null); }
2022-07-27 22:17:18 +02:00
+ public static <T> Codec<PalettedContainer<T>> codecRW(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues) {
2022-07-28 10:30:32 +02:00
+ PalettedContainerRO.Unpacker<T, PalettedContainer<T>> unpacker = (idListx, paletteProviderx, serialized) -> {
+ return unpack(idListx, paletteProviderx, serialized, defaultValue, presetValues);
2022-07-18 12:30:31 +02:00
+ };
+ // Paper end
2022-07-27 22:17:18 +02:00
return codec(idList, entryCodec, paletteProvider, defaultValue, unpacker);
2022-06-08 05:40:53 +02:00
}
2022-07-27 22:46:05 +02:00
public static <T> Codec<PalettedContainerRO<T>> codecRO(IdMap<T> idList, Codec<T> entryCodec, PalettedContainer.Strategy paletteProvider, T defaultValue) {
PalettedContainerRO.Unpacker<T, PalettedContainerRO<T>> unpacker = (idListx, paletteProviderx, serialized) -> {
- return unpack(idListx, paletteProviderx, serialized).map((result) -> {
+ return unpack(idListx, paletteProviderx, serialized, defaultValue, null).map((result) -> { // Paper - Anti-Xray - Add preset values
return result;
});
};
2023-09-24 04:35:16 +02:00
@@ -66,19 +72,52 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2021-11-29 12:55:13 +01:00
});
}
- public PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Configuration<T> dataProvider, BitStorage storage, List<T> paletteEntries) {
+ // Paper start - Anti-Xray - Add preset values
2022-07-18 12:30:31 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Configuration<T> dataProvider, BitStorage storage, List<T> paletteEntries) { this(idList, paletteProvider, dataProvider, storage, paletteEntries, null, null); }
2022-03-01 04:25:13 +01:00
+ public PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Configuration<T> dataProvider, BitStorage storage, List<T> paletteEntries, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues) {
2021-11-29 12:55:13 +01:00
+ this.presetValues = presetValues;
this.registry = idList;
this.strategy = paletteProvider;
this.data = new PalettedContainer.Data<>(dataProvider, storage, dataProvider.factory().create(dataProvider.bits(), idList, this, paletteEntries));
+
+ if (presetValues != null && (dataProvider.factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY ? this.data.palette.valueFor(0) != defaultValue : dataProvider.factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY)) {
+ // In 1.18 Mojang unfortunately removed code that already handled possible resize operations on read from disk for us
+ // We readd this here but in a smarter way than it was before
+ int maxSize = 1 << dataProvider.bits();
+
+ for (T presetValue : presetValues) {
+ if (this.data.palette.getSize() >= maxSize) {
+ java.util.Set<T> allValues = new java.util.HashSet<>(paletteEntries);
+ allValues.addAll(Arrays.asList(presetValues));
+ int newBits = Mth.ceillog2(allValues.size());
+
+ if (newBits > dataProvider.bits()) {
+ this.onResize(newBits, null);
+ }
+
+ break;
+ }
+
+ this.data.palette.idFor(presetValue);
+ }
+ }
+ // Paper end
}
- private PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Data<T> data) {
+ // Paper start - Anti-Xray - Add preset values
2022-03-01 04:25:13 +01:00
+ private PalettedContainer(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainer.Data<T> data, T @org.jetbrains.annotations.Nullable [] presetValues) {
2021-11-29 12:55:13 +01:00
+ this.presetValues = presetValues;
+ // Paper end
this.registry = idList;
this.strategy = paletteProvider;
this.data = data;
}
- public PalettedContainer(IdMap<T> idList, T object, PalettedContainer.Strategy paletteProvider) {
+ // Paper start - Anti-Xray - Add preset values
2022-07-18 12:30:31 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public PalettedContainer(IdMap<T> idList, T object, PalettedContainer.Strategy paletteProvider) { this(idList, object, paletteProvider, null); }
2022-03-01 06:43:03 +01:00
+ public PalettedContainer(IdMap<T> idList, T object, PalettedContainer.Strategy paletteProvider, T @org.jetbrains.annotations.Nullable [] presetValues) {
2021-11-29 12:55:13 +01:00
+ this.presetValues = presetValues;
+ // Paper end
this.strategy = paletteProvider;
this.registry = idList;
this.data = this.createOrReuseData((PalettedContainer.Data<T>)null, 0);
2023-09-24 04:35:16 +02:00
@@ -93,11 +132,33 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2021-11-29 12:55:13 +01:00
@Override
2024-01-23 15:43:48 +01:00
public synchronized int onResize(int newBits, T object) { // Paper - synchronize
2021-11-29 12:55:13 +01:00
PalettedContainer.Data<T> data = this.data;
+
+ // Paper start - Anti-Xray - Add preset values
+ if (this.presetValues != null && object != null && data.configuration().factory() == PalettedContainer.Strategy.SINGLE_VALUE_PALETTE_FACTORY) {
+ int duplicates = 0;
+ List<T> presetValues = Arrays.asList(this.presetValues);
+ duplicates += presetValues.contains(object) ? 1 : 0;
+ duplicates += presetValues.contains(data.palette.valueFor(0)) ? 1 : 0;
+ newBits = Mth.ceillog2((1 << this.strategy.calculateBitsForSerialization(this.registry, 1 << newBits)) + presetValues.size() - duplicates);
+ }
+
PalettedContainer.Data<T> data2 = this.createOrReuseData(data, newBits);
data2.copyFrom(data.palette, data.storage);
this.data = data2;
- return data2.palette.idFor(object);
+ this.addPresetValues();
+ return object == null ? -1 : data2.palette.idFor(object);
+ // Paper end
2023-03-23 22:57:03 +01:00
+ }
+
2021-11-29 12:55:13 +01:00
+ // Paper start - Anti-Xray - Add preset values
+ private void addPresetValues() {
+ if (this.presetValues != null && this.data.configuration().factory() != PalettedContainer.Strategy.GLOBAL_PALETTE_FACTORY) {
+ for (T presetValue : this.presetValues) {
+ this.data.palette.idFor(presetValue);
+ }
+ }
2023-03-23 22:57:03 +01:00
}
2021-11-29 12:55:13 +01:00
+ // Paper end
2023-03-23 22:57:03 +01:00
2021-11-29 12:55:13 +01:00
public T getAndSet(int x, int y, int z, T value) {
this.acquire();
2023-09-24 04:35:16 +02:00
@@ -167,25 +228,34 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2021-11-29 12:55:13 +01:00
data.palette.read(buf);
buf.readLongArray(data.storage.getRaw());
this.data = data;
2022-07-18 12:30:31 +02:00
+ this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server)
2021-11-29 12:55:13 +01:00
} finally {
this.release();
}
}
2024-01-23 15:43:48 +01:00
+ // Paper start - Anti-Xray; Add chunk packet info
2023-03-23 22:57:03 +01:00
+ @Override
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public void write(FriendlyByteBuf buf) { this.write(buf, null, 0); }
2022-07-18 12:30:31 +02:00
@Override
2024-01-23 15:43:48 +01:00
- public synchronized void write(FriendlyByteBuf buf) { // Paper - synchronize
+ public synchronized void write(FriendlyByteBuf buf, @Nullable com.destroystokyo.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { // Paper - Synchronize
2021-11-29 12:55:13 +01:00
this.acquire();
try {
- this.data.write(buf);
2023-06-09 06:29:58 +02:00
+ this.data.write(buf, chunkPacketInfo, chunkSectionIndex);
2021-11-29 12:55:13 +01:00
+
+ if (chunkPacketInfo != null) {
+ chunkPacketInfo.setPresetValues(chunkSectionIndex, this.presetValues);
+ }
+ // Paper end
} finally {
this.release();
}
}
2022-07-27 22:17:18 +02:00
- private static <T> DataResult<PalettedContainer<T>> unpack(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainerRO.PackedData<T> serialized) {
+ private static <T> DataResult<PalettedContainer<T>> unpack(IdMap<T> idList, PalettedContainer.Strategy paletteProvider, PalettedContainerRO.PackedData<T> serialized, T defaultValue, T @org.jetbrains.annotations.Nullable [] presetValues) { // Paper - Anti-Xray - Add preset values
List<T> list = serialized.paletteEntries();
int i = paletteProvider.size();
int j = paletteProvider.calculateBitsForSerialization(idList, list.size());
2023-09-24 04:35:16 +02:00
@@ -225,7 +295,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2021-11-29 12:55:13 +01:00
}
}
2022-07-27 22:17:18 +02:00
- return DataResult.success(new PalettedContainer<>(idList, paletteProvider, configuration, bitStorage, list));
+ return DataResult.success(new PalettedContainer<>(idList, paletteProvider, configuration, bitStorage, list, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
2021-11-29 12:55:13 +01:00
}
2022-06-08 05:40:53 +02:00
@Override
2023-09-24 04:35:16 +02:00
@@ -285,12 +355,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
2021-11-29 12:55:13 +01:00
}
public PalettedContainer<T> copy() {
2022-06-08 05:40:53 +02:00
- return new PalettedContainer<>(this.registry, this.strategy, this.data.copy());
+ return new PalettedContainer<>(this.registry, this.strategy, this.data.copy(), this.presetValues); // Paper - Anti-Xray - Add preset values
2021-11-29 12:55:13 +01:00
}
2022-06-08 05:40:53 +02:00
@Override
2022-07-18 12:30:31 +02:00
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
2023-09-24 04:35:16 +02:00
@@ -334,9 +404,18 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
return 1 + this.palette.getSerializedSize() + VarInt.getByteSize(this.storage.getRaw().length) + this.storage.getRaw().length * 8;
2021-11-29 12:55:13 +01:00
}
- public void write(FriendlyByteBuf buf) {
+ // Paper start - Anti-Xray - Add chunk packet info
2023-06-09 06:29:58 +02:00
+ public void write(FriendlyByteBuf buf, @Nullable com.destroystokyo.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) {
2021-11-29 12:55:13 +01:00
buf.writeByte(this.storage.getBits());
this.palette.write(buf);
+
+ if (chunkPacketInfo != null) {
+ chunkPacketInfo.setBits(chunkSectionIndex, this.configuration.bits());
+ chunkPacketInfo.setPalette(chunkSectionIndex, this.palette);
2023-09-24 04:35:16 +02:00
+ chunkPacketInfo.setIndex(chunkSectionIndex, buf.writerIndex() + VarInt.getByteSize(this.storage.getRaw().length));
2021-11-29 12:55:13 +01:00
+ }
+ // Paper end
+
buf.writeLongArray(this.storage.getRaw());
}
2022-06-08 05:40:53 +02:00
2022-07-18 12:30:31 +02:00
diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainerRO.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainerRO.java
2023-06-09 06:29:58 +02:00
index 9a2bf744abd8916d492e901be889223591bac3fd..1dd415c96d17eff8e7555c33d3c52e57f2559fa5 100644
2022-07-18 12:30:31 +02:00
--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainerRO.java
+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainerRO.java
@@ -14,7 +14,10 @@ public interface PalettedContainerRO<T> {
2022-07-27 22:17:18 +02:00
void getAll(Consumer<T> action);
2022-07-18 12:30:31 +02:00
- void write(FriendlyByteBuf buf);
+ // Paper start - Anti-Xray - Add chunk packet info
+ @Deprecated @io.papermc.paper.annotation.DoNotUse void write(FriendlyByteBuf buf);
2023-06-09 06:29:58 +02:00
+ void write(FriendlyByteBuf buf, @javax.annotation.Nullable com.destroystokyo.paper.antixray.ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex);
2022-07-18 12:30:31 +02:00
+ // Paper end
int getSerializedSize();
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
2024-01-25 10:54:46 +01:00
index 5d50f1bcba507975b8942529104c0ccd5e08c252..1ee35c828ea637e2954158060e1ad98f2649cedd 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
2022-12-07 20:22:28 +01:00
@@ -71,7 +71,7 @@ import org.slf4j.Logger;
2021-11-29 12:55:13 +01:00
public class ChunkSerializer {
2022-06-08 05:40:53 +02:00
- public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
+ public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null); // Paper - Anti-Xray - Add preset block states
2022-03-01 06:43:03 +01:00
private static final Logger LOGGER = LogUtils.getLogger();
2021-11-29 12:55:13 +01:00
private static final String TAG_UPGRADE_DATA = "UpgradeData";
private static final String BLOCK_TICKS_TAG = "block_ticks";
2024-01-24 13:07:40 +01:00
@@ -172,16 +172,20 @@ public class ChunkSerializer {
2021-11-29 12:55:13 +01:00
if (k >= 0 && k < achunksection.length) {
Logger logger;
PalettedContainer datapaletteblock;
+ // Paper start - Anti-Xray - Add preset block states
2023-06-09 06:29:58 +02:00
+ BlockState[] presetBlockStates = world.chunkPacketBlockController.getPresetBlockStates(world, chunkPos, b0);
2021-11-29 12:55:13 +01:00
if (nbttagcompound1.contains("block_states", 10)) {
- dataresult = ChunkSerializer.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, nbttagcompound1.getCompound("block_states")).promotePartial((s) -> {
2022-06-08 05:40:53 +02:00
+ Codec<PalettedContainer<BlockState>> blockStateCodec = presetBlockStates == null ? ChunkSerializer.BLOCK_STATE_CODEC : PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), presetBlockStates);
2021-11-29 12:55:13 +01:00
+ dataresult = blockStateCodec.parse(NbtOps.INSTANCE, nbttagcompound1.getCompound("block_states")).promotePartial((s) -> {
ChunkSerializer.logErrors(chunkPos, b0, s);
});
logger = ChunkSerializer.LOGGER;
Objects.requireNonNull(logger);
2022-03-01 06:43:03 +01:00
datapaletteblock = (PalettedContainer) ((DataResult<PalettedContainer<BlockState>>) dataresult).getOrThrow(false, logger::error); // CraftBukkit - decompile error
2021-11-29 12:55:13 +01:00
} else {
- datapaletteblock = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
+ datapaletteblock = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, presetBlockStates);
+ // Paper end
}
2022-06-08 05:40:53 +02:00
PalettedContainer object; // CraftBukkit - read/write
2024-01-24 13:07:40 +01:00
@@ -194,7 +198,7 @@ public class ChunkSerializer {
2021-11-29 12:55:13 +01:00
Objects.requireNonNull(logger);
2022-06-08 05:40:53 +02:00
object = ((DataResult<PalettedContainer<Holder<Biome>>>) dataresult).getOrThrow(false, logger::error); // CraftBukkit - decompile error
2021-11-29 12:55:13 +01:00
} else {
2022-06-08 05:40:53 +02:00
- object = new PalettedContainer<>(iregistry.asHolderIdMap(), iregistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
+ object = new PalettedContainer<>(iregistry.asHolderIdMap(), iregistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES, null); // Paper - Anti-Xray - Add preset biomes
2021-11-29 12:55:13 +01:00
}
2023-06-09 06:29:58 +02:00
LevelChunkSection chunksection = new LevelChunkSection(datapaletteblock, (PalettedContainer) object); // CraftBukkit - read/write
2024-01-24 13:07:40 +01:00
@@ -429,7 +433,7 @@ public class ChunkSerializer {
2021-11-29 12:55:13 +01:00
2022-06-08 05:40:53 +02:00
// 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.getHolderOrThrow(Biomes.PLAINS));
+ return PalettedContainer.codecRW(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getHolderOrThrow(Biomes.PLAINS), null); // Paper - Anti-Xray - Add preset biomes
2021-11-29 12:55:13 +01:00
}
2022-06-08 05:40:53 +02:00
// CraftBukkit end
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
2024-01-23 15:43:48 +01:00
index d4e0ef75dd12709a0dcf9193821c30b8943e6c36..fd702027e62eb38d51fb7c46ef268e9bb94e1e92 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
2023-09-24 04:35:16 +02:00
@@ -53,7 +53,7 @@ public class CraftChunk implements Chunk {
2021-11-29 12:55:13 +01:00
private final ServerLevel worldServer;
private final int x;
private final int z;
- private static final PalettedContainer<net.minecraft.world.level.block.state.BlockState> emptyBlockIDs = new PalettedContainer<>(net.minecraft.world.level.block.Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
+ private static final PalettedContainer<net.minecraft.world.level.block.state.BlockState> emptyBlockIDs = new PalettedContainer<>(net.minecraft.world.level.block.Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); // Paper - Anti-Xray - Add preset block states
2023-10-26 23:56:40 +02:00
private static final byte[] FULL_LIGHT = new byte[2048];
private static final byte[] EMPTY_LIGHT = new byte[2048];
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2024-02-01 10:15:57 +01:00
index 3ea2cee19e6fe1b94e39ef535102d41ec2c0bdad..b8f05300a17d415505deb8da4a923357220ae1bd 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2024-01-24 15:57:53 +01:00
@@ -2610,7 +2610,7 @@ public final class CraftServer implements Server {
2021-11-29 12:55:13 +01:00
public ChunkGenerator.ChunkData createChunkData(World world) {
2023-06-13 01:51:45 +02:00
Preconditions.checkArgument(world != null, "World cannot be null");
2021-11-29 12:55:13 +01:00
ServerLevel handle = ((CraftWorld) world).getHandle();
2022-12-07 20:22:28 +01:00
- return new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registries.BIOME));
+ return new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registries.BIOME), world); // Paper - Anti-Xray - Add parameters
2021-11-29 12:55:13 +01:00
}
2024-01-23 15:43:48 +01:00
// Paper start - Allow delegation to vanilla chunk gen
2022-06-02 04:08:51 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
2024-01-25 10:54:46 +01:00
index d1cff7794313fd29717e9d7818ccf00e340f08a9..a139601888b88e8580bdb9c2469386a94abae975 100644
2022-06-02 04:08:51 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
2024-01-25 10:54:46 +01:00
@@ -524,11 +524,16 @@ public class CraftWorld extends CraftRegionAccessor implements World {
2022-06-02 04:08:51 +02:00
List<ServerPlayer> playersInRange = playerChunk.playerProvider.getPlayers(playerChunk.getPos(), false);
2022-09-26 10:02:51 +02:00
if (playersInRange.isEmpty()) return true; // Paper - rewrite player chunk loader
2022-06-02 04:08:51 +02:00
2023-06-09 06:29:58 +02:00
- ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, this.world.getLightEngine(), null, null);
2022-06-02 04:08:51 +02:00
+ // Paper start - Anti-Xray - Bypass
+ Map<Object, ClientboundLevelChunkWithLightPacket> refreshPackets = new HashMap<>();
for (ServerPlayer player : playersInRange) {
if (player.connection == null) continue;
- player.connection.send(refreshPacket);
+ Boolean shouldModify = chunk.getLevel().chunkPacketBlockController.shouldModify(player, chunk);
+ player.connection.send(refreshPackets.computeIfAbsent(shouldModify, s -> { // Use connection to prevent creating firing event
2023-06-09 06:29:58 +02:00
+ return new ClientboundLevelChunkWithLightPacket(chunk, this.world.getLightEngine(), null, null, (Boolean) s);
2022-06-02 04:08:51 +02:00
+ }));
+ // Paper end
}
2022-09-26 10:02:51 +02:00
// Paper - rewrite player chunk loader
2021-11-29 12:55:13 +01:00
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
2024-01-23 15:43:48 +01:00
index 9b640705f2c810160aa7fea5006429ec41d0c858..44a010590e830fd238cf6fdda443e28b72022e66 100644
2021-11-29 12:55:13 +01:00
--- a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
2024-01-14 10:46:04 +01:00
@@ -27,8 +27,13 @@ public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
2021-11-29 12:55:13 +01:00
private final Registry<net.minecraft.world.level.biome.Biome> biomes;
private Set<BlockPos> tiles;
private final Set<BlockPos> lights = new HashSet<>();
+ // Paper start - Anti-Xray - Add parameters
Updated Upstream (Bukkit/CraftBukkit) (#10034)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
f29cb801 Separate checkstyle-suppressions file is not required
86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API
d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor
b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack
9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode()
994a6163 Attempt upgrade of resolver libraries
CraftBukkit Changes:
b3b43a6ad Add Checkstyle check for unused imports
13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names
3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API
2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor
1dbdbbed4 PR-1238: Remove unnecessary sign ticking
659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper
e37e29ce0 Increase outdated build delay
c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack
492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode()
e11fbb9d7 Upgrade MySQL driver
9f3a0bd2a Attempt upgrade of resolver libraries
60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion
Spigot Changes:
06d602e7 Rebuild patches
2023-12-17 03:09:28 +01:00
+ private final org.bukkit.World world;
2021-11-29 12:55:13 +01:00
- public OldCraftChunkData(int minHeight, int maxHeight, Registry<net.minecraft.world.level.biome.Biome> biomes) {
2022-07-18 12:30:31 +02:00
+ @Deprecated @io.papermc.paper.annotation.DoNotUse public OldCraftChunkData(int minHeight, int maxHeight, Registry<net.minecraft.world.level.biome.Biome> biomes) { this(minHeight, maxHeight, biomes, null); }
Updated Upstream (Bukkit/CraftBukkit) (#10034)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
f29cb801 Separate checkstyle-suppressions file is not required
86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API
d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor
b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack
9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode()
994a6163 Attempt upgrade of resolver libraries
CraftBukkit Changes:
b3b43a6ad Add Checkstyle check for unused imports
13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names
3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API
2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor
1dbdbbed4 PR-1238: Remove unnecessary sign ticking
659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper
e37e29ce0 Increase outdated build delay
c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack
492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode()
e11fbb9d7 Upgrade MySQL driver
9f3a0bd2a Attempt upgrade of resolver libraries
60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion
Spigot Changes:
06d602e7 Rebuild patches
2023-12-17 03:09:28 +01:00
+ public OldCraftChunkData(int minHeight, int maxHeight, Registry<net.minecraft.world.level.biome.Biome> biomes, org.bukkit.World world) {
2021-11-29 12:55:13 +01:00
+ this.world = world;
+ // Paper end
this.minHeight = minHeight;
this.maxHeight = maxHeight;
this.biomes = biomes;
2024-01-14 10:46:04 +01:00
@@ -176,7 +181,7 @@ public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
2021-11-29 12:55:13 +01:00
int offset = (y - this.minHeight) >> 4;
LevelChunkSection section = this.sections[offset];
if (create && section == null) {
2023-06-09 06:29:58 +02:00
- this.sections[offset] = section = new LevelChunkSection(this.biomes);
+ this.sections[offset] = section = new LevelChunkSection(this.biomes, this.world instanceof org.bukkit.craftbukkit.CraftWorld ? ((org.bukkit.craftbukkit.CraftWorld) this.world).getHandle() : null, null, offset + (this.minHeight >> 4)); // Paper - Anti-Xray - Add parameters
2021-11-29 12:55:13 +01:00
}
return section;
}