From 9ef96155077f5830f6f2e3ea3605a6795438418f Mon Sep 17 00:00:00 2001 From: stonar96 Date: Thu, 2 Feb 2023 15:35:24 +0100 Subject: [PATCH] Add custom per block replacement diff --git a/RayTraceAntiXray/src/main/java/com/vanillage/raytraceantixray/antixray/ChunkPacketBlockControllerAntiXray.java b/RayTraceAntiXray/src/main/java/com/vanillage/raytraceantixray/antixray/ChunkPacketBlockControllerAntiXray.java index b3cd0ff..bc7d9f1 100644 --- a/RayTraceAntiXray/src/main/java/com/vanillage/raytraceantixray/antixray/ChunkPacketBlockControllerAntiXray.java +++ b/RayTraceAntiXray/src/main/java/com/vanillage/raytraceantixray/antixray/ChunkPacketBlockControllerAntiXray.java @@ -58,8 +58,8 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo private final int[] presetBlockStateBitsNetherrackGlobal; private final int[] presetBlockStateBitsEndStoneGlobal; public final boolean[] solidGlobal = new boolean[Block.BLOCK_STATE_REGISTRY.size()]; - private final boolean[] obfuscateGlobal = new boolean[Block.BLOCK_STATE_REGISTRY.size()]; - private final boolean[] traceGlobal; + private final int[] obfuscateGlobal = new int[Block.BLOCK_STATE_REGISTRY.size()]; + private final int[] traceGlobal; private final LevelChunkSection[] emptyNearbyChunkSections = {EMPTY_SECTION, EMPTY_SECTION, EMPTY_SECTION, EMPTY_SECTION}; public final boolean rayTraceThirdPerson; public final double rayTraceDistance; @@ -76,9 +76,9 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo this.rayTraceThirdPerson = rayTraceThirdPerson; this.rayTraceDistance = rayTraceDistance; this.maxRayTraceBlockCountPerChunk = maxRayTraceBlockCountPerChunk; - List toObfuscate; + List toObfuscate = paperWorldConfig.hiddenBlocks; - if (engineMode == EngineMode.HIDE) { + /*if (engineMode == EngineMode.HIDE) { toObfuscate = paperWorldConfig.hiddenBlocks; presetBlockStates = null; presetBlockStatesFull = null; @@ -124,16 +124,57 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo presetBlockStateBitsDeepslateGlobal = null; presetBlockStateBitsNetherrackGlobal = null; presetBlockStateBitsEndStoneGlobal = null; + }*/ + + List presetBlockStateList = new LinkedList<>(); + BlockState defaultBlockState; + + switch (level.getWorld().getEnvironment()) { + case NETHER: + defaultBlockState = Blocks.NETHERRACK.defaultBlockState(); + break; + case THE_END: + defaultBlockState = Blocks.END_STONE.defaultBlockState(); + break; + default: + defaultBlockState = Blocks.STONE.defaultBlockState(); } + // -1 means false (don't obfuscate). + Arrays.fill(obfuscateGlobal, -1); + for (String id : toObfuscate) { - Block block = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(id)).orElse(null); + String fromToIdSeparator = "->"; + int fromToIdSeparatorIndex = id.lastIndexOf(fromToIdSeparator); + String fromId = fromToIdSeparatorIndex >= 0 ? id.substring(0, fromToIdSeparatorIndex) : id; + Block block = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(fromId)).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.defaultBlockState().isAir()) { + BlockState toBlockState = null; + + if (fromToIdSeparatorIndex >= 0) { + Block toBlock = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(id.substring(fromToIdSeparatorIndex + fromToIdSeparator.length()))).orElse(null); + + if (toBlock != null && !(toBlock instanceof EntityBlock)) { + toBlockState = toBlock.defaultBlockState(); + } + } + + if (toBlockState == null) { + toBlockState = defaultBlockState; + } + + int presetBlockStateListIndex = presetBlockStateList.indexOf(toBlockState); + + if (presetBlockStateListIndex < 0) { + presetBlockStateListIndex = presetBlockStateList.size(); + presetBlockStateList.add(toBlockState); + } + // Replace all block states of a specified block for (BlockState blockState : block.getStateDefinition().getPossibleStates()) { - obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = true; + obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = presetBlockStateListIndex; } } } @@ -141,22 +182,69 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (toTrace == null) { traceGlobal = obfuscateGlobal; } else { - traceGlobal = new boolean[Block.BLOCK_STATE_REGISTRY.size()]; + traceGlobal = new int[Block.BLOCK_STATE_REGISTRY.size()]; + // -1 means false (don't obfuscate). + Arrays.fill(traceGlobal, -1); for (String id : toTrace) { - Block block = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(id)).orElse(null); + String fromToIdSeparator = "->"; + int fromToIdSeparatorIndex = id.lastIndexOf(fromToIdSeparator); + String fromId = fromToIdSeparatorIndex >= 0 ? id.substring(0, fromToIdSeparatorIndex) : id; + Block block = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(fromId)).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.defaultBlockState().isAir()) { + BlockState toBlockState = null; + + if (fromToIdSeparatorIndex >= 0) { + Block toBlock = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(id.substring(fromToIdSeparatorIndex + fromToIdSeparator.length()))).orElse(null); + + if (toBlock != null && !(toBlock instanceof EntityBlock)) { + toBlockState = toBlock.defaultBlockState(); + } + } + + if (toBlockState == null) { + toBlockState = defaultBlockState; + } + + int presetBlockStateListIndex = presetBlockStateList.indexOf(toBlockState); + + if (presetBlockStateListIndex < 0) { + presetBlockStateListIndex = presetBlockStateList.size(); + presetBlockStateList.add(toBlockState); + } + // Replace all block states of a specified block for (BlockState blockState : block.getStateDefinition().getPossibleStates()) { - traceGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = true; - obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = true; + traceGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = presetBlockStateListIndex; + obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] = presetBlockStateListIndex; } } } } + if (presetBlockStateList.isEmpty()) { + presetBlockStateList.add(defaultBlockState); + } + + presetBlockStates = presetBlockStateList.toArray(new BlockState[0]); + presetBlockStatesFull = presetBlockStates; + presetBlockStatesStone = null; + presetBlockStatesDeepslate = null; + 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; + presetBlockStateBitsDeepslateGlobal = null; + presetBlockStateBitsNetherrackGlobal = null; + presetBlockStateBitsEndStoneGlobal = null; + EmptyLevelChunk emptyChunk = new EmptyLevelChunk(level, new ChunkPos(0, 0), MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(Biomes.PLAINS)); BlockPos zeroPos = new BlockPos(0, 0, 0); @@ -175,14 +263,14 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } private int getPresetBlockStatesFullLength() { - return engineMode == EngineMode.HIDE ? 1 : presetBlockStatesFull.length; + return presetBlockStatesFull.length; } @Override public BlockState[] getPresetBlockStates(Level level, ChunkPos chunkPos, int bottomBlockY) { // Return the block states to be added to the paletted containers so that they can be used for obfuscation if (bottomBlockY < maxBlockHeight) { - if (engineMode == EngineMode.HIDE) { + /*if (engineMode == EngineMode.HIDE) { switch (level.getWorld().getEnvironment()) { case NETHER: return presetBlockStatesNetherrack; @@ -191,7 +279,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo default: return bottomBlockY < 0 ? presetBlockStatesDeepslate : presetBlockStatesStone; } - } + }*/ return presetBlockStates; } @@ -235,22 +323,24 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo // If an ExecutorService with multiple threads is used, ThreadLocal must be used here private final ThreadLocal presetBlockStateBits = ThreadLocal.withInitial(() -> new int[getPresetBlockStatesFullLength()]); private static final ThreadLocal SOLID = ThreadLocal.withInitial(() -> new boolean[Block.BLOCK_STATE_REGISTRY.size()]); - private static final ThreadLocal OBFUSCATE = ThreadLocal.withInitial(() -> new boolean[Block.BLOCK_STATE_REGISTRY.size()]); - private static final ThreadLocal TRACE = ThreadLocal.withInitial(() -> new boolean[Block.BLOCK_STATE_REGISTRY.size()]); + private static final ThreadLocal OBFUSCATE = ThreadLocal.withInitial(() -> new int[Block.BLOCK_STATE_REGISTRY.size()]); + private static final ThreadLocal TRACE = ThreadLocal.withInitial(() -> new int[Block.BLOCK_STATE_REGISTRY.size()]); // These boolean arrays represent chunk layers, true means don't obfuscate, false means obfuscate private static final ThreadLocal CURRENT = ThreadLocal.withInitial(() -> new boolean[16][16]); private static final ThreadLocal NEXT = ThreadLocal.withInitial(() -> new boolean[16][16]); private static final ThreadLocal NEXT_NEXT = ThreadLocal.withInitial(() -> new boolean[16][16]); + private static final ThreadLocal OBFUSCATE_CACHE = ThreadLocal.withInitial(() -> new int[16][16]); private static final ThreadLocal TRACE_CACHE = 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[] trace = traceGlobal == obfuscateGlobal ? obfuscate : TRACE.get(); + int[] obfuscate = OBFUSCATE.get(); + int[] trace = traceGlobal == obfuscateGlobal ? obfuscate : TRACE.get(); boolean[][] current = CURRENT.get(); boolean[][] next = NEXT.get(); boolean[][] nextNext = NEXT_NEXT.get(); + int[][] obfuscateCache = OBFUSCATE_CACHE.get(); boolean[][] traceCache = TRACE_CACHE.get(); // bitStorageReader, bitStorageWriter and nearbyChunkSections could also be reused (with ThreadLocal if necessary) but it's not worth it BitStorageReader bitStorageReader = new BitStorageReader(); @@ -260,8 +350,8 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo Level level = chunk.getLevel(); int maxChunkSectionIndex = Math.min((maxBlockHeight >> 4) - chunk.getMinSection(), chunk.getSectionsCount()) - 1; boolean[] solidTemp = null; - boolean[] obfuscateTemp = null; - boolean[] traceTemp = null; + int[] obfuscateTemp = null; + int[] traceTemp = null; bitStorageReader.setBuffer(chunkPacketInfoAntiXray.getBuffer()); bitStorageWriter.setBuffer(chunkPacketInfoAntiXray.getBuffer()); int numberOfBlocks = presetBlockStateBits.length; @@ -290,7 +380,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo int[] presetBlockStateBitsTemp; if (chunkPacketInfoAntiXray.getPalette(chunkSectionIndex) instanceof GlobalPalette) { - if (engineMode == EngineMode.HIDE) { + /*if (engineMode == EngineMode.HIDE) { switch (level.getWorld().getEnvironment()) { case NETHER: presetBlockStateBitsTemp = presetBlockStateBitsNetherrackGlobal; @@ -301,9 +391,9 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo default: presetBlockStateBitsTemp = chunkSectionIndex + chunk.getMinSection() < 0 ? presetBlockStateBitsDeepslateGlobal : presetBlockStateBitsStoneGlobal; } - } else { + } else {*/ presetBlockStateBitsTemp = presetBlockStateBitsGlobal; - } + //} } else { // If it's presetBlockStates, use this.presetBlockStatesFull instead BlockState[] presetBlockStatesFull = chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex) == presetBlockStates ? this.presetBlockStatesFull : chunkPacketInfoAntiXray.getPresetValues(chunkSectionIndex); @@ -340,7 +430,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo // Abuse the obfuscateLayer method to read the blocks of the first layer of the current chunk section bitStorageWriter.setBits(0); - obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, -1, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, traceCache, emptyNearbyChunkSections, random, blocks); + obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, -1, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, obfuscateCache, traceCache, emptyNearbyChunkSections, random, blocks); } bitStorageWriter.setBits(chunkPacketInfoAntiXray.getBits(chunkSectionIndex)); @@ -355,7 +445,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo current = next; next = nextNext; nextNext = temp; - obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, y, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, traceCache, nearbyChunkSections, random, blocks); + obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, y, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, obfuscateCache, traceCache, nearbyChunkSections, random, blocks); } // Check if the chunk section above doesn't need obfuscation @@ -378,7 +468,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo // There is nothing to read anymore bitStorageReader.setBits(0); solid[0] = true; - obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, 15, bitStorageReader, bitStorageWriter, solid, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, traceCache, nearbyChunkSections, random, blocks); + obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, 15, bitStorageReader, bitStorageWriter, solid, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, obfuscateCache, traceCache, nearbyChunkSections, random, blocks); } 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)); @@ -390,7 +480,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo current = next; next = nextNext; nextNext = temp; - obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, 15, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, traceCache, nearbyChunkSections, random, blocks); + obfuscateLayer(chunk.getPos(), chunk.getMinSection(), chunkSectionIndex, 15, bitStorageReader, bitStorageWriter, solidTemp, obfuscateTemp, traceTemp, presetBlockStateBitsTemp, current, next, nextNext, obfuscateCache, traceCache, nearbyChunkSections, random, blocks); } bitStorageWriter.flush(); @@ -404,7 +494,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo chunkPacketInfoAntiXray.getChunkPacket().setReady(true); } - private void obfuscateLayer(ChunkPos chunkPos, int minSection, int chunkSectionIndex, int y, BitStorageReader bitStorageReader, BitStorageWriter bitStorageWriter, boolean[] solid, boolean[] obfuscate, boolean[] trace, int[] presetBlockStateBits, boolean[][] current, boolean[][] next, boolean[][] nextNext, boolean[][] traceCache, LevelChunkSection[] nearbyChunkSections, IntSupplier random, Collection blocks) { + private void obfuscateLayer(ChunkPos chunkPos, int minSection, int chunkSectionIndex, int y, BitStorageReader bitStorageReader, BitStorageWriter bitStorageWriter, boolean[] solid, int[] obfuscate, int[] trace, int[] presetBlockStateBits, boolean[][] current, boolean[][] next, boolean[][] nextNext, int[][] obfuscateCache, boolean[][] traceCache, LevelChunkSection[] nearbyChunkSections, IntSupplier random, Collection blocks) { int minX = chunkPos.getMinBlockX(); int minZ = chunkPos.getMinBlockZ(); int realY = (chunkSectionIndex + minSection << 4) + y; @@ -413,7 +503,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[0][0] = !solid[bits]) { if (traceCache[0][0] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][0]]); // Exposed to air blocks.add(new BlockPos(minX + 0, realY, minZ + 0)); } else { bitStorageWriter.skip(); @@ -424,23 +514,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[0][0] || isTransparent(nearbyChunkSections[2], 0, y, 15) || isTransparent(nearbyChunkSections[0], 15, y, 0)) { if (traceCache[0][0] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][0]]); // Exposed to air blocks.add(new BlockPos(minX + 0, realY, minZ + 0)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][0]]); // Not exposed to air } } - if (trace[bits]) { + int obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[0][0] = obfuscateValue; traceCache[0][0] = true; } else { traceCache[0][0] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[0][0] = true; + } else { + obfuscateCache[0][0] = obfuscateValue; } } @@ -450,7 +546,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[0][x] = !solid[bits]) { if (traceCache[0][x] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][x]]); // Exposed to air blocks.add(new BlockPos(minX + x, realY, minZ + 0)); } else { bitStorageWriter.skip(); @@ -462,23 +558,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[0][x] || isTransparent(nearbyChunkSections[2], x, y, 15)) { if (traceCache[0][x] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][x]]); // Exposed to air blocks.add(new BlockPos(minX + x, realY, minZ + 0)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][x]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[0][x] = obfuscateValue; traceCache[0][x] = true; } else { traceCache[0][x] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[0][x] = true; + } else { + obfuscateCache[0][x] = obfuscateValue; } } } @@ -488,7 +590,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[0][15] = !solid[bits]) { if (traceCache[0][15] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][15]]); // Exposed to air blocks.add(new BlockPos(minX + 15, realY, minZ + 0)); } else { bitStorageWriter.skip(); @@ -499,23 +601,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[0][15] || isTransparent(nearbyChunkSections[2], 15, y, 15) || isTransparent(nearbyChunkSections[1], 0, y, 0)) { if (traceCache[0][15] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][15]]); // Exposed to air blocks.add(new BlockPos(minX + 15, realY, minZ + 0)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[0][15]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[0][15] = obfuscateValue; traceCache[0][15] = true; } else { traceCache[0][15] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[0][15] = true; + } else { + obfuscateCache[0][15] = obfuscateValue; } } @@ -526,7 +634,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[z][0] = !solid[bits]) { if (traceCache[z][0] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][0]]); // Exposed to air blocks.add(new BlockPos(minX + 0, realY, minZ + z)); } else { bitStorageWriter.skip(); @@ -538,23 +646,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[z][0] || isTransparent(nearbyChunkSections[0], 15, y, z)) { if (traceCache[z][0] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][0]]); // Exposed to air blocks.add(new BlockPos(minX + 0, realY, minZ + z)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][0]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[z][0] = obfuscateValue; traceCache[z][0] = true; } else { traceCache[z][0] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[z][0] = true; + } else { + obfuscateCache[z][0] = obfuscateValue; } } @@ -564,7 +678,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[z][x] = !solid[bits]) { if (traceCache[z][x] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][x]]); // Exposed to air blocks.add(new BlockPos(minX + x, realY, minZ + z)); } else { bitStorageWriter.skip(); @@ -577,23 +691,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[z][x]) { if (traceCache[z][x] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][x]]); // Exposed to air blocks.add(new BlockPos(minX + x, realY, minZ + z)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][x]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[z][x] = obfuscateValue; traceCache[z][x] = true; } else { traceCache[z][x] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[z][x] = true; + } else { + obfuscateCache[z][x] = obfuscateValue; } } } @@ -603,7 +723,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[z][15] = !solid[bits]) { if (traceCache[z][15] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][15]]); // Exposed to air blocks.add(new BlockPos(minX + 15, realY, minZ + z)); } else { bitStorageWriter.skip(); @@ -615,23 +735,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[z][15] || isTransparent(nearbyChunkSections[1], 0, y, z)) { if (traceCache[z][15] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][15]]); // Exposed to air blocks.add(new BlockPos(minX + 15, realY, minZ + z)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[z][15]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[z][15] = obfuscateValue; traceCache[z][15] = true; } else { traceCache[z][15] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[z][15] = true; + } else { + obfuscateCache[z][15] = obfuscateValue; } } } @@ -641,7 +767,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[15][0] = !solid[bits]) { if (traceCache[15][0] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][0]]); // Exposed to air blocks.add(new BlockPos(minX + 0, realY, minZ + 15)); } else { bitStorageWriter.skip(); @@ -652,23 +778,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[15][0] || isTransparent(nearbyChunkSections[3], 0, y, 0) || isTransparent(nearbyChunkSections[0], 15, y, 15)) { if (traceCache[15][0] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][0]]); // Exposed to air blocks.add(new BlockPos(minX + 0, realY, minZ + 15)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][0]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[15][0] = obfuscateValue; traceCache[15][0] = true; } else { traceCache[15][0] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[15][0] = true; + } else { + obfuscateCache[15][0] = obfuscateValue; } } @@ -678,7 +810,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[15][x] = !solid[bits]) { if (traceCache[15][x] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][x]]); // Exposed to air blocks.add(new BlockPos(minX + x, realY, minZ + 15)); } else { bitStorageWriter.skip(); @@ -690,23 +822,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[15][x] || isTransparent(nearbyChunkSections[3], x, y, 0)) { if (traceCache[15][x] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][x]]); // Exposed to air blocks.add(new BlockPos(minX + x, realY, minZ + 15)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][x]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[15][x] = obfuscateValue; traceCache[15][x] = true; } else { traceCache[15][x] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[15][x] = true; + } else { + obfuscateCache[15][x] = obfuscateValue; } } } @@ -716,7 +854,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo if (nextNext[15][15] = !solid[bits]) { if (traceCache[15][15] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][15]]); // Exposed to air blocks.add(new BlockPos(minX + 15, realY, minZ + 15)); } else { bitStorageWriter.skip(); @@ -727,23 +865,29 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo } else { if (current[15][15] || isTransparent(nearbyChunkSections[3], 15, y, 0) || isTransparent(nearbyChunkSections[1], 0, y, 15)) { if (traceCache[15][15] && blocks.size() < maxRayTraceBlockCountPerChunk) { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][15]]); // Exposed to air blocks.add(new BlockPos(minX + 15, realY, minZ + 15)); } else { bitStorageWriter.skip(); } } else { - bitStorageWriter.write(presetBlockStateBits[random.getAsInt()]); // Not exposed to air + bitStorageWriter.write(presetBlockStateBits[obfuscateCache[15][15]]); // Not exposed to air } } - if (trace[bits]) { + obfuscateValue = trace[bits]; + + if (obfuscateValue != -1) { + obfuscateCache[15][15] = obfuscateValue; traceCache[15][15] = true; } else { traceCache[15][15] = false; + obfuscateValue = obfuscate[bits]; - if (!obfuscate[bits]) { + if (obfuscateValue == -1) { next[15][15] = true; + } else { + obfuscateCache[15][15] = obfuscateValue; } } } @@ -782,6 +926,25 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo return temp; } + private int[] readPalette(Palette palette, int[] temp, int[] 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) { @@ -838,7 +1001,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo public void updateBlock(Level level, BlockPos blockPos) { BlockState blockState = level.getBlockStateIfLoaded(blockPos); - if (blockState != null && obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)]) { + if (blockState != null && obfuscateGlobal[GLOBAL_BLOCKSTATE_PALETTE.idFor(blockState)] != -1) { ((ServerLevel) level).getChunkSource().blockChanged(blockPos); } }