From 32a2cbb4dd015100ad2219148569434453a27083 Mon Sep 17 00:00:00 2001 From: D4rkr34lm Date: Tue, 19 May 2026 22:47:22 +0200 Subject: [PATCH] Finish initial implementation of logic --- .../src/de/steamwar/techhider/ChunkHider.java | 189 ++++-------------- .../src/de/steamwar/techhider/TechHider.java | 21 +- 2 files changed, 56 insertions(+), 154 deletions(-) diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java index e45e5159..3ba49d16 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java @@ -56,11 +56,19 @@ public abstract class ChunkHider { private final int SECTION_SPAN_SIZE = 16; private final byte BIT_PER_BLOCK_INDIRECTION_LIMIT = 8; + private final int BLOCKS_PER_SECTION = 4096; + private final int BIOMES_PER_SECTION = 64; private final byte BITS_PER_LONG = 64; - private long[] readSectionDataFromBuffer(ByteBuf dataSource, byte bitsPerEntry, int entryCount) { + private final int blockIdUsedForHiding; + + public ChunkHider(Block blockUsedForObfuscation) { + blockIdUsedForHiding = Block.BLOCK_STATE_REGISTRY.getId(blockUsedForObfuscation.defaultBlockState()); + } + + private long[] readSectionDataFromBuffer(ByteBuf dataSource, short bitsPerEntry, int entryCount) { int entriesPerLong = BITS_PER_LONG / bitsPerEntry; int dataLengthAsLongCount = (entryCount + entriesPerLong - 1) / entriesPerLong; @@ -73,7 +81,7 @@ public abstract class ChunkHider { return dataArray; } - public ClientboundLevelChunkWithLightPacket chunkHiderGenerator(Player player, ClientboundLevelChunkWithLightPacket packet) { + public ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(Player player, ClientboundLevelChunkWithLightPacket packet) { int chunkX = packet.getX(); int chunkZ = packet.getZ(); ClientboundLevelChunkPacketData chunkData = packet.getChunkData(); @@ -85,15 +93,16 @@ public abstract class ChunkHider { int worldMaxHeight = player.getWorld().getMaxHeight(); for (int yOffset = worldMinHeight; yOffset < worldMaxHeight; yOffset += SECTION_SPAN_SIZE) { - // TODO make configurable - int blockIdUsedForHiding = 121; - short blockCount = in.readShort(); byte bitsPerBlock = in.readByte(); if(bitsPerBlock == 0) { int sectionBlockId = ProtocolUtils.readVarInt(in); + + out.writeShort(blockCount); + out.writeByte(bitsPerBlock); + ProtocolUtils.writeVarInt(out, sectionBlockId); } else if (bitsPerBlock <= BIT_PER_BLOCK_INDIRECTION_LIMIT) { int palletLength = ProtocolUtils.readVarInt(in); @@ -205,6 +214,7 @@ public abstract class ChunkHider { } } + copyOverSectionBiomeData(in, out); } if (in.readableBytes() != 0) { @@ -258,159 +268,34 @@ public abstract class ChunkHider { }).toList(); } - private void biomes(SectionHider section) { - section.copyBitsPerBlock(); - if (section.getBitsPerBlock() == 0) { - section.copyVarInt(); - } else if (section.getBitsPerBlock() < 6) { - section.skipPalette(); - section.skipNewDataArray(64); - } else { - // Direct (global) biome IDs – no palette present - section.skipNewDataArray(64); + private void copyOverSectionBiomeData(ByteBuf oldData, ByteBuf newData){ + short bitsPerBiome = oldData.readShort(); + newData.writeShort(bitsPerBiome); + + if(bitsPerBiome == 0) { + int sectionBiomeId = ProtocolUtils.readVarInt(oldData); + ProtocolUtils.writeVarInt(newData, sectionBiomeId); } - } + else if(bitsPerBiome <= BIT_PER_BLOCK_INDIRECTION_LIMIT) { + int palletLength = ProtocolUtils.readVarInt(oldData); + ProtocolUtils.writeVarInt(newData, palletLength); - @Getter - class SectionHider { - private final Player player; - private final ByteBuf in; - private final ByteBuf out; + for(int i = 0; i < palletLength; i++) { + int palletEntry = ProtocolUtils.readVarInt(oldData); + ProtocolUtils.writeVarInt(newData, palletEntry); + } - private final int chunkX; - private final int chunkY; - private final int chunkZ; - private final int offsetX; - private final int offsetY; - private final int offsetZ; - - - private boolean paletted; - private int bitsPerBlock; - private int blockCount; - private int air; - private int target; - private Set blockIdsToObfuscate; - private final int blockIdToObfuscateTo; - - public SectionHider(Player player, ByteBuf in, ByteBuf out, int chunkX, int chunkY, int chunkZ) { - this.player = player; - this.in = in; - this.out = out; - this.chunkX = chunkX; - this.chunkY = chunkY; - this.chunkZ = chunkZ; - this.offsetX = 16 * chunkX; - this.offsetY = 16 * chunkY; - this.offsetZ = 16 * chunkZ; - this.skipSection = techHider.getLocationEvaluator().skipChunkSection(player, chunkX, chunkY, chunkZ); - - this.paletted = false; - this.bitsPerBlock = 0; - this.air = TechHider.AIR_ID; - this.target = techHider.getObfuscationTargetId(); - this.obfuscate = techHider.getObfuscateIds(); + long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION); + for(long rawDataSegment : rawData ) { + newData.writeLong(rawDataSegment); + } } - - public boolean blockPrecise() { - return techHider.getLocationEvaluator().blockPrecise(player, chunkX, chunkY, chunkZ); - } - - public TechHider.State test(int x, int y, int z) { - return techHider.getLocationEvaluator().check(player, offsetX + x, offsetY + y, offsetZ + z); - } - - public void copyBlockCount() { - this.blockCount = in.readShort(); - out.writeShort(blockCount); - } - - public void copyBitsPerBlock() { - bitsPerBlock = in.readByte(); - out.writeByte(bitsPerBlock); - } - - public int copyVarInt() { - int value = ProtocolUtils.readVarInt(in); - ProtocolUtils.writeVarInt(out, value); - return value; - } - - public void skipPalette() { - int paletteLength = copyVarInt(); - for (int i = 0; i < paletteLength; i++) { - copyVarInt(); + else { + long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION); + for(long rawDataSegment : rawData ) { + newData.writeLong(rawDataSegment); } } - public void processPalette() { - int paletteLength = copyVarInt(); - if (paletteLength == 0) return; - - paletted = true; - air = 0; - target = 0; - - for (int i = 0; i < paletteLength; i++) { - int entry = ProtocolUtils.readVarInt(in); - if (obfuscate.contains(entry)) { - entry = techHider.getObfuscationTargetId(); - } - - if (entry == TechHider.AIR_ID) { - air = i; - } else if (entry == techHider.getObfuscationTargetId()) { - target = i; - } - - ProtocolUtils.writeVarInt(out, entry); - } - blockIdsToObfuscate = Collections.emptySet(); - } - - public void skipDataArray() { - int dataArrayLength = copyVarInt(); - out.writeBytes(in, dataArrayLength * 8); - } - - public void skipNewDataArray(int entries) { - if (bitsPerBlock == 0) { - return; - } - - char valuesPerLong = (char) (64 / bitsPerBlock); - int i1 = (entries + valuesPerLong - 1) / valuesPerLong; - out.writeBytes(in, i1 * Long.BYTES); - } - - public long[] readDataArray() { - long[] array = new long[copyVarInt()]; - for (int i = 0; i < array.length; i++) { - array[i] = in.readLong(); - } - - return array; - } - - public long[] readNewDataArray(int entries) { - if (bitsPerBlock == 0) { - return new long[entries]; - } - - char valuesPerLong = (char) (64 / bitsPerBlock); - int i1 = (entries + valuesPerLong - 1) / valuesPerLong; - long[] array = new long[i1]; - for (int i = 0; i < i1; i++) { - array[i] = in.readLong(); - } - - return array; - } - - public void writeDataArray(long[] array) { - for (long l : array) { - out.writeLong(l); - } - } } } diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java index 61358c26..ead26362 100644 --- a/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java +++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java @@ -186,12 +186,30 @@ public abstract class TechHider { private final Block blockUsedForObfuscation; private final BlockState blockStateUsedForObfuscation; + private ChunkHider chunkHider; // TODO handle packet bundle public TechHider(Plugin plugin, Block blockUsedForObfuscation) { this.blockUsedForObfuscation = blockUsedForObfuscation; this.blockStateUsedForObfuscation = blockUsedForObfuscation.defaultBlockState(); + this.chunkHider = new ChunkHider(blockUsedForObfuscation) { + @Override + public boolean isPlayerPrivilegedToAccessBlock(Player p, int blockX, int blockY, int blockZ, Block block) { + return TechHider.this.isPlayerPrivilegedToAccessBlock(p, blockX, blockY, blockZ, block); + } + + @Override + public boolean isPlayerPrivilegedToAccessBlockEntity(Player p, int blockX, int blockY, int blockZ, BlockEntityType type) { + return TechHider.this.isPlayerPrivilegedToAccessBlocEntity(p, blockX, blockY, blockZ, type); + } + + @Override + public boolean isPlayerPrivilegedToAccessPosition(Player p, int blockX, int blockY, int blockZ) { + return TechHider.this.isPlayerPrivilegedToAccessPosition(p, blockX, blockY, blockZ); + } + }; + this.bypassingPackets = new HashSet<>(List.of( // --- 5.1.x Login Protocol --- ClientboundLoginDisconnectPacket.class, // 5.1.1 Disconnect @@ -621,9 +639,8 @@ public abstract class TechHider { } } - private final ChunkHider chunkHider = new ChunkHider(); private ClientboundLevelChunkWithLightPacket processChunkWithLight(Player p, ClientboundLevelChunkWithLightPacket packet) { - return chunkHider.processLevelChunkWithLightPacket(p, blockEntitiesToHide, this::isPlayerPrivilegedToAccessBlockPos, blockToObfuscateTo, blockIdsToObfuscate, packet); + return chunkHider.processLevelChunkWithLightPacket(p, packet); } private Packet processContainerPacket(Player player, int containerId, Packet packet) {