From 83f377be8bcde04df5a78d0bcbd62320542f9da3 Mon Sep 17 00:00:00 2001 From: stonar96 Date: Tue, 24 Nov 2020 17:59:04 +0100 Subject: [PATCH] Preserve order and allow multiple equal blocks in hidden-blocks of Anti-Xray (#4072) * Preserve order of hidden-blocks in Anti-Xray This small change allows to specify and predict the order in which Anti-Xray uses the hidden-blocks in engine-mode 2. The order is preserved as specified in the hidden-blocks list. This can be useful, for example, when adding air to the hidden-blocks to predict which fake ores should be exposed to fake air. * Allow to add equal blocks multiple times to hidden-blocks This adds the ability to add equal blocks multiple times to the hidden-blocks of Anti-Xray in engine-mode 2. Thus it is possible to give certain blocks different priorities in Anti-Xray. For example if air and diamond_ore are added twice, the obfuscated chunk will contain twice as many air and diamond_ore blocks as other blocks in the list. --- Spigot-Server-Patches/0362-Anti-Xray.patch | 34 ++++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Spigot-Server-Patches/0362-Anti-Xray.patch b/Spigot-Server-Patches/0362-Anti-Xray.patch index 5c9e80b122..c01e30ee09 100644 --- a/Spigot-Server-Patches/0362-Anti-Xray.patch +++ b/Spigot-Server-Patches/0362-Anti-Xray.patch @@ -100,14 +100,15 @@ index 0000000000000000000000000000000000000000..df7e4183d8842f5be8ae9d0698f8fa90 +} 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..b879f1796912bb8467202e946ccf0c9270d1589d +index 0000000000000000000000000000000000000000..ac2dd0841dc849c3ceabb5ea899594ae73fb52fc --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/antixray/ChunkPacketBlockControllerAntiXray.java -@@ -0,0 +1,605 @@ +@@ -0,0 +1,615 @@ +package com.destroystokyo.paper.antixray; + +import java.util.ArrayList; -+import java.util.HashSet; ++import java.util.LinkedHashSet; ++import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executor; @@ -127,6 +128,7 @@ index 0000000000000000000000000000000000000000..b879f1796912bb8467202e946ccf0c92 + private final int maxChunkSectionIndex; + private final int updateRadius; + private final IBlockData[] predefinedBlockData; ++ private final IBlockData[] predefinedBlockDataFull; + private final IBlockData[] predefinedBlockDataStone; + private final IBlockData[] predefinedBlockDataNetherrack; + private final IBlockData[] predefinedBlockDataEndStone; @@ -152,6 +154,7 @@ index 0000000000000000000000000000000000000000..b879f1796912bb8467202e946ccf0c92 + 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()}; @@ -161,25 +164,30 @@ index 0000000000000000000000000000000000000000..b879f1796912bb8467202e946ccf0c92 + predefinedBlockDataBitsEndStoneGlobal = new int[] {ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(Blocks.END_STONE.getBlockData())}; + } else { + toObfuscate = new ArrayList<>(paperWorldConfig.replacementBlocks); -+ Set predefinedBlockDataSet = new HashSet(); ++ List predefinedBlockDataList = new LinkedList(); + + for (String id : paperWorldConfig.hiddenBlocks) { + Block block = IRegistry.BLOCK.getOptional(new MinecraftKey(id)).orElse(null); + + if (block != null && !block.isTileEntity()) { + toObfuscate.add(id); -+ predefinedBlockDataSet.add(block.getBlockData()); ++ predefinedBlockDataList.add(block.getBlockData()); + } + } + ++ // The doc of the LinkedHashSet(Collection 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 predefinedBlockDataSet = new LinkedHashSet(); ++ // Therefore addAll(Collection 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[predefinedBlockData.length]; ++ predefinedBlockDataBitsGlobal = new int[predefinedBlockDataFull.length]; + -+ for (int i = 0; i < predefinedBlockData.length; i++) { -+ predefinedBlockDataBitsGlobal[i] = ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(predefinedBlockData[i]); ++ for (int i = 0; i < predefinedBlockDataFull.length; i++) { ++ predefinedBlockDataBitsGlobal[i] = ChunkSection.GLOBAL_PALETTE.getOrCreateIdFor(predefinedBlockDataFull[i]); + } + + predefinedBlockDataBitsStoneGlobal = null; @@ -213,8 +221,8 @@ index 0000000000000000000000000000000000000000..b879f1796912bb8467202e946ccf0c92 + this.maxBlockYUpdatePosition = (maxChunkSectionIndex + 1) * 16 + updateRadius - 1; + } + -+ private int getPredefinedBlockDataLength() { -+ return engineMode == EngineMode.HIDE ? 1 : predefinedBlockData.length; ++ private int getPredefinedBlockDataFullLength() { ++ return engineMode == EngineMode.HIDE ? 1 : predefinedBlockDataFull.length; + } + + @Override @@ -272,7 +280,7 @@ index 0000000000000000000000000000000000000000..b879f1796912bb8467202e946ccf0c92 + + // 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 predefinedBlockDataBits = ThreadLocal.withInitial(() -> new int[getPredefinedBlockDataLength()]); ++ private final ThreadLocal predefinedBlockDataBits = ThreadLocal.withInitial(() -> new int[getPredefinedBlockDataFullLength()]); + private static final ThreadLocal solid = ThreadLocal.withInitial(() -> new boolean[Block.REGISTRY_ID.size()]); + private static final ThreadLocal obfuscate = ThreadLocal.withInitial(() -> new boolean[Block.REGISTRY_ID.size()]); + // These boolean arrays represent chunk layers, true means don't obfuscate, false means obfuscate @@ -322,10 +330,12 @@ index 0000000000000000000000000000000000000000..b879f1796912bb8467202e946ccf0c92 + 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(chunkPacketInfoAntiXray.getPredefinedObjects(chunkSectionIndex)[i]); ++ predefinedBlockDataBitsTemp[i] = chunkPacketInfoAntiXray.getDataPalette(chunkSectionIndex).getOrCreateIdFor(predefinedBlockDataFull[i]); + } + } +