mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-22 17:07:34 +01:00
1568 lines
82 KiB
Diff
1568 lines
82 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: stonar96 <minecraft.stonar96@gmail.com>
|
|
Date: Mon, 20 Aug 2018 03:03:58 +0200
|
|
Subject: [PATCH] Anti-Xray
|
|
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
index 1278d09f70c1e97607ef20d87a178dc252c7f723..c45493e88bf7e8811be2759ff9ac19e3fe9d938a 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -1,7 +1,9 @@
|
|
package com.destroystokyo.paper;
|
|
|
|
+import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
+import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray.EngineMode;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.configuration.file.YamlConfiguration;
|
|
import org.spigotmc.SpigotWorldConfig;
|
|
@@ -461,4 +463,38 @@ public class PaperWorldConfig {
|
|
private void maxAutoSaveChunksPerTick() {
|
|
maxAutoSaveChunksPerTick = getInt("max-auto-save-chunks-per-tick", 24);
|
|
}
|
|
+
|
|
+ public boolean antiXray;
|
|
+ public EngineMode engineMode;
|
|
+ public int maxChunkSectionIndex;
|
|
+ public int updateRadius;
|
|
+ public boolean lavaObscures;
|
|
+ public boolean usePermission;
|
|
+ public List<String> hiddenBlocks;
|
|
+ public List<String> replacementBlocks;
|
|
+ private void antiXray() {
|
|
+ antiXray = getBoolean("anti-xray.enabled", false);
|
|
+ engineMode = EngineMode.getById(getInt("anti-xray.engine-mode", EngineMode.HIDE.getId()));
|
|
+ engineMode = engineMode == null ? EngineMode.HIDE : engineMode;
|
|
+ maxChunkSectionIndex = getInt("anti-xray.max-chunk-section-index", 3);
|
|
+ maxChunkSectionIndex = maxChunkSectionIndex > 15 ? 15 : maxChunkSectionIndex;
|
|
+ updateRadius = getInt("anti-xray.update-radius", 2);
|
|
+ lavaObscures = getBoolean("anti-xray.lava-obscures", false);
|
|
+ usePermission = getBoolean("anti-xray.use-permission", false);
|
|
+ hiddenBlocks = getList("anti-xray.hidden-blocks", Arrays.asList("gold_ore", "iron_ore", "coal_ore", "lapis_ore", "mossy_cobblestone", "obsidian", "chest", "diamond_ore", "redstone_ore", "clay", "emerald_ore", "ender_chest"));
|
|
+ replacementBlocks = getList("anti-xray.replacement-blocks", Arrays.asList("stone", "oak_planks"));
|
|
+ if (PaperConfig.version < 19) {
|
|
+ hiddenBlocks.remove("lit_redstone_ore");
|
|
+ int index = replacementBlocks.indexOf("planks");
|
|
+ if (index != -1) {
|
|
+ replacementBlocks.set(index, "oak_planks");
|
|
+ }
|
|
+ set("anti-xray.hidden-blocks", hiddenBlocks);
|
|
+ set("anti-xray.replacement-blocks", replacementBlocks);
|
|
+ }
|
|
+ log("Anti-Xray: " + (antiXray ? "enabled" : "disabled") + " / Engine Mode: " + engineMode.getDescription() + " / Up to " + ((maxChunkSectionIndex + 1) * 16) + " blocks / Update Radius: " + updateRadius);
|
|
+ if (antiXray && usePermission) {
|
|
+ Bukkit.getLogger().warning("You have enabled permission-based Anti-Xray checking - depending on your permission plugin, this may cause performance issues");
|
|
+ }
|
|
+ }
|
|
}
|
|
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
|
|
index 0000000000000000000000000000000000000000..83a023ae018cbb79b5f151b1c7a5c8ba0c3bf1bf
|
|
--- /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.BlockPosition;
|
|
+import net.minecraft.core.EnumDirection;
|
|
+import net.minecraft.network.protocol.game.PacketPlayOutMapChunk;
|
|
+import net.minecraft.server.level.EntityPlayer;
|
|
+import net.minecraft.server.level.PlayerInteractManager;
|
|
+import net.minecraft.world.level.World;
|
|
+import net.minecraft.world.level.block.state.IBlockData;
|
|
+import net.minecraft.world.level.chunk.Chunk;
|
|
+import net.minecraft.world.level.chunk.ChunkSection;
|
|
+import net.minecraft.world.level.chunk.IChunkAccess;
|
|
+
|
|
+public class ChunkPacketBlockController {
|
|
+
|
|
+ public static final ChunkPacketBlockController NO_OPERATION_INSTANCE = new ChunkPacketBlockController();
|
|
+
|
|
+ protected ChunkPacketBlockController() {
|
|
+
|
|
+ }
|
|
+
|
|
+ public IBlockData[] getPredefinedBlockData(World world, IChunkAccess chunk, ChunkSection chunkSection, boolean initializeBlocks) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ public boolean shouldModify(EntityPlayer entityPlayer, Chunk chunk, int chunkSectionSelector) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ public ChunkPacketInfo<IBlockData> getChunkPacketInfo(PacketPlayOutMapChunk packetPlayOutMapChunk, Chunk chunk, int chunkSectionSelector) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ public void modifyBlocks(PacketPlayOutMapChunk packetPlayOutMapChunk, ChunkPacketInfo<IBlockData> chunkPacketInfo) {
|
|
+ packetPlayOutMapChunk.setReady(true);
|
|
+ }
|
|
+
|
|
+ public void onBlockChange(World world, BlockPosition blockPosition, IBlockData newBlockData, IBlockData oldBlockData, int flag) {
|
|
+
|
|
+ }
|
|
+
|
|
+ public void onPlayerLeftClickBlock(PlayerInteractManager playerInteractManager, BlockPosition blockPosition, EnumDirection enumDirection) {
|
|
+
|
|
+ }
|
|
+}
|
|
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
|
|
index 0000000000000000000000000000000000000000..cd3b5b62d470ab6753b44f9b13dcf5522e4cbd15
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java
|
|
@@ -0,0 +1,650 @@
|
|
+package com.destroystokyo.paper.antixray;
|
|
+
|
|
+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;
|
|
+
|
|
+import net.minecraft.core.BlockPosition;
|
|
+import net.minecraft.core.EnumDirection;
|
|
+import net.minecraft.core.IRegistry;
|
|
+import net.minecraft.network.protocol.game.PacketPlayOutMapChunk;
|
|
+import net.minecraft.resources.MinecraftKey;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.level.EntityPlayer;
|
|
+import net.minecraft.server.level.PlayerInteractManager;
|
|
+import net.minecraft.server.level.WorldServer;
|
|
+import net.minecraft.world.level.ChunkCoordIntPair;
|
|
+import net.minecraft.world.level.World;
|
|
+import net.minecraft.world.level.block.Block;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import net.minecraft.world.level.block.state.IBlockData;
|
|
+import net.minecraft.world.level.chunk.Chunk;
|
|
+import net.minecraft.world.level.chunk.ChunkEmpty;
|
|
+import net.minecraft.world.level.chunk.ChunkSection;
|
|
+import net.minecraft.world.level.chunk.DataPalette;
|
|
+import net.minecraft.world.level.chunk.IChunkAccess;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.World.Environment;
|
|
+
|
|
+import com.destroystokyo.paper.PaperWorldConfig;
|
|
+
|
|
+public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockController {
|
|
+
|
|
+ private final Executor executor;
|
|
+ private final EngineMode engineMode;
|
|
+ private final int maxChunkSectionIndex;
|
|
+ private final int updateRadius;
|
|
+ private final boolean usePermission;
|
|
+ private final IBlockData[] predefinedBlockData;
|
|
+ private final IBlockData[] predefinedBlockDataFull;
|
|
+ private final IBlockData[] predefinedBlockDataStone;
|
|
+ private final IBlockData[] predefinedBlockDataNetherrack;
|
|
+ private final IBlockData[] predefinedBlockDataEndStone;
|
|
+ private final int[] predefinedBlockDataBitsGlobal;
|
|
+ private final int[] predefinedBlockDataBitsStoneGlobal;
|
|
+ private final int[] predefinedBlockDataBitsNetherrackGlobal;
|
|
+ private final int[] predefinedBlockDataBitsEndStoneGlobal;
|
|
+ private final boolean[] solidGlobal = new boolean[Block.REGISTRY_ID.size()];
|
|
+ private final boolean[] obfuscateGlobal = new boolean[Block.REGISTRY_ID.size()];
|
|
+ private final ChunkSection[] emptyNearbyChunkSections = {Chunk.EMPTY_CHUNK_SECTION, Chunk.EMPTY_CHUNK_SECTION, Chunk.EMPTY_CHUNK_SECTION, Chunk.EMPTY_CHUNK_SECTION};
|
|
+ private final int maxBlockYUpdatePosition;
|
|
+
|
|
+ public ChunkPacketBlockControllerAntiXray(World world, Executor executor) {
|
|
+ PaperWorldConfig paperWorldConfig = world.paperConfig;
|
|
+ engineMode = paperWorldConfig.engineMode;
|
|
+ maxChunkSectionIndex = paperWorldConfig.maxChunkSectionIndex;
|
|
+ updateRadius = paperWorldConfig.updateRadius;
|
|
+ usePermission = paperWorldConfig.usePermission;
|
|
+
|
|
+ this.executor = executor;
|
|
+
|
|
+ List<String> toObfuscate;
|
|
+
|
|
+ if (engineMode == EngineMode.HIDE) {
|
|
+ toObfuscate = paperWorldConfig.hiddenBlocks;
|
|
+ predefinedBlockData = null;
|
|
+ predefinedBlockDataFull = null;
|
|
+ predefinedBlockDataStone = new IBlockData[] {Blocks.STONE.getBlockData()};
|
|
+ predefinedBlockDataNetherrack = new IBlockData[] {Blocks.NETHERRACK.getBlockData()};
|
|
+ predefinedBlockDataEndStone = new IBlockData[] {Blocks.END_STONE.getBlockData()};
|
|
+ predefinedBlockDataBitsGlobal = null;
|
|
+ predefinedBlockDataBitsStoneGlobal = new int[] {ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(Blocks.STONE.getBlockData())};
|
|
+ predefinedBlockDataBitsNetherrackGlobal = new int[] {ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(Blocks.NETHERRACK.getBlockData())};
|
|
+ predefinedBlockDataBitsEndStoneGlobal = new int[] {ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(Blocks.END_STONE.getBlockData())};
|
|
+ } else {
|
|
+ toObfuscate = new ArrayList<>(paperWorldConfig.replacementBlocks);
|
|
+ List<IBlockData> predefinedBlockDataList = new LinkedList<IBlockData>();
|
|
+
|
|
+ for (String id : paperWorldConfig.hiddenBlocks) {
|
|
+ Block block = IRegistry.BLOCK.getOptional(new MinecraftKey(id)).orElse(null);
|
|
+
|
|
+ if (block != null && !block.isTileEntity()) {
|
|
+ toObfuscate.add(id);
|
|
+ predefinedBlockDataList.add(block.getBlockData());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // The doc of the LinkedHashSet(Collection<? extends E> c) constructor doesn't specify that the insertion order is the predictable iteration order of the specified Collection, although it is in the implementation
|
|
+ Set<IBlockData> predefinedBlockDataSet = new LinkedHashSet<IBlockData>();
|
|
+ // Therefore addAll(Collection<? extends E> c) is used, which guarantees this order in the doc
|
|
+ predefinedBlockDataSet.addAll(predefinedBlockDataList);
|
|
+ predefinedBlockData = predefinedBlockDataSet.size() == 0 ? new IBlockData[] {Blocks.DIAMOND_ORE.getBlockData()} : predefinedBlockDataSet.toArray(new IBlockData[0]);
|
|
+ predefinedBlockDataFull = predefinedBlockDataSet.size() == 0 ? new IBlockData[] {Blocks.DIAMOND_ORE.getBlockData()} : predefinedBlockDataList.toArray(new IBlockData[0]);
|
|
+ predefinedBlockDataStone = null;
|
|
+ predefinedBlockDataNetherrack = null;
|
|
+ predefinedBlockDataEndStone = null;
|
|
+ predefinedBlockDataBitsGlobal = new int[predefinedBlockDataFull.length];
|
|
+
|
|
+ for (int i = 0; i < predefinedBlockDataFull.length; i++) {
|
|
+ predefinedBlockDataBitsGlobal[i] = ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(predefinedBlockDataFull[i]);
|
|
+ }
|
|
+
|
|
+ predefinedBlockDataBitsStoneGlobal = null;
|
|
+ predefinedBlockDataBitsNetherrackGlobal = null;
|
|
+ predefinedBlockDataBitsEndStoneGlobal = null;
|
|
+ }
|
|
+
|
|
+ for (String id : toObfuscate) {
|
|
+ Block block = IRegistry.BLOCK.getOptional(new MinecraftKey(id)).orElse(null);
|
|
+
|
|
+ // Don't obfuscate air because air causes unnecessary block updates and causes block updates to fail in the void
|
|
+ if (block != null && !block.getBlockData().isAir()) {
|
|
+ // Replace all block states of a specified block
|
|
+ // No OBFHELPER for nms.BlockStateList#a() due to too many decompile errors
|
|
+ // The OBFHELPER should be getBlockDataList()
|
|
+ for (IBlockData blockData : block.getStates().a()) {
|
|
+ obfuscateGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(blockData)] = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ChunkEmpty emptyChunk = new ChunkEmpty(world, new ChunkCoordIntPair(0, 0));
|
|
+ BlockPosition zeroPos = new BlockPosition(0, 0, 0);
|
|
+
|
|
+ for (int i = 0; i < solidGlobal.length; i++) {
|
|
+ IBlockData blockData = ChunkSection.GLOBAL_PALETTE.getObject(i);
|
|
+
|
|
+ if (blockData != null) {
|
|
+ solidGlobal[i] = blockData.isOccluding(emptyChunk, zeroPos)
|
|
+ && blockData.getBlock() != Blocks.SPAWNER && blockData.getBlock() != Blocks.BARRIER && blockData.getBlock() != Blocks.SHULKER_BOX && blockData.getBlock() != Blocks.SLIME_BLOCK || paperWorldConfig.lavaObscures && blockData == Blocks.LAVA.getBlockData();
|
|
+ // Comparing blockData == Blocks.LAVA.getBlockData() instead of blockData.getBlock() == Blocks.LAVA ensures that only "stationary lava" is used
|
|
+ // shulker box checks TE.
|
|
+ }
|
|
+ }
|
|
+
|
|
+ this.maxBlockYUpdatePosition = (maxChunkSectionIndex + 1) * 16 + updateRadius - 1;
|
|
+ }
|
|
+
|
|
+ private int getPredefinedBlockDataFullLength() {
|
|
+ return engineMode == EngineMode.HIDE ? 1 : predefinedBlockDataFull.length;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public IBlockData[] getPredefinedBlockData(World world, IChunkAccess chunk, ChunkSection chunkSection, boolean initializeBlocks) {
|
|
+ // Return the block data which should be added to the data palettes so that they can be used for the obfuscation
|
|
+ if (chunkSection.getYPosition() >> 4 <= maxChunkSectionIndex) {
|
|
+ switch (engineMode) {
|
|
+ case HIDE:
|
|
+ switch (world.getWorld().getEnvironment()) {
|
|
+ case NETHER:
|
|
+ return predefinedBlockDataNetherrack;
|
|
+ case THE_END:
|
|
+ return predefinedBlockDataEndStone;
|
|
+ default:
|
|
+ return predefinedBlockDataStone;
|
|
+ }
|
|
+ default:
|
|
+ return predefinedBlockData;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean shouldModify(EntityPlayer entityPlayer, Chunk chunk, int chunkSectionSelector) {
|
|
+ return !usePermission || !entityPlayer.getBukkitEntity().hasPermission("paper.antixray.bypass");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public ChunkPacketInfoAntiXray getChunkPacketInfo(PacketPlayOutMapChunk packetPlayOutMapChunk, Chunk chunk, int chunkSectionSelector) {
|
|
+ // Return a new instance to collect data and objects in the right state while creating the chunk packet for thread safe access later
|
|
+ // Note: As of 1.14 this has to be moved later due to the chunk system.
|
|
+ ChunkPacketInfoAntiXray chunkPacketInfoAntiXray = new ChunkPacketInfoAntiXray(packetPlayOutMapChunk, chunk, chunkSectionSelector, this);
|
|
+ return chunkPacketInfoAntiXray;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void modifyBlocks(PacketPlayOutMapChunk packetPlayOutMapChunk, ChunkPacketInfo<IBlockData> chunkPacketInfo) {
|
|
+ if (chunkPacketInfo == null) {
|
|
+ packetPlayOutMapChunk.setReady(true);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!Bukkit.isPrimaryThread()) {
|
|
+ // plugins?
|
|
+ MinecraftServer.getServer().scheduleOnMain(() -> {
|
|
+ this.modifyBlocks(packetPlayOutMapChunk, chunkPacketInfo);
|
|
+ });
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ Chunk chunk = chunkPacketInfo.getChunk();
|
|
+ int x = chunk.getPos().x;
|
|
+ int z = chunk.getPos().z;
|
|
+ WorldServer world = (WorldServer)chunk.world;
|
|
+ ((ChunkPacketInfoAntiXray) chunkPacketInfo).setNearbyChunks(
|
|
+ (Chunk) world.getChunkIfLoadedImmediately(x - 1, z),
|
|
+ (Chunk) world.getChunkIfLoadedImmediately(x + 1, z),
|
|
+ (Chunk) world.getChunkIfLoadedImmediately(x, z - 1),
|
|
+ (Chunk) world.getChunkIfLoadedImmediately(x, z + 1));
|
|
+
|
|
+ executor.execute((ChunkPacketInfoAntiXray) 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[]> predefinedBlockDataBits = ThreadLocal.withInitial(() -> new int[getPredefinedBlockDataFullLength()]);
|
|
+ private static final ThreadLocal<boolean[]> solid = ThreadLocal.withInitial(() -> new boolean[Block.REGISTRY_ID.size()]);
|
|
+ private static final ThreadLocal<boolean[]> obfuscate = ThreadLocal.withInitial(() -> new boolean[Block.REGISTRY_ID.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[][]> nextNext = ThreadLocal.withInitial(() -> new boolean[16][16]);
|
|
+
|
|
+ public void obfuscate(ChunkPacketInfoAntiXray chunkPacketInfoAntiXray) {
|
|
+ int[] predefinedBlockDataBits = this.predefinedBlockDataBits.get();
|
|
+ boolean[] solid = this.solid.get();
|
|
+ boolean[] obfuscate = this.obfuscate.get();
|
|
+ boolean[][] current = this.current.get();
|
|
+ boolean[][] next = this.next.get();
|
|
+ boolean[][] nextNext = this.nextNext.get();
|
|
+ // dataBitsReader, dataBitsWriter and nearbyChunkSections could also be reused (with ThreadLocal if necessary) but it's not worth it
|
|
+ DataBitsReader dataBitsReader = new DataBitsReader();
|
|
+ DataBitsWriter dataBitsWriter = new DataBitsWriter();
|
|
+ ChunkSection[] nearbyChunkSections = new ChunkSection[4];
|
|
+ boolean[] solidTemp = null;
|
|
+ boolean[] obfuscateTemp = null;
|
|
+ dataBitsReader.setDataBits(chunkPacketInfoAntiXray.getData());
|
|
+ dataBitsWriter.setDataBits(chunkPacketInfoAntiXray.getData());
|
|
+ int numberOfBlocks = predefinedBlockDataBits.length;
|
|
+ // Keep the lambda expressions as simple as possible. They are used very frequently.
|
|
+ IntSupplier random = numberOfBlocks == 1 ? (() -> 0) : new IntSupplier() {
|
|
+ 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.getPredefinedObjects(chunkSectionIndex) != null) {
|
|
+ int[] predefinedBlockDataBitsTemp;
|
|
+
|
|
+ if (chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex) == ChunkSection.GLOBAL_PALETTE) {
|
|
+ predefinedBlockDataBitsTemp = engineMode == EngineMode.HIDE ? chunkPacketInfoAntiXray.getChunk().world.getWorld().getEnvironment() == Environment.NETHER ? predefinedBlockDataBitsNetherrackGlobal : chunkPacketInfoAntiXray.getChunk().world.getWorld().getEnvironment() == Environment.THE_END ? predefinedBlockDataBitsEndStoneGlobal : predefinedBlockDataBitsStoneGlobal : predefinedBlockDataBitsGlobal;
|
|
+ } else {
|
|
+ // If it's this.predefinedBlockData, use this.predefinedBlockDataFull instead
|
|
+ IBlockData[] predefinedBlockDataFull = chunkPacketInfoAntiXray.getPredefinedObjects(chunkSectionIndex) == predefinedBlockData ? this.predefinedBlockDataFull : chunkPacketInfoAntiXray.getPredefinedObjects(chunkSectionIndex);
|
|
+ predefinedBlockDataBitsTemp = predefinedBlockDataBits;
|
|
+
|
|
+ for (int i = 0; i < predefinedBlockDataBitsTemp.length; i++) {
|
|
+ predefinedBlockDataBitsTemp[i] = chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex).getOrCreateIdFor(predefinedBlockDataFull[i]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ dataBitsWriter.setIndex(chunkPacketInfoAntiXray.getDataBitsIndex(chunkSectionIndex));
|
|
+
|
|
+ // Check if the chunk section below was not obfuscated
|
|
+ if (chunkSectionIndex == 0 || !chunkPacketInfoAntiXray.isWritten(chunkSectionIndex - 1) || chunkPacketInfoAntiXray.getPredefinedObjects(chunkSectionIndex - 1) == null) {
|
|
+ // If so, initialize some stuff
|
|
+ dataBitsReader.setBitsPerObject(chunkPacketInfoAntiXray.getBitsPerObject(chunkSectionIndex));
|
|
+ dataBitsReader.setIndex(chunkPacketInfoAntiXray.getDataBitsIndex(chunkSectionIndex));
|
|
+ solidTemp = readDataPalette(chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex), solid, solidGlobal);
|
|
+ obfuscateTemp = readDataPalette(chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex), obfuscate, obfuscateGlobal);
|
|
+ // Read the blocks of the upper layer of the chunk section below if it exists
|
|
+ ChunkSection belowChunkSection = null;
|
|
+ boolean skipFirstLayer = chunkSectionIndex == 0 || (belowChunkSection = chunkPacketInfoAntiXray.getChunk().getSections()[chunkSectionIndex - 1]) == Chunk.EMPTY_CHUNK_SECTION;
|
|
+
|
|
+ for (int z = 0; z < 16; z++) {
|
|
+ for (int x = 0; x < 16; x++) {
|
|
+ current[z][x] = true;
|
|
+ next[z][x] = skipFirstLayer || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(belowChunkSection.getType(x, 15, z))];
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Abuse the obfuscateLayer method to read the blocks of the first layer of the current chunk section
|
|
+ dataBitsWriter.setBitsPerObject(0);
|
|
+ obfuscateLayer(-1, dataBitsReader, dataBitsWriter, solidTemp, obfuscateTemp, predefinedBlockDataBitsTemp, current, next, nextNext, emptyNearbyChunkSections, random);
|
|
+ }
|
|
+
|
|
+ dataBitsWriter.setBitsPerObject(chunkPacketInfoAntiXray.getBitsPerObject(chunkSectionIndex));
|
|
+ nearbyChunkSections[0] = chunkPacketInfoAntiXray.getNearbyChunks()[0] == null ? Chunk.EMPTY_CHUNK_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[0].getSections()[chunkSectionIndex];
|
|
+ nearbyChunkSections[1] = chunkPacketInfoAntiXray.getNearbyChunks()[1] == null ? Chunk.EMPTY_CHUNK_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[1].getSections()[chunkSectionIndex];
|
|
+ nearbyChunkSections[2] = chunkPacketInfoAntiXray.getNearbyChunks()[2] == null ? Chunk.EMPTY_CHUNK_SECTION : chunkPacketInfoAntiXray.getNearbyChunks()[2].getSections()[chunkSectionIndex];
|
|
+ nearbyChunkSections[3] = chunkPacketInfoAntiXray.getNearbyChunks()[3] == null ? Chunk.EMPTY_CHUNK_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;
|
|
+ obfuscateLayer(y, dataBitsReader, dataBitsWriter, solidTemp, obfuscateTemp, predefinedBlockDataBitsTemp, current, next, nextNext, nearbyChunkSections, random);
|
|
+ }
|
|
+
|
|
+ // Check if the chunk section above doesn't need obfuscation
|
|
+ if (chunkSectionIndex == maxChunkSectionIndex || !chunkPacketInfoAntiXray.isWritten(chunkSectionIndex + 1) || chunkPacketInfoAntiXray.getPredefinedObjects(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
|
|
+ ChunkSection aboveChunkSection;
|
|
+
|
|
+ if (chunkSectionIndex != 15 && (aboveChunkSection = chunkPacketInfoAntiXray.getChunk().getSections()[chunkSectionIndex + 1]) != Chunk.EMPTY_CHUNK_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 (!solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(aboveChunkSection.getType(x, 0, z))]) {
|
|
+ current[z][x] = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // There is nothing to read anymore
|
|
+ dataBitsReader.setBitsPerObject(0);
|
|
+ solid[0] = true;
|
|
+ obfuscateLayer(15, dataBitsReader, dataBitsWriter, solid, obfuscateTemp, predefinedBlockDataBitsTemp, 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
|
|
+ dataBitsReader.setBitsPerObject(chunkPacketInfoAntiXray.getBitsPerObject(chunkSectionIndex + 1));
|
|
+ dataBitsReader.setIndex(chunkPacketInfoAntiXray.getDataBitsIndex(chunkSectionIndex + 1));
|
|
+ solidTemp = readDataPalette(chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex + 1), solid, solidGlobal);
|
|
+ obfuscateTemp = readDataPalette(chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex + 1), obfuscate, obfuscateGlobal);
|
|
+ boolean[][] temp = current;
|
|
+ current = next;
|
|
+ next = nextNext;
|
|
+ nextNext = temp;
|
|
+ obfuscateLayer(15, dataBitsReader, dataBitsWriter, solidTemp, obfuscateTemp, predefinedBlockDataBitsTemp, current, next, nextNext, nearbyChunkSections, random);
|
|
+ }
|
|
+
|
|
+ dataBitsWriter.finish();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ chunkPacketInfoAntiXray.getPacketPlayOutMapChunk().setReady(true);
|
|
+ }
|
|
+
|
|
+ private void obfuscateLayer(int y, DataBitsReader dataBitsReader, DataBitsWriter dataBitsWriter, boolean[] solid, boolean[] obfuscate, int[] predefinedBlockDataBits, boolean[][] current, boolean[][] next, boolean[][] nextNext, ChunkSection[] nearbyChunkSections, IntSupplier random) {
|
|
+ // First block of first line
|
|
+ int dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[0][0] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[0][1] = true;
|
|
+ next[1][0] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[2] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[2].getType(0, y, 15))] || nearbyChunkSections[0] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[0].getType(15, y, 0))] || current[0][0]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[0][0] = true;
|
|
+ }
|
|
+
|
|
+ // First line
|
|
+ for (int x = 1; x < 15; x++) {
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[0][x] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[0][x - 1] = true;
|
|
+ next[0][x + 1] = true;
|
|
+ next[1][x] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[2] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[2].getType(x, y, 15))] || current[0][x]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[0][x] = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Last block of first line
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[0][15] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[0][14] = true;
|
|
+ next[1][15] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[2] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[2].getType(15, y, 15))] || nearbyChunkSections[1] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[1].getType(0, y, 0))] || current[0][15]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[0][15] = true;
|
|
+ }
|
|
+
|
|
+ // All inner lines
|
|
+ for (int z = 1; z < 15; z++) {
|
|
+ // First block
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[z][0] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[z][1] = true;
|
|
+ next[z - 1][0] = true;
|
|
+ next[z + 1][0] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[0] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[0].getType(15, y, z))] || current[z][0]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[z][0] = true;
|
|
+ }
|
|
+
|
|
+ // All inner blocks
|
|
+ for (int x = 1; x < 15; x++) {
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[z][x] = !solid[dataBits]) {
|
|
+ dataBitsWriter.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]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[z][x] = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Last block
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[z][15] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[z][14] = true;
|
|
+ next[z - 1][15] = true;
|
|
+ next[z + 1][15] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[1] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[1].getType(0, y, z))] || current[z][15]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[z][15] = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // First block of last line
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[15][0] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[15][1] = true;
|
|
+ next[14][0] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[3] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[3].getType(0, y, 0))] || nearbyChunkSections[0] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[0].getType(15, y, 15))] || current[15][0]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[15][0] = true;
|
|
+ }
|
|
+
|
|
+ // Last line
|
|
+ for (int x = 1; x < 15; x++) {
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[15][x] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[15][x - 1] = true;
|
|
+ next[15][x + 1] = true;
|
|
+ next[14][x] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[3] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[3].getType(x, y, 0))] || current[15][x]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[15][x] = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Last block of last line
|
|
+ dataBits = dataBitsReader.read();
|
|
+
|
|
+ if (nextNext[15][15] = !solid[dataBits]) {
|
|
+ dataBitsWriter.skip();
|
|
+ next[15][14] = true;
|
|
+ next[14][15] = true;
|
|
+ } else {
|
|
+ if (nearbyChunkSections[3] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[3].getType(15, y, 0))] || nearbyChunkSections[1] == Chunk.EMPTY_CHUNK_SECTION || !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(nearbyChunkSections[1].getType(0, y, 15))] || current[15][15]) {
|
|
+ dataBitsWriter.skip();
|
|
+ } else {
|
|
+ dataBitsWriter.write(predefinedBlockDataBits[random.getAsInt()]);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!obfuscate[dataBits]) {
|
|
+ next[15][15] = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private boolean[] readDataPalette(DataPalette<IBlockData> dataPalette, boolean[] temp, boolean[] global) {
|
|
+ if (dataPalette == ChunkSection.GLOBAL_PALETTE) {
|
|
+ return global;
|
|
+ }
|
|
+
|
|
+ IBlockData blockData;
|
|
+
|
|
+ for (int i = 0; (blockData = dataPalette.getObject(i)) != null; i++) {
|
|
+ temp[i] = global[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(blockData)];
|
|
+ }
|
|
+
|
|
+ return temp;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onBlockChange(World world, BlockPosition blockPosition, IBlockData newBlockData, IBlockData oldBlockData, int flag) {
|
|
+ if (oldBlockData != null && solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(oldBlockData)] && !solidGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(newBlockData)] && blockPosition.getY() <= maxBlockYUpdatePosition) {
|
|
+ updateNearbyBlocks(world, blockPosition);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void onPlayerLeftClickBlock(PlayerInteractManager playerInteractManager, BlockPosition blockPosition, EnumDirection enumDirection) {
|
|
+ if (blockPosition.getY() <= maxBlockYUpdatePosition) {
|
|
+ updateNearbyBlocks(playerInteractManager.world, blockPosition);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void updateNearbyBlocks(World world, BlockPosition blockPosition) {
|
|
+ if (updateRadius >= 2) {
|
|
+ BlockPosition temp = blockPosition.west();
|
|
+ updateBlock(world, temp);
|
|
+ updateBlock(world, temp.west());
|
|
+ updateBlock(world, temp.down());
|
|
+ updateBlock(world, temp.up());
|
|
+ updateBlock(world, temp.north());
|
|
+ updateBlock(world, temp.south());
|
|
+ updateBlock(world, temp = blockPosition.east());
|
|
+ updateBlock(world, temp.east());
|
|
+ updateBlock(world, temp.down());
|
|
+ updateBlock(world, temp.up());
|
|
+ updateBlock(world, temp.north());
|
|
+ updateBlock(world, temp.south());
|
|
+ updateBlock(world, temp = blockPosition.down());
|
|
+ updateBlock(world, temp.down());
|
|
+ updateBlock(world, temp.north());
|
|
+ updateBlock(world, temp.south());
|
|
+ updateBlock(world, temp = blockPosition.up());
|
|
+ updateBlock(world, temp.up());
|
|
+ updateBlock(world, temp.north());
|
|
+ updateBlock(world, temp.south());
|
|
+ updateBlock(world, temp = blockPosition.north());
|
|
+ updateBlock(world, temp.north());
|
|
+ updateBlock(world, temp = blockPosition.south());
|
|
+ updateBlock(world, temp.south());
|
|
+ } else if (updateRadius == 1) {
|
|
+ updateBlock(world, blockPosition.west());
|
|
+ updateBlock(world, blockPosition.east());
|
|
+ updateBlock(world, blockPosition.down());
|
|
+ updateBlock(world, blockPosition.up());
|
|
+ updateBlock(world, blockPosition.north());
|
|
+ updateBlock(world, blockPosition.south());
|
|
+ } else {
|
|
+ // Do nothing if updateRadius <= 0 (test mode)
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void updateBlock(World world, BlockPosition blockPosition) {
|
|
+ IBlockData blockData = world.getTypeIfLoaded(blockPosition);
|
|
+
|
|
+ if (blockData != null && obfuscateGlobal[ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(blockData)]) {
|
|
+ // world.notify(blockPosition, blockData, blockData, 3);
|
|
+ ((WorldServer)world).getChunkProvider().flagDirty(blockPosition); // We only need to re-send to client
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public enum EngineMode {
|
|
+
|
|
+ HIDE(1, "hide ores"),
|
|
+ OBFUSCATE(2, "obfuscate");
|
|
+
|
|
+ private final int id;
|
|
+ private final String description;
|
|
+
|
|
+ EngineMode(int id, String description) {
|
|
+ this.id = id;
|
|
+ this.description = description;
|
|
+ }
|
|
+
|
|
+ public static EngineMode getById(int id) {
|
|
+ for (EngineMode engineMode : values()) {
|
|
+ if (engineMode.id == id) {
|
|
+ return engineMode;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ public int getId() {
|
|
+ return id;
|
|
+ }
|
|
+
|
|
+ public String getDescription() {
|
|
+ return description;
|
|
+ }
|
|
+ }
|
|
+}
|
|
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..22c9adefc3e51e9e4b8d611a40d1497d2a16a8d2
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfo.java
|
|
@@ -0,0 +1,81 @@
|
|
+package com.destroystokyo.paper.antixray;
|
|
+
|
|
+import net.minecraft.network.protocol.game.PacketPlayOutMapChunk;
|
|
+import net.minecraft.world.level.chunk.Chunk;
|
|
+import net.minecraft.world.level.chunk.DataPalette;
|
|
+
|
|
+public class ChunkPacketInfo<T> {
|
|
+
|
|
+ private final PacketPlayOutMapChunk packetPlayOutMapChunk;
|
|
+ private final Chunk chunk;
|
|
+ private final int chunkSectionSelector;
|
|
+ private byte[] data;
|
|
+ private final int[] bitsPerObject = new int[16];
|
|
+ private final Object[] dataPalettes = new Object[16];
|
|
+ private final int[] dataBitsIndexes = new int[16];
|
|
+ private final Object[][] predefinedObjects = new Object[16][];
|
|
+
|
|
+ public ChunkPacketInfo(PacketPlayOutMapChunk packetPlayOutMapChunk, Chunk chunk, int chunkSectionSelector) {
|
|
+ this.packetPlayOutMapChunk = packetPlayOutMapChunk;
|
|
+ this.chunk = chunk;
|
|
+ this.chunkSectionSelector = chunkSectionSelector;
|
|
+ }
|
|
+
|
|
+ public PacketPlayOutMapChunk getPacketPlayOutMapChunk() {
|
|
+ return packetPlayOutMapChunk;
|
|
+ }
|
|
+
|
|
+ public Chunk getChunk() {
|
|
+ return chunk;
|
|
+ }
|
|
+
|
|
+ public int getChunkSectionSelector() {
|
|
+ return chunkSectionSelector;
|
|
+ }
|
|
+
|
|
+ public byte[] getData() {
|
|
+ return data;
|
|
+ }
|
|
+
|
|
+ public void setData(byte[] data) {
|
|
+ this.data = data;
|
|
+ }
|
|
+
|
|
+ public int getBitsPerObject(int chunkSectionIndex) {
|
|
+ return bitsPerObject[chunkSectionIndex];
|
|
+ }
|
|
+
|
|
+ public void setBitsPerObject(int chunkSectionIndex, int bitsPerObject) {
|
|
+ this.bitsPerObject[chunkSectionIndex] = bitsPerObject;
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public DataPalette<T> getDataPalette(int chunkSectionIndex) {
|
|
+ return (DataPalette<T>) dataPalettes[chunkSectionIndex];
|
|
+ }
|
|
+
|
|
+ public void setDataPalette(int chunkSectionIndex, DataPalette<T> dataPalette) {
|
|
+ dataPalettes[chunkSectionIndex] = dataPalette;
|
|
+ }
|
|
+
|
|
+ public int getDataBitsIndex(int chunkSectionIndex) {
|
|
+ return dataBitsIndexes[chunkSectionIndex];
|
|
+ }
|
|
+
|
|
+ public void setDataBitsIndex(int chunkSectionIndex, int dataBitsIndex) {
|
|
+ dataBitsIndexes[chunkSectionIndex] = dataBitsIndex;
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public T[] getPredefinedObjects(int chunkSectionIndex) {
|
|
+ return (T[]) predefinedObjects[chunkSectionIndex];
|
|
+ }
|
|
+
|
|
+ public void setPredefinedObjects(int chunkSectionIndex, T[] predefinedObjects) {
|
|
+ this.predefinedObjects[chunkSectionIndex] = predefinedObjects;
|
|
+ }
|
|
+
|
|
+ public boolean isWritten(int chunkSectionIndex) {
|
|
+ return bitsPerObject[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..4b64964e52b11bea4d2c0d0f64f55ad08d2189be
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketInfoAntiXray.java
|
|
@@ -0,0 +1,30 @@
|
|
+package com.destroystokyo.paper.antixray;
|
|
+
|
|
+import net.minecraft.network.protocol.game.PacketPlayOutMapChunk;
|
|
+import net.minecraft.world.level.block.state.IBlockData;
|
|
+import net.minecraft.world.level.chunk.Chunk;
|
|
+
|
|
+public final class ChunkPacketInfoAntiXray extends ChunkPacketInfo<IBlockData> implements Runnable {
|
|
+
|
|
+ private Chunk[] nearbyChunks;
|
|
+ private final ChunkPacketBlockControllerAntiXray chunkPacketBlockControllerAntiXray;
|
|
+
|
|
+ public ChunkPacketInfoAntiXray(PacketPlayOutMapChunk packetPlayOutMapChunk, Chunk chunk, int chunkSectionSelector,
|
|
+ ChunkPacketBlockControllerAntiXray chunkPacketBlockControllerAntiXray) {
|
|
+ super(packetPlayOutMapChunk, chunk, chunkSectionSelector);
|
|
+ this.chunkPacketBlockControllerAntiXray = chunkPacketBlockControllerAntiXray;
|
|
+ }
|
|
+
|
|
+ public Chunk[] getNearbyChunks() {
|
|
+ return nearbyChunks;
|
|
+ }
|
|
+
|
|
+ public void setNearbyChunks(Chunk... nearbyChunks) {
|
|
+ this.nearbyChunks = nearbyChunks;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ chunkPacketBlockControllerAntiXray.obfuscate(this);
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/antixray/DataBitsReader.java b/src/main/java/com/destroystokyo/paper/antixray/DataBitsReader.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..298ea423084dbcc1b61f991bcd82b8ae51bf0977
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/antixray/DataBitsReader.java
|
|
@@ -0,0 +1,51 @@
|
|
+package com.destroystokyo.paper.antixray;
|
|
+
|
|
+public final class DataBitsReader {
|
|
+
|
|
+ private byte[] dataBits;
|
|
+ private int bitsPerObject;
|
|
+ private int mask;
|
|
+ private int longInDataBitsIndex;
|
|
+ private int bitInLongIndex;
|
|
+ private long current;
|
|
+
|
|
+ public void setDataBits(byte[] dataBits) {
|
|
+ this.dataBits = dataBits;
|
|
+ }
|
|
+
|
|
+ public void setBitsPerObject(int bitsPerObject) {
|
|
+ this.bitsPerObject = bitsPerObject;
|
|
+ mask = (1 << bitsPerObject) - 1;
|
|
+ }
|
|
+
|
|
+ public void setIndex(int index) {
|
|
+ this.longInDataBitsIndex = index;
|
|
+ bitInLongIndex = 0;
|
|
+ init();
|
|
+ }
|
|
+
|
|
+ private void init() {
|
|
+ if (dataBits.length > longInDataBitsIndex + 7) {
|
|
+ current = ((((long) dataBits[longInDataBitsIndex]) << 56)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 1] & 0xff) << 48)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 2] & 0xff) << 40)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 3] & 0xff) << 32)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 4] & 0xff) << 24)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 5] & 0xff) << 16)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 6] & 0xff) << 8)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 7] & 0xff)));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public int read() {
|
|
+ if (bitInLongIndex + bitsPerObject > 64) {
|
|
+ bitInLongIndex = 0;
|
|
+ longInDataBitsIndex += 8;
|
|
+ init();
|
|
+ }
|
|
+
|
|
+ int value = (int) (current >>> bitInLongIndex) & mask;
|
|
+ bitInLongIndex += bitsPerObject;
|
|
+ return value;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/antixray/DataBitsWriter.java b/src/main/java/com/destroystokyo/paper/antixray/DataBitsWriter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..333763936897befda5bb6c077944d2667f922799
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/antixray/DataBitsWriter.java
|
|
@@ -0,0 +1,79 @@
|
|
+package com.destroystokyo.paper.antixray;
|
|
+
|
|
+public final class DataBitsWriter {
|
|
+
|
|
+ private byte[] dataBits;
|
|
+ private int bitsPerObject;
|
|
+ private long mask;
|
|
+ private int longInDataBitsIndex;
|
|
+ private int bitInLongIndex;
|
|
+ private long current;
|
|
+ private boolean dirty;
|
|
+
|
|
+ public void setDataBits(byte[] dataBits) {
|
|
+ this.dataBits = dataBits;
|
|
+ }
|
|
+
|
|
+ public void setBitsPerObject(int bitsPerObject) {
|
|
+ this.bitsPerObject = bitsPerObject;
|
|
+ mask = (1 << bitsPerObject) - 1;
|
|
+ }
|
|
+
|
|
+ public void setIndex(int index) {
|
|
+ this.longInDataBitsIndex = index;
|
|
+ bitInLongIndex = 0;
|
|
+ init();
|
|
+ }
|
|
+
|
|
+ private void init() {
|
|
+ if (dataBits.length > longInDataBitsIndex + 7) {
|
|
+ current = ((((long) dataBits[longInDataBitsIndex]) << 56)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 1] & 0xff) << 48)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 2] & 0xff) << 40)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 3] & 0xff) << 32)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 4] & 0xff) << 24)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 5] & 0xff) << 16)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 6] & 0xff) << 8)
|
|
+ | (((long) dataBits[longInDataBitsIndex + 7] & 0xff)));
|
|
+ }
|
|
+
|
|
+ dirty = false;
|
|
+ }
|
|
+
|
|
+ public void finish() {
|
|
+ if (dirty && dataBits.length > longInDataBitsIndex + 7) {
|
|
+ dataBits[longInDataBitsIndex] = (byte) (current >> 56 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 1] = (byte) (current >> 48 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 2] = (byte) (current >> 40 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 3] = (byte) (current >> 32 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 4] = (byte) (current >> 24 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 5] = (byte) (current >> 16 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 6] = (byte) (current >> 8 & 0xff);
|
|
+ dataBits[longInDataBitsIndex + 7] = (byte) (current & 0xff);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public void write(int value) {
|
|
+ if (bitInLongIndex + bitsPerObject > 64) {
|
|
+ finish();
|
|
+ bitInLongIndex = 0;
|
|
+ longInDataBitsIndex += 8;
|
|
+ init();
|
|
+ }
|
|
+
|
|
+ current = current & ~(mask << bitInLongIndex) | (value & mask) << bitInLongIndex;
|
|
+ dirty = true;
|
|
+ bitInLongIndex += bitsPerObject;
|
|
+ }
|
|
+
|
|
+ public void skip() {
|
|
+ bitInLongIndex += bitsPerObject;
|
|
+
|
|
+ if (bitInLongIndex > 64) {
|
|
+ finish();
|
|
+ bitInLongIndex = bitsPerObject;
|
|
+ longInDataBitsIndex += 8;
|
|
+ init();
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutMapChunk.java b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutMapChunk.java
|
|
index a7d10d124021f3427f23fcd533f885367b64515c..3047cf8c4ec1b664d6b790f18d2b1657e4b00435 100644
|
|
--- a/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutMapChunk.java
|
|
+++ b/src/main/java/net/minecraft/network/protocol/game/PacketPlayOutMapChunk.java
|
|
@@ -1,5 +1,6 @@
|
|
package net.minecraft.network.protocol.game;
|
|
|
|
+import com.destroystokyo.paper.antixray.ChunkPacketInfo; // Paper - Anti-Xray - Add chunk packet info
|
|
import com.google.common.collect.Lists;
|
|
import io.netty.buffer.ByteBuf;
|
|
import io.netty.buffer.Unpooled;
|
|
@@ -16,6 +17,7 @@ import net.minecraft.network.protocol.Packet;
|
|
import net.minecraft.world.level.ChunkCoordIntPair;
|
|
import net.minecraft.world.level.block.entity.TileEntity;
|
|
import net.minecraft.world.level.block.entity.TileEntitySkull;
|
|
+import net.minecraft.world.level.block.state.IBlockData;
|
|
import net.minecraft.world.level.chunk.BiomeStorage;
|
|
import net.minecraft.world.level.chunk.Chunk;
|
|
import net.minecraft.world.level.chunk.ChunkSection;
|
|
@@ -33,7 +35,13 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
|
private List<NBTTagCompound> g;
|
|
private boolean h;
|
|
|
|
- public PacketPlayOutMapChunk() {}
|
|
+ // Paper start - Async-Anti-Xray - Set the ready flag to true
|
|
+ private volatile boolean ready; // Paper - Async-Anti-Xray - Ready flag for the network manager
|
|
+ public PacketPlayOutMapChunk() {
|
|
+ this.ready = true;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
// Paper start
|
|
private final java.util.List<Packet> extraPackets = new java.util.ArrayList<>();
|
|
private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750);
|
|
@@ -43,7 +51,11 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
|
return extraPackets;
|
|
}
|
|
// Paper end
|
|
- public PacketPlayOutMapChunk(Chunk chunk, int i) {
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated public PacketPlayOutMapChunk(Chunk chunk, int i) { this(chunk, i, true); } // Notice for updates: Please make sure this constructor isn't used anywhere
|
|
+ public PacketPlayOutMapChunk(Chunk chunk, int i, boolean modifyBlocks) {
|
|
+ ChunkPacketInfo<IBlockData> chunkPacketInfo = modifyBlocks ? chunk.world.chunkPacketBlockController.getChunkPacketInfo(this, chunk, i) : null;
|
|
+ // Paper end
|
|
ChunkCoordIntPair chunkcoordintpair = chunk.getPos();
|
|
|
|
this.a = chunkcoordintpair.x;
|
|
@@ -66,7 +78,12 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
|
}
|
|
|
|
this.f = new byte[this.a(chunk, i)];
|
|
- this.c = this.a(new PacketDataSerializer(this.j()), chunk, i);
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setData(this.getData());
|
|
+ }
|
|
+ this.c = this.writeChunk(new PacketDataSerializer(this.j()), chunk, i, chunkPacketInfo);
|
|
+ // Paper end
|
|
this.g = Lists.newArrayList();
|
|
iterator = chunk.getTileEntities().entrySet().iterator();
|
|
int totalTileEntities = 0; // Paper
|
|
@@ -93,8 +110,19 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
|
this.g.add(nbttagcompound);
|
|
}
|
|
}
|
|
+ chunk.world.chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
|
+ }
|
|
|
|
+ // Paper start - Async-Anti-Xray - Getter and Setter for the ready flag
|
|
+ @Override
|
|
+ public boolean isReady() {
|
|
+ return this.ready;
|
|
+ }
|
|
+
|
|
+ public void setReady(boolean ready) {
|
|
+ this.ready = ready;
|
|
}
|
|
+ // Paper end
|
|
|
|
@Override
|
|
public void a(PacketDataSerializer packetdataserializer) throws IOException {
|
|
@@ -160,8 +188,12 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
|
return bytebuf;
|
|
}
|
|
|
|
- public int writeChunk(PacketDataSerializer packetDataSerializer, Chunk chunk, int chunkSectionSelector) { return this.a(packetDataSerializer, chunk, chunkSectionSelector); } // Paper - OBFHELPER
|
|
- public int a(PacketDataSerializer packetdataserializer, Chunk chunk, int i) {
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated public int writeChunk(PacketDataSerializer packetDataSerializer, Chunk chunk, int chunkSectionSelector) { return this.a(packetDataSerializer, chunk, chunkSectionSelector); } // OBFHELPER // Notice for updates: Please make sure this method isn't used anywhere
|
|
+ @Deprecated public int a(PacketDataSerializer packetdataserializer, Chunk chunk, int i) { return this.writeChunk(packetdataserializer, chunk, i, null); } // Notice for updates: Please make sure this method isn't used anywhere
|
|
+ public int writeChunk(PacketDataSerializer packetDataSerializer, Chunk chunk, int chunkSectionSelector, ChunkPacketInfo<IBlockData> chunkPacketInfo) { return this.a(packetDataSerializer, chunk, chunkSectionSelector, chunkPacketInfo); } // OBFHELPER
|
|
+ public int a(PacketDataSerializer packetdataserializer, Chunk chunk, int i, ChunkPacketInfo<IBlockData> chunkPacketInfo) {
|
|
+ // Paper end
|
|
int j = 0;
|
|
ChunkSection[] achunksection = chunk.getSections();
|
|
int k = 0;
|
|
@@ -171,7 +203,7 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
|
|
|
|
if (chunksection != Chunk.a && (!this.f() || !chunksection.c()) && (i & 1 << k) != 0) {
|
|
j |= 1 << k;
|
|
- chunksection.b(packetdataserializer);
|
|
+ chunksection.writeChunkSection(packetdataserializer, chunkPacketInfo); // Paper - Anti-Xray - Add chunk packet info
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
index ca05fe4ed0773b94035c63f8f8db6c034f0b92e2..5a11765c8a7d754ec86d829fa5e85d2809dd937e 100644
|
|
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
|
|
@@ -656,7 +656,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
}
|
|
|
|
this.g(chunkcoordintpair);
|
|
- return Either.left(new ProtoChunk(chunkcoordintpair, ChunkConverter.a));
|
|
+ return Either.left(new ProtoChunk(chunkcoordintpair, ChunkConverter.a, this.world)); // Paper - Anti-Xray - Add parameter
|
|
}, this.executor);
|
|
}
|
|
|
|
@@ -1404,9 +1404,10 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
|
|
}
|
|
|
|
+ private final void sendChunk(EntityPlayer entityplayer, Packet<?>[] apacket, Chunk chunk) { this.a(entityplayer, apacket, chunk); } // Paper - OBFHELPER
|
|
private void a(EntityPlayer entityplayer, Packet<?>[] apacket, Chunk chunk) {
|
|
if (apacket[0] == null) {
|
|
- apacket[0] = new PacketPlayOutMapChunk(chunk, 65535);
|
|
+ apacket[0] = new PacketPlayOutMapChunk(chunk, 65535, chunk.world.chunkPacketBlockController.shouldModify(entityplayer, chunk, 65535)); // Paper - Anti-Xray - Bypass
|
|
apacket[1] = new PacketPlayOutLightUpdate(chunk.getPos(), this.lightEngine, true);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/PlayerInteractManager.java b/src/main/java/net/minecraft/server/level/PlayerInteractManager.java
|
|
index d86b1e528b53db809ac993aa2f1d2799d4f1a574..fbd8a6985a261396789c87e4b687140bd49cea0d 100644
|
|
--- a/src/main/java/net/minecraft/server/level/PlayerInteractManager.java
|
|
+++ b/src/main/java/net/minecraft/server/level/PlayerInteractManager.java
|
|
@@ -309,6 +309,8 @@ public class PlayerInteractManager {
|
|
}
|
|
|
|
}
|
|
+
|
|
+ this.world.chunkPacketBlockController.onPlayerLeftClickBlock(this, blockposition, enumdirection); // Paper - Anti-Xray
|
|
}
|
|
|
|
public void a(BlockPosition blockposition, PacketPlayInBlockDig.EnumPlayerDigType packetplayinblockdig_enumplayerdigtype, String s) {
|
|
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
index d7fe6f00b352dad9e9f579f9af86cb8b90ef83ae..e2c0d30c5b25f9c44025f0619ba254c89402d9f9 100644
|
|
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
|
|
@@ -210,7 +210,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
|
|
|
// Add env and gen to constructor, WorldData -> WorldDataServer
|
|
public WorldServer(MinecraftServer minecraftserver, Executor executor, Convertable.ConversionSession convertable_conversionsession, IWorldDataServer iworlddataserver, ResourceKey<World> resourcekey, DimensionManager dimensionmanager, WorldLoadListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<MobSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
|
|
- super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env);
|
|
+ super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getMethodProfiler, false, flag, i, gen, env, executor); // Paper pass executor
|
|
this.pvpMode = minecraftserver.getPVP();
|
|
convertable = convertable_conversionsession;
|
|
uuid = WorldUUID.getUUID(convertable_conversionsession.folder.toFile());
|
|
diff --git a/src/main/java/net/minecraft/world/level/World.java b/src/main/java/net/minecraft/world/level/World.java
|
|
index 12ac3608736b45447afe6b0d35ead1441390be5e..15da3511a9e57c320f4cf409852bee07109095bc 100644
|
|
--- a/src/main/java/net/minecraft/world/level/World.java
|
|
+++ b/src/main/java/net/minecraft/world/level/World.java
|
|
@@ -2,6 +2,8 @@ package net.minecraft.world.level;
|
|
|
|
import co.aikar.timings.Timing;
|
|
import co.aikar.timings.Timings;
|
|
+import com.destroystokyo.paper.antixray.ChunkPacketBlockController; // Paper - Anti-Xray
|
|
+import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray; // Paper - Anti-Xray
|
|
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
|
import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.base.MoreObjects;
|
|
@@ -144,6 +146,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
|
|
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
|
|
|
public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
|
|
+ public final ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
|
|
|
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
|
|
public static BlockPosition lastPhysicsProblem; // Spigot
|
|
@@ -165,9 +168,10 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
|
|
return typeKey;
|
|
}
|
|
|
|
- protected World(WorldDataMutable worlddatamutable, ResourceKey<World> resourcekey, final DimensionManager dimensionmanager, Supplier<GameProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) {
|
|
+ protected World(WorldDataMutable worlddatamutable, ResourceKey<World> resourcekey, final DimensionManager dimensionmanager, Supplier<GameProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env, java.util.concurrent.Executor executor) { // Paper
|
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName()); // Spigot
|
|
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((net.minecraft.world.level.storage.WorldDataServer) worlddatamutable).getName(), this.spigotConfig); // Paper
|
|
+ this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
|
|
this.generator = gen;
|
|
this.world = new CraftWorld((WorldServer) this, gen, env);
|
|
this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit
|
|
@@ -433,6 +437,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
|
|
// CraftBukkit end
|
|
|
|
IBlockData iblockdata1 = chunk.setType(blockposition, iblockdata, (i & 64) != 0, (i & 1024) == 0); // CraftBukkit custom NO_PLACE flag
|
|
+ this.chunkPacketBlockController.onBlockChange(this, blockposition, iblockdata, iblockdata1, i); // 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/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
|
|
index 2690c44eaae193a259fe195c95e59d07d5e1cc5a..3fdce0e6fa34eb4b1eafc618068a3fb06abd5ec1 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
|
|
@@ -465,7 +465,7 @@ public class Chunk implements IChunkAccess {
|
|
return null;
|
|
}
|
|
|
|
- chunksection = new ChunkSection(j >> 4 << 4);
|
|
+ chunksection = new ChunkSection(j >> 4 << 4, this, this.world, true); // Paper - Anti-Xray - Add parameters
|
|
this.sections[j >> 4] = chunksection;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkEmpty.java b/src/main/java/net/minecraft/world/level/chunk/ChunkEmpty.java
|
|
index 89efd0b68b04457e1cd617dcc8bb1a6ea1c4717c..9fb8d20e9e1a8cc716c32a100b1d70e90f385eca 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkEmpty.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkEmpty.java
|
|
@@ -8,6 +8,7 @@ import net.minecraft.SystemUtils;
|
|
import net.minecraft.core.BlockPosition;
|
|
import net.minecraft.core.IRegistry;
|
|
import net.minecraft.data.worldgen.biome.BiomeRegistry;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.server.level.PlayerChunk;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.level.ChunkCoordIntPair;
|
|
@@ -28,7 +29,7 @@ public class ChunkEmpty extends Chunk {
|
|
});
|
|
|
|
public ChunkEmpty(World world, ChunkCoordIntPair chunkcoordintpair) {
|
|
- super(world, chunkcoordintpair, new BiomeStorage(world.r().b(IRegistry.ay), ChunkEmpty.b));
|
|
+ super(world, chunkcoordintpair, new BiomeStorage(MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay), ChunkEmpty.b)); // Paper - world isnt ready yet for anti xray use here, use server singleton for registry
|
|
}
|
|
|
|
// Paper start
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
|
|
index eea4a30428293eaf7afbe303a37adec60b44c2b4..0b4e346daaea91565fde2f789fafa8b431a7b042 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
|
|
@@ -1,9 +1,11 @@
|
|
package net.minecraft.world.level.chunk;
|
|
|
|
import java.util.function.Predicate;
|
|
+import com.destroystokyo.paper.antixray.ChunkPacketInfo; // Paper - Anti-Xray - Add chunk packet info
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.nbt.GameProfileSerializer;
|
|
import net.minecraft.network.PacketDataSerializer;
|
|
+import net.minecraft.world.level.World;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.state.IBlockData;
|
|
@@ -18,16 +20,22 @@ public class ChunkSection {
|
|
private short e;
|
|
final DataPaletteBlock<IBlockData> blockIds; // Paper - package-private
|
|
|
|
- public ChunkSection(int i) {
|
|
- this(i, (short) 0, (short) 0, (short) 0);
|
|
+ // Paper start - Anti-Xray - Add parameters
|
|
+ @Deprecated public ChunkSection(int i) { this(i, null, null, true); } // Notice for updates: Please make sure this constructor isn't used anywhere
|
|
+ public ChunkSection(int i, IChunkAccess chunk, World world, boolean initializeBlocks) {
|
|
+ this(i, (short) 0, (short) 0, (short) 0, chunk, world, initializeBlocks);
|
|
+ // Paper end
|
|
}
|
|
|
|
- public ChunkSection(int i, short short0, short short1, short short2) {
|
|
+ // Paper start - Anti-Xray - Add parameters
|
|
+ @Deprecated public ChunkSection(int i, short short0, short short1, short short2) { this(i, short0, short1, short2, null, null, true); } // Notice for updates: Please make sure this constructor isn't used anywhere
|
|
+ public ChunkSection(int i, short short0, short short1, short short2, IChunkAccess chunk, World world, boolean initializeBlocks) {
|
|
+ // Paper end
|
|
this.yPos = i;
|
|
this.nonEmptyBlockCount = short0;
|
|
this.tickingBlockCount = short1;
|
|
this.e = short2;
|
|
- this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData());
|
|
+ this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData(), world == null ? null : world.chunkPacketBlockController.getPredefinedBlockData(world, chunk, this, initializeBlocks), initializeBlocks); // Paper - Anti-Xray - Add predefined block data
|
|
}
|
|
|
|
public final IBlockData getType(int i, int j, int k) { // Paper
|
|
@@ -139,10 +147,14 @@ public class ChunkSection {
|
|
return this.blockIds;
|
|
}
|
|
|
|
- public void writeChunkSection(PacketDataSerializer packetDataSerializer) { this.b(packetDataSerializer); } // Paper - OBFHELPER
|
|
- public void b(PacketDataSerializer packetdataserializer) {
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated public final void writeChunkSection(PacketDataSerializer packetDataSerializer) { this.b(packetDataSerializer); } // OBFHELPER // Notice for updates: Please make sure this method isn't used anywhere
|
|
+ @Deprecated public final void b(PacketDataSerializer packetdataserializer) { this.writeChunkSection(packetdataserializer, null); } // Notice for updates: Please make sure this method isn't used anywhere
|
|
+ public final void writeChunkSection(PacketDataSerializer packetDataSerializer, ChunkPacketInfo<IBlockData> chunkPacketInfo) { this.b(packetDataSerializer, chunkPacketInfo); } // OBFHELPER
|
|
+ public void b(PacketDataSerializer packetdataserializer, ChunkPacketInfo<IBlockData> chunkPacketInfo) {
|
|
+ // Paper end
|
|
packetdataserializer.writeShort(this.nonEmptyBlockCount);
|
|
- this.blockIds.b(packetdataserializer);
|
|
+ this.blockIds.writeDataPaletteBlock(packetdataserializer, chunkPacketInfo, this.yPos >> 4); // Paper - Anti-Xray - Add chunk packet info
|
|
}
|
|
|
|
public int j() {
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/DataPaletteBlock.java b/src/main/java/net/minecraft/world/level/chunk/DataPaletteBlock.java
|
|
index cc0c5995dc3840ce66ea849849f7c37555d3b5e6..68d53a51acc9790b9cda20ec4d2ec6edd1baac1a 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/DataPaletteBlock.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/DataPaletteBlock.java
|
|
@@ -1,6 +1,7 @@
|
|
package net.minecraft.world.level.chunk;
|
|
|
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|
+import com.destroystokyo.paper.antixray.ChunkPacketInfo; // Paper - Anti-Xray - Add chunk packet info
|
|
import java.util.Arrays;
|
|
import java.util.Objects;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
@@ -27,6 +28,7 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
|
|
private final Function<NBTTagCompound, T> e;
|
|
private final Function<T, NBTTagCompound> f;
|
|
private final T g;
|
|
+ private final T[] predefinedObjects; // Paper - Anti-Xray - Add predefined objects
|
|
protected DataBits a; public final DataBits getDataBits() { return this.a; } // Paper - OBFHELPER
|
|
private DataPalette<T> h; private DataPalette<T> getDataPalette() { return this.h; } // Paper - OBFHELPER
|
|
private int i; private int getBitsPerObject() { return this.i; } // Paper - OBFHELPER
|
|
@@ -51,14 +53,47 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
|
|
//this.j.unlock(); // Paper - disable this
|
|
}
|
|
|
|
- public DataPaletteBlock(DataPalette<T> datapalette, RegistryBlockID<T> registryblockid, Function<NBTTagCompound, T> function, Function<T, NBTTagCompound> function1, T t0) {
|
|
+ // Paper start - Anti-Xray - Add predefined objects
|
|
+ @Deprecated public DataPaletteBlock(DataPalette<T> datapalette, RegistryBlockID<T> registryblockid, Function<NBTTagCompound, T> function, Function<T, NBTTagCompound> function1, T t0) { this(datapalette, registryblockid, function, function1, t0, null, true); } // Notice for updates: Please make sure this constructor isn't used anywhere
|
|
+ public DataPaletteBlock(DataPalette<T> datapalette, RegistryBlockID<T> registryblockid, Function<NBTTagCompound, T> function, Function<T, NBTTagCompound> function1, T t0, T[] predefinedObjects, boolean initialize) {
|
|
+ // Paper end
|
|
this.b = datapalette;
|
|
this.d = registryblockid;
|
|
this.e = function;
|
|
this.f = function1;
|
|
this.g = t0;
|
|
- this.b(4);
|
|
+ // Paper start - Anti-Xray - Add predefined objects
|
|
+ this.predefinedObjects = predefinedObjects;
|
|
+
|
|
+ if (initialize) {
|
|
+ if (predefinedObjects == null) {
|
|
+ // Default
|
|
+ this.initialize(4);
|
|
+ } else {
|
|
+ // MathHelper.d() is trailingBits(roundCeilPow2(n)), alternatively; (int)ceil(log2(n)); however it's trash, use numberOfLeadingZeros instead
|
|
+ // Count the bits of the maximum array index to initialize a data palette with enough space from the beginning
|
|
+ // The length of the array is used because air is also added to the data palette from the beginning
|
|
+ // Start with at least 4
|
|
+ int maxIndex = predefinedObjects.length >> 4;
|
|
+ int bitCount = (32 - Integer.numberOfLeadingZeros(Math.max(16, maxIndex) - 1));
|
|
+
|
|
+ // Initialize with at least 15 free indixes
|
|
+ this.initialize((1 << bitCount) - predefinedObjects.length < 16 ? bitCount + 1 : bitCount);
|
|
+ this.addPredefinedObjects();
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+ }
|
|
+
|
|
+ // Paper start - Anti-Xray - Add predefined objects
|
|
+ private void addPredefinedObjects() {
|
|
+ if (this.predefinedObjects != null && this.getDataPalette() != this.getDataPaletteGlobal()) {
|
|
+ for (int i = 0; i < this.predefinedObjects.length; i++) {
|
|
+ this.getDataPalette().getOrCreateIdFor(this.predefinedObjects[i]);
|
|
+ }
|
|
+ }
|
|
}
|
|
+ // Paper end
|
|
|
|
private static int b(int i, int j, int k) {
|
|
return j << 8 | k << 4 | i;
|
|
@@ -93,6 +128,7 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
|
|
|
|
int j;
|
|
|
|
+ this.addPredefinedObjects(); // Paper - Anti-Xray - Add predefined objects
|
|
for (j = 0; j < databits.b(); ++j) {
|
|
T t1 = datapalette.a(databits.a(j));
|
|
|
|
@@ -142,24 +178,38 @@ public class DataPaletteBlock<T> implements DataPaletteExpandable<T> {
|
|
return t0 == null ? this.g : t0;
|
|
}
|
|
|
|
- public void writeDataPaletteBlock(PacketDataSerializer packetDataSerializer) { this.b(packetDataSerializer); } // Paper - OBFHELPER
|
|
- public synchronized void b(PacketDataSerializer packetdataserializer) { // Paper - synchronize
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ @Deprecated public void writeDataPaletteBlock(PacketDataSerializer packetDataSerializer) { this.b(packetDataSerializer); } // OBFHELPER // Notice for updates: Please make sure this method isn't used anywhere
|
|
+ @Deprecated public void b(PacketDataSerializer packetdataserializer) { this.writeDataPaletteBlock(packetdataserializer, null, 0); } // Notice for updates: Please make sure this method isn't used anywhere
|
|
+ public void writeDataPaletteBlock(PacketDataSerializer packetDataSerializer, ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { this.b(packetDataSerializer, chunkPacketInfo, chunkSectionIndex); } // OBFHELPER
|
|
+ public synchronized void b(PacketDataSerializer packetdataserializer, ChunkPacketInfo<T> chunkPacketInfo, int chunkSectionIndex) { // Paper - synchronize
|
|
+ // Paper end
|
|
this.a();
|
|
packetdataserializer.writeByte(this.i);
|
|
this.h.b(packetdataserializer);
|
|
+ // Paper start - Anti-Xray - Add chunk packet info
|
|
+ if (chunkPacketInfo != null) {
|
|
+ chunkPacketInfo.setBitsPerObject(chunkSectionIndex, this.getBitsPerObject());
|
|
+ chunkPacketInfo.setDataPalette(chunkSectionIndex, this.getDataPalette());
|
|
+ chunkPacketInfo.setDataBitsIndex(chunkSectionIndex, packetdataserializer.writerIndex() + PacketDataSerializer.countBytes(this.getDataBits().getDataBits().length));
|
|
+ chunkPacketInfo.setPredefinedObjects(chunkSectionIndex, this.predefinedObjects);
|
|
+ }
|
|
+ // Paper end
|
|
packetdataserializer.a(this.a.a());
|
|
this.b();
|
|
}
|
|
|
|
public synchronized void a(NBTTagList nbttaglist, long[] along) { // Paper - synchronize
|
|
this.a();
|
|
- int i = Math.max(4, MathHelper.e(nbttaglist.size()));
|
|
+ // Paper - Anti-Xray - TODO: Should this.predefinedObjects.length just be added here (faster) or should the contents be compared to calculate the size (less RAM)?
|
|
+ int i = Math.max(4, MathHelper.e(nbttaglist.size() + (this.predefinedObjects == null ? 0 : this.predefinedObjects.length))); // Paper - Anti-Xray - Calculate the size with predefined objects
|
|
|
|
- if (i != this.i) {
|
|
+ if (true || i != this.i) { // Paper - Anti-Xray - Not initialized yet
|
|
this.b(i);
|
|
}
|
|
|
|
this.h.a(nbttaglist);
|
|
+ this.addPredefinedObjects(); // Paper - Anti-Xray - Add predefined objects
|
|
int j = along.length * 64 / 4096;
|
|
|
|
if (this.h == this.b) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
|
index 9eeb99a21a6ed7f71ff64cf4cfdff646d31abbcf..9b308a10554b037ede0c455fbd3e906021218ddc 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
|
|
@@ -64,16 +64,24 @@ public class ProtoChunk implements IChunkAccess {
|
|
private long s;
|
|
private final Map<WorldGenStage.Features, BitSet> t;
|
|
private volatile boolean u;
|
|
+ private final World world; // Paper - Anti-Xray - Add world
|
|
|
|
- public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter) {
|
|
+ // Paper start - Anti-Xray - Add world
|
|
+ @Deprecated public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter) { this(chunkcoordintpair, chunkconverter, null); } // Notice for updates: Please make sure this constructor isn't used anywhere
|
|
+ public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter, World world) {
|
|
+ // Paper end
|
|
this(chunkcoordintpair, chunkconverter, (ChunkSection[]) null, new ProtoChunkTickList<>((block) -> {
|
|
return block == null || block.getBlockData().isAir();
|
|
}, chunkcoordintpair), new ProtoChunkTickList<>((fluidtype) -> {
|
|
return fluidtype == null || fluidtype == FluidTypes.EMPTY;
|
|
- }, chunkcoordintpair));
|
|
+ }, chunkcoordintpair), world); // Paper - Anti-Xray - Add world
|
|
}
|
|
|
|
- public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter, @Nullable ChunkSection[] achunksection, ProtoChunkTickList<Block> protochunkticklist, ProtoChunkTickList<FluidType> protochunkticklist1) {
|
|
+ // Paper start - Anti-Xray - Add world
|
|
+ @Deprecated public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter, @Nullable ChunkSection[] achunksection, ProtoChunkTickList<Block> protochunkticklist, ProtoChunkTickList<FluidType> protochunkticklist1) { this(chunkcoordintpair, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, null); } // Notice for updates: Please make sure this constructor isn't used anywhere
|
|
+ public ProtoChunk(ChunkCoordIntPair chunkcoordintpair, ChunkConverter chunkconverter, @Nullable ChunkSection[] achunksection, ProtoChunkTickList<Block> protochunkticklist, ProtoChunkTickList<FluidType> protochunkticklist1, World world) {
|
|
+ this.world = world;
|
|
+ // Paper end
|
|
this.f = Maps.newEnumMap(HeightMap.Type.class);
|
|
this.g = ChunkStatus.EMPTY;
|
|
this.h = Maps.newHashMap();
|
|
@@ -228,7 +236,7 @@ public class ProtoChunk implements IChunkAccess {
|
|
|
|
public ChunkSection a(int i) {
|
|
if (this.j[i] == Chunk.a) {
|
|
- this.j[i] = new ChunkSection(i << 4);
|
|
+ this.j[i] = new ChunkSection(i << 4, this, this.world, true); // Paper - Anti-Xray - Add parameters
|
|
}
|
|
|
|
return this.j[i];
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunkExtension.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunkExtension.java
|
|
index 9351e6ba541d440c485b6e4a3209170c5756e31e..7a82d43d51d80a3054e0871bf4b9aa7635920efc 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunkExtension.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunkExtension.java
|
|
@@ -27,7 +27,7 @@ public class ProtoChunkExtension extends ProtoChunk {
|
|
private final Chunk a;
|
|
|
|
public ProtoChunkExtension(Chunk chunk) {
|
|
- super(chunk.getPos(), ChunkConverter.a);
|
|
+ super(chunk.getPos(), ChunkConverter.a, chunk.world); // Paper - Anti-Xray - Add parameter
|
|
this.a = chunk;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java
|
|
index 98bc26c7ae01884eb53766e72fc7cbabbf065e6e..c652897aae99c48c6cc020b5d64f6a8b02beecb5 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkRegionLoader.java
|
|
@@ -101,7 +101,7 @@ public class ChunkRegionLoader {
|
|
byte b0 = nbttagcompound2.getByte("Y");
|
|
|
|
if (nbttagcompound2.hasKeyOfType("Palette", 9) && nbttagcompound2.hasKeyOfType("BlockStates", 12)) {
|
|
- ChunkSection chunksection = new ChunkSection(b0 << 4);
|
|
+ ChunkSection chunksection = new ChunkSection(b0 << 4, null, worldserver, false); // Paper - Anti-Xray - Add parameters
|
|
|
|
chunksection.getBlocks().a(nbttagcompound2.getList("Palette", 10), nbttagcompound2.getLongArray("BlockStates"));
|
|
chunksection.recalcBlockCounts();
|
|
@@ -165,7 +165,7 @@ public class ChunkRegionLoader {
|
|
// CraftBukkit end
|
|
});
|
|
} else {
|
|
- ProtoChunk protochunk = new ProtoChunk(chunkcoordintpair, chunkconverter, achunksection, protochunkticklist, protochunkticklist1);
|
|
+ ProtoChunk protochunk = new ProtoChunk(chunkcoordintpair, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, worldserver); // Paper - Anti-Xray - Add parameter
|
|
|
|
protochunk.a(biomestorage);
|
|
object = protochunk;
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
|
index a8e94f69faec93661dc6ae2efeec44b8bfd2e965..c36f55f178166eb099cc5c64784be5a9f4750199 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
|
@@ -44,7 +44,7 @@ public class CraftChunk implements Chunk {
|
|
private final WorldServer worldServer;
|
|
private final int x;
|
|
private final int z;
|
|
- private static final DataPaletteBlock<IBlockData> emptyBlockIDs = new ChunkSection(0).getBlocks();
|
|
+ private static final DataPaletteBlock<IBlockData> emptyBlockIDs = new ChunkSection(0, null, null, true).getBlocks(); // Paper - Anti-Xray - Add parameters
|
|
private static final byte[] emptyLight = new byte[2048];
|
|
|
|
public CraftChunk(net.minecraft.world.level.chunk.Chunk chunk) {
|
|
@@ -288,7 +288,7 @@ public class CraftChunk implements Chunk {
|
|
NBTTagCompound data = new NBTTagCompound();
|
|
cs[i].getBlocks().a(data, "Palette", "BlockStates");
|
|
|
|
- DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, net.minecraft.world.level.block.Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData()); // TODO: snapshot whole ChunkSection
|
|
+ DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, net.minecraft.world.level.block.Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData(), null, false); // TODO: snapshot whole ChunkSection // Paper - Anti-Xray - Add no predefined block data and don't initialize because it's done in the line below internally
|
|
blockids.a(data.getList("Palette", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray("BlockStates"));
|
|
|
|
sectionBlockIDs[i] = blockids;
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java
|
|
index 3d15915275331cb767750c24c89b4b43d43033ef..afca0038bb74ac53f07a25729a3c1542e244c6fd 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftChunkData.java
|
|
@@ -21,9 +21,11 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
|
|
private final int maxHeight;
|
|
private final ChunkSection[] sections;
|
|
private Set<BlockPosition> tiles;
|
|
+ private World world; // Paper - Anti-Xray - Add world
|
|
|
|
public CraftChunkData(World world) {
|
|
this(world.getMaxHeight());
|
|
+ this.world = world; // Paper - Anti-Xray - Add world
|
|
}
|
|
|
|
/* pp for tests */ CraftChunkData(int maxHeight) {
|
|
@@ -157,7 +159,7 @@ public final class CraftChunkData implements ChunkGenerator.ChunkData {
|
|
private ChunkSection getChunkSection(int y, boolean create) {
|
|
ChunkSection section = sections[y >> 4];
|
|
if (create && section == null) {
|
|
- sections[y >> 4] = section = new ChunkSection(y >> 4 << 4);
|
|
+ sections[y >> 4] = section = new ChunkSection(y >> 4 << 4, null, world instanceof org.bukkit.craftbukkit.CraftWorld ? ((org.bukkit.craftbukkit.CraftWorld) world).getHandle() : null, true); // Paper - Anti-Xray - Add parameters
|
|
}
|
|
return section;
|
|
}
|