From a69a5bfe36acee0483c4221206ea5ae579b682db Mon Sep 17 00:00:00 2001 From: Lixfel Date: Thu, 7 Mar 2024 12:11:49 +0100 Subject: [PATCH 1/3] Block precise TechHider (preparation for block HullHider) Untested --- .gitignore | 3 - .../de/steamwar/techhider/ChunkHider14.java | 117 ++------------ .../steamwar/techhider/ProtocolWrapper14.java | 20 +-- .../de/steamwar/techhider/ChunkHider18.java | 132 ++++++++-------- .../steamwar/techhider/ProtocolWrapper18.java | 60 ++++++-- .../steamwar/techhider/ProtocolWrapper19.java | 2 +- .../de/steamwar/techhider/ChunkHider8.java | 2 +- .../steamwar/techhider/ProtocolWrapper8.java | 40 +++-- .../de/steamwar/techhider/ChunkHider9.java | 144 ++++++++++++------ .../src/de/steamwar/techhider/ChunkHider.java | 27 +++- .../de/steamwar/techhider/ProtocolUtils.java | 36 ++++- .../steamwar/techhider/ProtocolWrapper.java | 4 +- .../src/de/steamwar/techhider/TechHider.java | 74 ++++++--- build.gradle | 10 +- 14 files changed, 387 insertions(+), 284 deletions(-) diff --git a/.gitignore b/.gitignore index 36e1257..9ee48d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# Package Files -*.jar - # Gradle .gradle **/build/ diff --git a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java index eae64df..6f779a6 100644 --- a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java +++ b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java @@ -20,122 +20,23 @@ package de.steamwar.techhider; import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; -import java.nio.ByteBuffer; -import java.nio.LongBuffer; +import java.util.Collections; import java.util.Set; public class ChunkHider14 extends ChunkHider9 { @Override - protected byte[] dataHider(int obfuscationTarget, Set obfuscate, byte[] data, Integer primaryBitMask) { - ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100); - int i = 0; + protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + out.writeShort(in.readShort()); // Block count + byte bitsPerBlock = in.readByte(); + out.writeByte(bitsPerBlock); - while(primaryBitMask != 0){ - while((primaryBitMask & 1) == 0){ - primaryBitMask >>= 1; - } - - buffer.writeBytes(data, i, 2); // Block count - i += 2; - byte bitsPerBlock = data[i++]; - buffer.writeByte(bitsPerBlock); - - if(bitsPerBlock < 9){ - int paletteLength = ProtocolUtils.readVarInt(data, i); - int paletteLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, paletteLengthLength); - i += paletteLengthLength; - for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++){ - int blockId = ProtocolUtils.readVarInt(data, i); - int actPaletteLength = ProtocolUtils.readVarIntLength(data, i); - - if(obfuscate.contains(blockId)){ - buffer.writeBytes(ProtocolUtils.writeVarInt(obfuscationTarget)); - }else{ - buffer.writeBytes(data, i, actPaletteLength); - } - i += actPaletteLength; - } - - //We modify only the chunk palette for performance reasons - int dataArrayLength = ProtocolUtils.readVarInt(data, i); - int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, dataArrayLength * 8 + dataArrayLengthLength); - i += dataArrayLengthLength; - i += dataArrayLength * 8; - }else{ - //Full Chunk/no palette, so the chunk has to be crawled through - int dataArrayLength = ProtocolUtils.readVarInt(data, i); - int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, dataArrayLengthLength); - i += dataArrayLengthLength; - - ByteBuffer source = ByteBuffer.wrap(data, i, dataArrayLength * 8); - VariableValueArray values = new VariableValueArray(bitsPerBlock, dataArrayLength, source.asLongBuffer()); - - for(int pos = 0; pos < 4096; pos++){ - if(obfuscate.contains(values.get(pos))){ - values.set(pos, obfuscationTarget); - } - } - - for(long l : values.backing) - buffer.writeLong(l); - - i += dataArrayLength * 8; - } - - primaryBitMask >>= 1; - } - buffer.writeBytes(data, i, data.length - i); // MC appends a 0 byte at the end if there is a full chunk, idk why - - data = new byte[buffer.readableBytes()]; - buffer.readBytes(data); - return data; - } - - private static final class VariableValueArray { - private final long[] backing; - private final int bitsPerValue; - private final long valueMask; - - public VariableValueArray(int bitsPerEntry, int dataArrayLength, LongBuffer buffer) { - this.bitsPerValue = bitsPerEntry; - this.backing = new long[dataArrayLength]; - buffer.get(backing); - this.valueMask = (1L << this.bitsPerValue) - 1; + if(bitsPerBlock < 9) { + obfuscationTarget = ChunkHider.processPalette(obfuscationTarget, obfuscate, in, out); + obfuscate = Collections.emptySet(); } - public int get(int index) { - index *= bitsPerValue; - int i0 = index >> 6; - int i1 = index & 0x3f; - - long value = backing[i0] >>> i1; - - // The value is divided over two long values - if (i1 + bitsPerValue > 64) { - value |= backing[++i0] << 64 - i1; - } - - return (int) (value & valueMask); - } - - public void set(int index, int value) { - index *= bitsPerValue; - int i0 = index >> 6; - int i1 = index & 0x3f; - - backing[i0] = this.backing[i0] & ~(this.valueMask << i1) | (value & valueMask) << i1; - int i2 = i1 + bitsPerValue; - // The value is divided over two long values - if (i2 > 64) { - i0++; - backing[i0] = backing[i0] & -(1L << i2 - 64) | value >> 64 - i1; - } - } + processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock); } } diff --git a/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java b/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java index 9b45405..76b4d9f 100644 --- a/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java +++ b/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java @@ -30,21 +30,23 @@ import java.util.function.UnaryOperator; public class ProtocolWrapper14 extends ProtocolWrapper8 { @Override - public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) { + public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator) { UnaryOperator blockBreakCloner = ProtocolUtils.shallowCloneGenerator(blockBreakPacket); Reflection.FieldAccessor blockBreakPosition = Reflection.getField(blockBreakPacket, TechHider.blockPosition, 0); Reflection.FieldAccessor blockBreakBlockData = Reflection.getField(blockBreakPacket, TechHider.iBlockData, 0); return (p, packet) -> { - Object pos = blockBreakPosition.get(packet); - if(bypass.bypass(p, ProtocolUtils.posToChunk(TechHider.blockPositionX.get(pos)), ProtocolUtils.posToChunk(TechHider.blockPositionZ.get(pos)))) - return packet; - - if(TechHider.iBlockDataHidden(obfuscate, blockBreakBlockData.get(packet))){ - packet = blockBreakCloner.apply(packet); - blockBreakBlockData.set(packet, obfuscationTarget); + switch (locationEvaluator.checkBlockPos(p, blockBreakPosition.get(packet))) { + case SKIP: + return packet; + case CHECK: + if(!TechHider.iBlockDataHidden(obfuscate, blockBreakBlockData.get(packet))) + return packet; + default: + packet = blockBreakCloner.apply(packet); + blockBreakBlockData.set(packet, obfuscationTarget); + return packet; } - return packet; }; } } diff --git a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java index b847d1b..2d0b1fe 100644 --- a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java +++ b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java @@ -22,21 +22,19 @@ package de.steamwar.techhider; import com.comphenix.tinyprotocol.Reflection; import de.steamwar.core.Core; import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; +import io.netty.buffer.Unpooled; import net.minecraft.core.IRegistry; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.MinecraftKey; import net.minecraft.util.SimpleBitStorage; import net.minecraft.world.level.block.entity.TileEntityTypes; -import org.bukkit.World; import org.bukkit.entity.Player; -import java.nio.ByteBuffer; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.BiFunction; -import java.util.function.IntFunction; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -49,29 +47,41 @@ public class ChunkHider18 implements ChunkHider { private static final UnaryOperator chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class); private static final UnaryOperator chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class); - private static final Reflection.FieldAccessor chunkX = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0); - private static final Reflection.FieldAccessor chunkZ = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1); + private static final Reflection.FieldAccessor chunkXField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0); + private static final Reflection.FieldAccessor chunkZField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1); private static final Reflection.FieldAccessor chunkData = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class, 0); private static final Reflection.FieldAccessor dataField = Reflection.getField(ClientboundLevelChunkPacketData.class, byte[].class, 0); private static final Reflection.FieldAccessor tileEntities = Reflection.getField(ClientboundLevelChunkPacketData.class, List.class, 0); @Override - public BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { + public BiFunction chunkHiderGenerator(TechHider.LocationEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { return (p, packet) -> { - if(bypass.bypass(p, chunkX.get(packet), chunkZ.get(packet))) + int chunkX = chunkXField.get(packet); + int chunkZ = chunkZField.get(packet); + if (locationEvaluator.skipChunk(p, chunkX, chunkZ)) return packet; packet = chunkPacketCloner.apply(packet); - Object data = chunkDataCloner.apply(chunkData.get(packet)); + Object dataWrapper = chunkDataCloner.apply(chunkData.get(packet)); - tileEntities.set(data, ((List)tileEntities.get(data)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList())); + tileEntities.set(dataWrapper, ((List)tileEntities.get(dataWrapper)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList())); - World world = p.getWorld(); - int sections = (world.getMaxHeight() - world.getMinHeight()) / 16; - dataField.set(data, dataHider(obfuscationTarget, obfuscate, dataField.get(data), sections)); + ByteBuf in = Unpooled.wrappedBuffer(dataField.get(dataWrapper)); + ByteBuf out = Unpooled.buffer(in.readableBytes() + 64); + int xOffset = 16*chunkX; + int zOffset = 16*chunkZ; + for(int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) { + int finalYOffset = yOffset; + dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+finalYOffset, z+zOffset), obfuscationTarget, obfuscate, in, out); + } + out.writeBytes(in); // MC appends a 0 byte at the end if there is a full chunk, idk why - chunkData.set(packet, data); + byte[] data = new byte[out.readableBytes()]; + out.readBytes(data); + dataField.set(dataWrapper, data); + + chunkData.set(packet, dataWrapper); return packet; }; } @@ -85,72 +95,62 @@ public class ChunkHider18 implements ChunkHider { return !hiddenBlockEntities.contains((String) getName.invoke(getKey.invoke(tileEntityTypes, entityType.get(tile)))); } - private byte[] dataHider(int obfuscationTarget, Set obfuscate, byte[] data, int sections) { - ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100); - int i = 0; + private void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + out.writeShort(in.readShort()); // Block count - while(sections-- > 0) { - buffer.writeBytes(data, i, 2); // Block count - i += 2; + containerWalker(in, out, 15, obfuscationTarget, obfuscate, (paletteTarget, dataArrayLength, bitsPerBlock) -> { + Set palettedObfuscate; + if(bitsPerBlock < 15) { + palettedObfuscate = Collections.emptySet(); + } else { + paletteTarget = obfuscationTarget; + palettedObfuscate = obfuscate; + } - i = containerWalker(data, buffer, i, 15, blockId -> obfuscate.contains(blockId) ? obfuscationTarget : blockId, (curI, dataArrayLength, bitsPerBlock) -> { - if(bitsPerBlock < 15) { - buffer.writeBytes(data, curI, dataArrayLength * 8); - } else { - ByteBuffer source = ByteBuffer.wrap(data, curI, dataArrayLength * 8); - long[] array = new long[dataArrayLength]; - source.asLongBuffer().get(array); - SimpleBitStorage values = new SimpleBitStorage(bitsPerBlock, 4096, array); + long[] array = new long[dataArrayLength]; + for(int i = 0; i < dataArrayLength; i++) + array[i] = in.readLong(); + SimpleBitStorage values = new SimpleBitStorage(bitsPerBlock, 4096, array); - for (int pos = 0; pos < 4096; pos++) { - if (obfuscate.contains(values.a(pos))) { - values.b(pos, obfuscationTarget); + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + int pos = (((y * 16) + z) * 16) + x; + + switch (locationEvaluator.test(x, y, z)) { + case SKIP: + break; + case CHECK: + if(!palettedObfuscate.contains(values.a(pos))) + break; + default: + values.b(pos, paletteTarget); } } - - for (long l : values.a()) - buffer.writeLong(l); } - }); - i = containerWalker(data, buffer, i, 6, value -> value, (curI, dataArrayLength, bitsPerBlock) -> buffer.writeBytes(data, curI, dataArrayLength * 8)); - } - buffer.writeBytes(data, i, data.length - i); // MC appends a 0 byte at the end if there is a full chunk, idk why + } - byte[] outdata = new byte[buffer.readableBytes()]; - buffer.readBytes(outdata); - return outdata; + for (long l : values.a()) + out.writeLong(l); + }); + containerWalker(in, out, 6, 0, Collections.emptySet(), (paletteTarget, dataArrayLength, bitsPerBlock) -> out.writeBytes(in, dataArrayLength * 8)); // Biomes } - private int containerWalker(byte[] data, ByteBuf buffer, int i, int globalPalette, IntFunction palette, TriConsumer dataArray) { - byte bitsPerBlock = data[i++]; - buffer.writeByte(bitsPerBlock); + private void containerWalker(ByteBuf in, ByteBuf out, int globalPalette, int obfuscationTarget, Set obfuscate, TriConsumer dataArray) { + byte bitsPerBlock = in.readByte(); + out.writeByte(bitsPerBlock); + //blockId -> obfuscate.contains(blockId) ? obfuscationTarget : blockId if(bitsPerBlock == 0) { - int paletteValue = ProtocolUtils.readVarInt(data, i); - i += ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(ProtocolUtils.writeVarInt(palette.apply(paletteValue))); + int value = ProtocolUtils.readVarInt(in); + ProtocolUtils.writeVarInt(out, obfuscate.contains(value) ? obfuscationTarget : value); }else if(bitsPerBlock < globalPalette) { - int paletteLength = ProtocolUtils.readVarInt(data, i); - int paletteLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, paletteLengthLength); - i += paletteLengthLength; - - for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++) { - int paletteValue = ProtocolUtils.readVarInt(data, i); - i += ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(ProtocolUtils.writeVarInt(palette.apply(paletteValue))); - } + obfuscationTarget = ChunkHider.processPalette(obfuscationTarget, obfuscate, in, out); } - int dataArrayLength = ProtocolUtils.readVarInt(data, i); - int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, dataArrayLengthLength); - i += dataArrayLengthLength; - - dataArray.accept(i, dataArrayLength, bitsPerBlock); - i += dataArrayLength * 8; - - return i; + int dataArrayLength = ProtocolUtils.readVarInt(in); + ProtocolUtils.writeVarInt(out, dataArrayLength); + dataArray.accept(obfuscationTarget, dataArrayLength, bitsPerBlock); } private interface TriConsumer { diff --git a/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java b/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java index a52ddd5..9f78b08 100644 --- a/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java +++ b/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java @@ -28,24 +28,56 @@ import net.minecraft.world.level.block.state.IBlockData; import org.bukkit.Material; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.Set; import java.util.function.BiFunction; -import java.util.function.UnaryOperator; public class ProtocolWrapper18 implements ProtocolWrapper { private static final Reflection.FieldAccessor multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPosition.class, 0); + private static final Reflection.FieldAccessor multiBlockChangePos = Reflection.getField(TechHider.multiBlockChangePacket, short[].class, 0); private static final Reflection.FieldAccessor multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, IBlockData[].class, 0); - private static final BiFunction, Object> iBlockDataArrayCloner = ProtocolUtils.arrayCloneGenerator(TechHider.iBlockData); @Override - public BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) { + public BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator) { return (p, packet) -> { Object chunkCoords = multiBlockChangeChunk.get(packet); - if(bypass.bypass(p, TechHider.blockPositionX.get(chunkCoords), TechHider.blockPositionZ.get(chunkCoords))) + int chunkX = TechHider.blockPositionX.get(chunkCoords); + int chunkY = TechHider.blockPositionY.get(chunkCoords); + int chunkZ = TechHider.blockPositionZ.get(chunkCoords); + if(locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ)) return packet; packet = TechHider.multiBlockChangeCloner.apply(packet); - multiBlockChangeBlocks.set(packet, iBlockDataArrayCloner.apply(multiBlockChangeBlocks.get(packet), block -> TechHider.iBlockDataHidden(obfuscate, block) ? obfuscationTarget : block)); + final short[] oldPos = multiBlockChangePos.get(packet); + final IBlockData[] oldBlocks = multiBlockChangeBlocks.get(packet); + ArrayList poss = new ArrayList<>(oldPos.length); + ArrayList blocks = new ArrayList<>(oldPos.length); + for(int i = 0; i < oldPos.length; i++) { + short pos = oldPos[i]; + IBlockData block = oldBlocks[i]; + switch(locationEvaluator.check(p, 16*chunkX + (pos >> 8 & 0xF), 16*chunkY + (pos & 0xF), 16*chunkZ + (pos >> 4 & 0xF))) { + case SKIP: + poss.add(pos); + blocks.add(block); + break; + case CHECK: + poss.add(pos); + blocks.add(TechHider.iBlockDataHidden(obfuscate, block) ? (IBlockData) obfuscationTarget : block); + break; + default: + break; + } + } + + if(blocks.isEmpty()) + return null; + + short[] newPos = new short[poss.size()]; + for(int i = 0; i < newPos.length; i++) + newPos[i] = poss.get(i); + + multiBlockChangePos.set(packet, newPos); + multiBlockChangeBlocks.set(packet, blocks.toArray()); return packet; }; } @@ -58,16 +90,18 @@ public class ProtocolWrapper18 implements ProtocolWrapper { } @Override - public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) { + public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator) { return (p, packet) -> { PacketPlayOutBlockBreak breakPacket = (PacketPlayOutBlockBreak) packet; - if(bypass.bypass(p, ProtocolUtils.posToChunk(TechHider.blockPositionX.get(breakPacket.b())), ProtocolUtils.posToChunk(TechHider.blockPositionZ.get(breakPacket.b())))) - return packet; - - if(!TechHider.iBlockDataHidden(obfuscate, breakPacket.c())) - return packet; - - return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) obfuscationTarget, breakPacket.d(), breakPacket.a()); + switch (locationEvaluator.checkBlockPos(p, breakPacket.b())) { + case SKIP: + return packet; + case CHECK: + if(!TechHider.iBlockDataHidden(obfuscate, breakPacket.c())) + return packet; + default: + return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) obfuscationTarget, breakPacket.d(), breakPacket.a()); + } }; } } diff --git a/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java b/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java index 9c31653..38ac90c 100644 --- a/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java +++ b/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java @@ -28,7 +28,7 @@ import java.util.function.BiFunction; public class ProtocolWrapper19 extends ProtocolWrapper18 { @Override - public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) { + public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator) { return null; } } diff --git a/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java b/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java index d60a437..b7da81e 100644 --- a/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java +++ b/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java @@ -34,7 +34,7 @@ public class ChunkHider8 implements ChunkHider { } @Override - public BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { + public BiFunction chunkHiderGenerator(TechHider.LocationEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { return (player, packet) -> packet; } } diff --git a/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java b/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java index 681b4f7..5b30a6b 100644 --- a/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java +++ b/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java @@ -23,9 +23,9 @@ import com.comphenix.tinyprotocol.Reflection; import org.bukkit.Material; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.Set; import java.util.function.BiFunction; -import java.util.function.UnaryOperator; public class ProtocolWrapper8 implements ProtocolWrapper { private static final Class chunkCoordinateIntPair = Reflection.getClass("{nms}.ChunkCoordIntPair"); @@ -34,25 +34,41 @@ public class ProtocolWrapper8 implements ProtocolWrapper { private static final Reflection.FieldAccessor chunkCoordinateZ = Reflection.getField(chunkCoordinateIntPair, int.class, 1); private static final Class multiBlockChangeInfo = Reflection.getClass("{nms}.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo"); private static final Reflection.ConstructorInvoker multiBlockChangeInfoConstructor = Reflection.getConstructor(multiBlockChangeInfo, TechHider.multiBlockChangePacket, short.class, TechHider.iBlockData); - private static final BiFunction, Object> multiBlockChangeInfoArrayCloner = ProtocolUtils.arrayCloneGenerator(multiBlockChangeInfo); private static final Reflection.FieldAccessor multiBlockChangeInfoBlock = Reflection.getField(multiBlockChangeInfo, TechHider.iBlockData, 0); private static final Reflection.FieldAccessor multiBlockChangeInfoPos = Reflection.getField(multiBlockChangeInfo, short.class, 0); private static final Class multiBlockChangeInfoArray = Reflection.getClass("[L{nms}.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo;"); private static final Reflection.FieldAccessor multiBlockChangeInfos = Reflection.getField(TechHider.multiBlockChangePacket, multiBlockChangeInfoArray, 0); @Override - public BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) { + public BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator) { return (p, packet) -> { Object chunkCoords = multiBlockChangeChunk.get(packet); - if(bypass.bypass(p, chunkCoordinateX.get(chunkCoords), chunkCoordinateZ.get(chunkCoords))) + int chunkX = chunkCoordinateX.get(chunkCoords); + int chunkZ = chunkCoordinateZ.get(chunkCoords); + if(locationEvaluator.skipChunk(p, chunkX, chunkZ)) return packet; - Object modpacket = TechHider.multiBlockChangeCloner.apply(packet); - multiBlockChangeInfos.set(modpacket, multiBlockChangeInfoArrayCloner.apply(multiBlockChangeInfos.get(modpacket), mbci -> { - if(TechHider.iBlockDataHidden(obfuscate, multiBlockChangeInfoBlock.get(mbci))) - return multiBlockChangeInfoConstructor.invoke(modpacket, multiBlockChangeInfoPos.get(mbci), obfuscationTarget); - return mbci; - })); - return modpacket; + packet = TechHider.multiBlockChangeCloner.apply(packet); + Object[] mbcis = (Object[]) multiBlockChangeInfos.get(packet); + ArrayList blockChangeInfos = new ArrayList<>(mbcis.length); + for(Object mbci : mbcis) { + short pos = (short) multiBlockChangeInfoPos.get(mbci); + switch(locationEvaluator.check(p, 16*chunkX + (pos >> 12 & 0xF), pos & 0xFF, 16*chunkZ + (pos >> 8 & 0xF))) { + case SKIP: + blockChangeInfos.add(mbci); + break; + case CHECK: + blockChangeInfos.add(TechHider.iBlockDataHidden(obfuscate, multiBlockChangeInfoBlock.get(mbci)) ? multiBlockChangeInfoConstructor.invoke(packet, pos, obfuscationTarget) : mbci); + break; + default: + break; + } + } + + if(blockChangeInfos.isEmpty()) + return null; + + multiBlockChangeInfos.set(packet, blockChangeInfos.toArray(mbcis)); + return packet; }; } @@ -63,7 +79,7 @@ public class ProtocolWrapper8 implements ProtocolWrapper { } @Override - public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) { + public BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator bypass) { return null; } } diff --git a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java index 0272dd6..8f34dbb 100644 --- a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java +++ b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java @@ -21,15 +21,14 @@ package de.steamwar.techhider; import com.comphenix.tinyprotocol.Reflection; import io.netty.buffer.ByteBuf; -import io.netty.buffer.UnpooledByteBufAllocator; -import org.bukkit.Bukkit; +import io.netty.buffer.Unpooled; import org.bukkit.entity.Player; +import java.util.Collections; import java.util.List; import java.util.Set; import java.util.function.BiFunction; import java.util.function.UnaryOperator; -import java.util.logging.Level; import java.util.stream.Collectors; public class ChunkHider9 extends ChunkHider8 { @@ -46,9 +45,11 @@ public class ChunkHider9 extends ChunkHider8 { private static final Reflection.MethodInvoker nbtTagGetString = Reflection.getTypedMethod(nbtTagCompound, null, String.class, String.class); @Override - public BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { + public BiFunction chunkHiderGenerator(TechHider.LocationEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { return (p, packet) -> { - if(bypass.bypass(p, mapChunkX.get(packet), mapChunkZ.get(packet))) + int chunkX = mapChunkX.get(packet); + int chunkZ = mapChunkZ.get(packet); + if (locationEvaluator.skipChunk(p, chunkX, chunkZ)) return packet; packet = mapChunkCloner.apply(packet); @@ -56,53 +57,108 @@ public class ChunkHider9 extends ChunkHider8 { nbttag -> !hiddenBlockEntities.contains((String) nbtTagGetString.invoke(nbttag, "id")) ).collect(Collectors.toList())); - byte[] data = dataHider(obfuscationTarget, obfuscate, mapChunkData.get(packet), mapChunkBitMask.get(packet)); + int xOffset = 16*chunkX; + int zOffset = 16*chunkZ; + int primaryBitMask = mapChunkBitMask.get(packet); + ByteBuf in = Unpooled.wrappedBuffer(mapChunkData.get(packet)); + ByteBuf out = Unpooled.buffer(in.readableBytes() + 64); + for(int chunkY = 0; chunkY < p.getWorld().getMaxHeight(); chunkY++) { + if(((1 << chunkY) & primaryBitMask) == 0) + continue; + + int yOffset = 16*chunkY; + dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+yOffset, z+zOffset), obfuscationTarget, obfuscate, in, out); + } + byte[] data = new byte[out.readableBytes()]; + out.readBytes(data); mapChunkData.set(packet, data); return packet; }; } - protected byte[] dataHider(int obfuscationTarget, Set obfuscate, byte[] data, Integer primaryBitMask) { - ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100); - int i = 0; + protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + byte bitsPerBlock = in.readByte(); + out.writeByte(bitsPerBlock); - while(i < data.length){ - byte bitsPerBlock = data[i++]; - buffer.writeByte(bitsPerBlock); - - if(bitsPerBlock != 13){ - int paletteLength = ProtocolUtils.readVarInt(data, i); - int paletteLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, paletteLengthLength); - i += paletteLengthLength; - - for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++){ - int entry = ProtocolUtils.readVarInt(data, i); - i += ProtocolUtils.readVarIntLength(data, i); - - if(obfuscate.contains(entry)){ - entry = obfuscationTarget; - } - buffer.writeBytes(ProtocolUtils.writeVarInt(entry)); - } - }else{ - buffer.writeByte(data[++i]); //Empty palette - Bukkit.getLogger().log(Level.SEVERE, "Full chunk occured"); - } - - int dataArrayLength = ProtocolUtils.readVarInt(data, i); - int dataArrayLengthLength = ProtocolUtils.readVarIntLength(data, i); - buffer.writeBytes(data, i, dataArrayLength*8 + dataArrayLengthLength); - i += dataArrayLengthLength; - i += dataArrayLength * 8; - - buffer.writeBytes(data, i, 4096); - i += 4096; //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048 + int paletteTarget = ChunkHider.processPalette(obfuscationTarget, obfuscate, in, out); + if(bitsPerBlock < 13) { + obfuscationTarget = paletteTarget; + obfuscate = Collections.emptySet(); } - data = new byte[buffer.readableBytes()]; - buffer.readBytes(data); - return data; + processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock); + + out.writeBytes(in, 4096); //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048 + } + + protected void processDataArray(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, int bitsPerBlock) { + int dataArrayLength = ProtocolUtils.readVarInt(in); + ProtocolUtils.writeVarInt(out, dataArrayLength); + + VariableValueArray values = new VariableValueArray(bitsPerBlock, dataArrayLength, in); + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + int pos = (((y * 16) + z) * 16) + x; + + switch (locationEvaluator.test(x, y, z)) { + case SKIP: + break; + case CHECK: + if(!obfuscate.contains(values.get(pos))) + break; + default: + values.set(pos, obfuscationTarget); + } + } + } + } + + for(long l : values.backing) + out.writeLong(l); + } + + private static class VariableValueArray { + private final long[] backing; + private final int bitsPerValue; + private final long valueMask; + + public VariableValueArray(int bitsPerEntry, int dataArrayLength, ByteBuf in) { + this.bitsPerValue = bitsPerEntry; + this.valueMask = (1L << this.bitsPerValue) - 1; + + this.backing = new long[dataArrayLength]; + for(int i = 0; i < dataArrayLength; i++) + backing[i] = in.readLong(); + } + + public int get(int index) { + index *= bitsPerValue; + int i0 = index >> 6; + int i1 = index & 0x3f; + + long value = backing[i0] >>> i1; + + // The value is divided over two long values + if (i1 + bitsPerValue > 64) + value |= backing[++i0] << 64 - i1; + + return (int) (value & valueMask); + } + + public void set(int index, int value) { + index *= bitsPerValue; + int i0 = index >> 6; + int i1 = index & 0x3f; + + backing[i0] = backing[i0] & ~(valueMask << i1) | (value & valueMask) << i1; + int i2 = i1 + bitsPerValue; + // The value is divided over two long values + if (i2 > 64) { + i0++; + backing[i0] = backing[i0] & -(1L << i2 - 64) | value >> 64 - i1; + } + } } } diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java b/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java index b87d83d..0a39245 100644 --- a/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java +++ b/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java @@ -21,6 +21,7 @@ package de.steamwar.techhider; import de.steamwar.core.Core; import de.steamwar.core.VersionDependent; +import io.netty.buffer.ByteBuf; import org.bukkit.entity.Player; import java.util.Set; @@ -30,5 +31,29 @@ public interface ChunkHider { ChunkHider impl = VersionDependent.getVersionImpl(Core.getInstance()); Class mapChunkPacket(); - BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities); + BiFunction chunkHiderGenerator(TechHider.LocationEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities); + + static int processPalette(int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + int paletteLength = ProtocolUtils.readVarInt(in); + ProtocolUtils.writeVarInt(out, paletteLength); + + int paletteTarget = 0; + + for(int i = 0; i < paletteLength; i++) { + int entry = ProtocolUtils.readVarInt(in); + if(obfuscate.contains(entry)) + entry = obfuscationTarget; + + if(entry == obfuscationTarget) + paletteTarget = i; + + ProtocolUtils.writeVarInt(out, entry); + } + + return paletteTarget; + } + + interface PosEvaluator { + TechHider.State test(int x, int y, int z); + } } diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java index 88a5cf9..43bf043 100644 --- a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java +++ b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java @@ -22,6 +22,7 @@ package de.steamwar.techhider; import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; import com.google.common.primitives.Bytes; +import io.netty.buffer.ByteBuf; import org.bukkit.Bukkit; import java.lang.reflect.Array; @@ -40,6 +41,7 @@ public class ProtocolUtils { Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet)); } + @Deprecated public static BiFunction, Object> arrayCloneGenerator(Class elementClass) { return (array, worker) -> { int length = Array.getLength(array); @@ -93,11 +95,12 @@ public class ProtocolUtils { public static int posToChunk(int c){ int chunk = c / 16; - if(c<0) + if(c < 0) chunk--; return chunk; } + @Deprecated public static int readVarInt(byte[] array, int startPos) { int numRead = 0; int result = 0; @@ -116,6 +119,35 @@ public class ProtocolUtils { return result; } + public static int readVarInt(ByteBuf buf) { + int numRead = 0; + int result = 0; + byte read; + do { + read = buf.readByte(); + int value = (read & 0b01111111); + result |= (value << (7 * numRead)); + + if (++numRead > 5) + throw new SecurityException("VarInt too long"); + } while ((read & 0b10000000) != 0); + + return result; + } + + public static void writeVarInt(ByteBuf buf, int value) { + do { + int temp = value & 0b01111111; + // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone + value >>>= 7; + if (value != 0) { + temp |= 0b10000000; + } + buf.writeByte(temp); + } while (value != 0); + } + + @Deprecated public static int readVarIntLength(byte[] array, int startPos) { int numRead = 0; byte read; @@ -130,6 +162,7 @@ public class ProtocolUtils { return numRead; } + @Deprecated public static byte[] writeVarInt(int value) { List buffer = new ArrayList<>(5); do { @@ -144,6 +177,7 @@ public class ProtocolUtils { return Bytes.toArray(buffer); } + @Deprecated public static class ChunkPos{ final int x; final int z; diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java index 2e9e311..489e11b 100644 --- a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java +++ b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java @@ -33,7 +33,7 @@ public interface ProtocolWrapper { boolean unfilteredTileEntityDataAction(Object packet); - BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass); + BiFunction blockBreakHiderGenerator(Class blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator); - BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass); + BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.LocationEvaluator locationEvaluator); } diff --git a/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java b/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java index 36e70b3..ebca7b8 100644 --- a/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java +++ b/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java @@ -37,6 +37,7 @@ public class TechHider { public static final Class blockPosition = Reflection.getClass("{nms.core}.BlockPosition"); private static final Class baseBlockPosition = Reflection.getClass("{nms.core}.BaseBlockPosition"); public static final Reflection.FieldAccessor blockPositionX = Reflection.getField(baseBlockPosition, int.class, 0); + public static final Reflection.FieldAccessor blockPositionY = Reflection.getField(baseBlockPosition, int.class, 1); public static final Reflection.FieldAccessor blockPositionZ = Reflection.getField(baseBlockPosition, int.class, 2); public static final Class iBlockData = Reflection.getClass("{nms.world.level.block.state}.IBlockData"); @@ -53,24 +54,29 @@ public class TechHider { } private final Map, BiFunction> techhiders = new HashMap<>(); - private final BypassEvaluator bypass; + private final LocationEvaluator locationEvaluator; private final Object obfuscationTarget; private final Set obfuscate; + @Deprecated public TechHider(BypassEvaluator bypass, Material obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { - this.bypass = bypass; + this((LocationEvaluator) (player, x, z) -> bypass.bypass(player, ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(z)), obfuscationTarget, obfuscate, hiddenBlockEntities); + } + + public TechHider(LocationEvaluator locationEvaluator, Material obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) { + this.locationEvaluator = locationEvaluator; this.obfuscate = obfuscate; this.obfuscationTarget = getBlockDataByBlock.invoke(getBlockByMaterial.invoke(null, obfuscationTarget)); techhiders.put(blockActionPacket, this::blockActionHider); techhiders.put(blockChangePacket, this::blockChangeHider); techhiders.put(tileEntityDataPacket, this::tileEntityDataHider); - techhiders.put(multiBlockChangePacket,ProtocolWrapper.impl.multiBlockChangeGenerator(this.obfuscationTarget, obfuscate, bypass)); - techhiders.put(ChunkHider.impl.mapChunkPacket(), ChunkHider.impl.chunkHiderGenerator(bypass, BlockIds.impl.materialToId(obfuscationTarget), obfuscate.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet()), hiddenBlockEntities)); + techhiders.put(multiBlockChangePacket, ProtocolWrapper.impl.multiBlockChangeGenerator(this.obfuscationTarget, obfuscate, locationEvaluator)); + techhiders.put(ChunkHider.impl.mapChunkPacket(), ChunkHider.impl.chunkHiderGenerator(locationEvaluator, BlockIds.impl.materialToId(obfuscationTarget), obfuscate.stream().flatMap(m -> BlockIds.impl.materialToAllIds(m).stream()).collect(Collectors.toSet()), hiddenBlockEntities)); if(Core.getVersion() > 12 && Core.getVersion() < 19) { Class blockBreakClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockBreak"); - techhiders.put(blockBreakClass, ProtocolWrapper.impl.blockBreakHiderGenerator(blockBreakClass, this.obfuscationTarget, obfuscate, bypass)); + techhiders.put(blockBreakClass, ProtocolWrapper.impl.blockBreakHiderGenerator(blockBreakClass, this.obfuscationTarget, obfuscate, locationEvaluator)); } if(Core.getVersion() > 8){ @@ -96,22 +102,23 @@ public class TechHider { private static final Reflection.FieldAccessor blockChangePosition = Reflection.getField(blockChangePacket, blockPosition, 0); private static final Reflection.FieldAccessor blockChangeBlockData = Reflection.getField(blockChangePacket, iBlockData, 0); private Object blockChangeHider(Player p, Object packet) { - Object pos = blockChangePosition.get(packet); - if(bypass.bypass(p, ProtocolUtils.posToChunk(blockPositionX.get(pos)), ProtocolUtils.posToChunk(blockPositionZ.get(pos)))) - return packet; - - if(iBlockDataHidden(obfuscate, blockChangeBlockData.get(packet))) { - packet = blockChangeCloner.apply(packet); - blockChangeBlockData.set(packet, obfuscationTarget); + switch (locationEvaluator.checkBlockPos(p, blockChangePosition.get(packet))) { + case SKIP: + return packet; + case CHECK: + if(!iBlockDataHidden(obfuscate, blockChangeBlockData.get(packet))) + return packet; + default: + packet = blockChangeCloner.apply(packet); + blockChangeBlockData.set(packet, obfuscationTarget); + return packet; } - return packet; } private static final Class blockActionPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockAction"); private static final Reflection.FieldAccessor blockActionPosition = Reflection.getField(blockActionPacket, blockPosition, 0); private Object blockActionHider(Player p, Object packet) { - Object pos = blockActionPosition.get(packet); - if(bypass.bypass(p, ProtocolUtils.posToChunk(blockPositionX.get(pos)), ProtocolUtils.posToChunk(blockPositionZ.get(pos)))) + if (locationEvaluator.checkBlockPos(p, blockActionPosition.get(packet)) == State.SKIP) return packet; return null; } @@ -119,16 +126,39 @@ public class TechHider { public static final Class tileEntityDataPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutTileEntityData"); private static final Reflection.FieldAccessor tileEntityDataPosition = Reflection.getField(tileEntityDataPacket, blockPosition, 0); private Object tileEntityDataHider(Player p, Object packet) { - Object pos = tileEntityDataPosition.get(packet); - if(bypass.bypass(p, ProtocolUtils.posToChunk(blockPositionX.get(pos)), ProtocolUtils.posToChunk(blockPositionZ.get(pos)))) - return packet; - - if(ProtocolWrapper.impl.unfilteredTileEntityDataAction(packet)) - return packet; - return null; + switch (locationEvaluator.checkBlockPos(p, tileEntityDataPosition.get(packet))) { + case SKIP: + return packet; + case CHECK: + if(ProtocolWrapper.impl.unfilteredTileEntityDataAction(packet)) + return packet; + default: + return null; + } } + @Deprecated public interface BypassEvaluator { boolean bypass(Player p, int chunkX, int chunkZ); } + + public enum State { + SKIP, + CHECK, + HIDE + } + + public interface LocationEvaluator { + boolean skipChunk(Player player, int x, int z); + default boolean skipChunkSection(Player player, int x, int y, int z) { + return skipChunk(player, x, z); + } + default State check(Player player, int x, int y, int z) { + return skipChunkSection(player, ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(y), ProtocolUtils.posToChunk(z)) ? State.SKIP : State.CHECK; + } + + default State checkBlockPos(Player player, Object pos) { + return check(player, blockPositionX.get(pos), blockPositionY.get(pos), blockPositionZ.get(pos)); + } + } } diff --git a/build.gradle b/build.gradle index 0a88ab2..6f4c1d0 100755 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,6 @@ mainClassName = '' allprojects { repositories { mavenCentral() - jcenter() maven { url = uri("https://repo.codemc.io/repository/maven-snapshots/") @@ -53,14 +52,23 @@ allprojects { maven { url = uri('https://hub.spigotmc.org/nexus/content/repositories/snapshots/') + content { + includeGroup('org.spigotmc') + } } maven { url = uri('https://libraries.minecraft.net') + content { + includeGroup('com.mojang') + } } maven { url = uri('https://repo.viaversion.com') + content { + includeGroup('com.viaversion') + } } } } From e9dc60de38e05e349c61674c1dd8ef3151f104c3 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 10 Mar 2024 19:27:30 +0100 Subject: [PATCH 2/3] Bugfixes, Chunk section skipping --- .../src/de/steamwar/techhider/ChunkHider14.java | 4 ++-- .../src/de/steamwar/techhider/ChunkHider18.java | 11 ++++++++--- .../de/steamwar/techhider/ProtocolWrapper18.java | 2 +- .../de/steamwar/techhider/ProtocolWrapper8.java | 3 ++- .../src/de/steamwar/techhider/ChunkHider9.java | 15 ++++++++++----- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java index 6f779a6..9b2ab0b 100644 --- a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java +++ b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java @@ -27,7 +27,7 @@ import java.util.Set; public class ChunkHider14 extends ChunkHider9 { @Override - protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip) { out.writeShort(in.readShort()); // Block count byte bitsPerBlock = in.readByte(); out.writeByte(bitsPerBlock); @@ -37,6 +37,6 @@ public class ChunkHider14 extends ChunkHider9 { obfuscate = Collections.emptySet(); } - processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock); + processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock, skip); } } diff --git a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java index 2d0b1fe..07d59b2 100644 --- a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java +++ b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java @@ -73,7 +73,7 @@ public class ChunkHider18 implements ChunkHider { int zOffset = 16*chunkZ; for(int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) { int finalYOffset = yOffset; - dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+finalYOffset, z+zOffset), obfuscationTarget, obfuscate, in, out); + dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+finalYOffset, z+zOffset), obfuscationTarget, obfuscate, in, out, locationEvaluator.skipChunkSection(p, chunkX, yOffset/16, chunkZ)); } out.writeBytes(in); // MC appends a 0 byte at the end if there is a full chunk, idk why @@ -95,10 +95,10 @@ public class ChunkHider18 implements ChunkHider { return !hiddenBlockEntities.contains((String) getName.invoke(getKey.invoke(tileEntityTypes, entityType.get(tile)))); } - private void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + private void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip) { out.writeShort(in.readShort()); // Block count - containerWalker(in, out, 15, obfuscationTarget, obfuscate, (paletteTarget, dataArrayLength, bitsPerBlock) -> { + containerWalker(in, out, 15, obfuscationTarget, skip ? Collections.emptySet() : obfuscate, (paletteTarget, dataArrayLength, bitsPerBlock) -> { Set palettedObfuscate; if(bitsPerBlock < 15) { palettedObfuscate = Collections.emptySet(); @@ -107,6 +107,11 @@ public class ChunkHider18 implements ChunkHider { palettedObfuscate = obfuscate; } + if(skip || dataArrayLength == 0) { + out.writeBytes(in, dataArrayLength*8); + return; + } + long[] array = new long[dataArrayLength]; for(int i = 0; i < dataArrayLength; i++) array[i] = in.readLong(); diff --git a/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java b/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java index 9f78b08..d314c2d 100644 --- a/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java +++ b/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java @@ -77,7 +77,7 @@ public class ProtocolWrapper18 implements ProtocolWrapper { newPos[i] = poss.get(i); multiBlockChangePos.set(packet, newPos); - multiBlockChangeBlocks.set(packet, blocks.toArray()); + multiBlockChangeBlocks.set(packet, blocks.toArray(new IBlockData[0])); return packet; }; } diff --git a/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java b/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java index 5b30a6b..ba307d0 100644 --- a/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java +++ b/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java @@ -23,6 +23,7 @@ import com.comphenix.tinyprotocol.Reflection; import org.bukkit.Material; import org.bukkit.entity.Player; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Set; import java.util.function.BiFunction; @@ -67,7 +68,7 @@ public class ProtocolWrapper8 implements ProtocolWrapper { if(blockChangeInfos.isEmpty()) return null; - multiBlockChangeInfos.set(packet, blockChangeInfos.toArray(mbcis)); + multiBlockChangeInfos.set(packet, blockChangeInfos.toArray((Object[])Array.newInstance(multiBlockChangeInfo, 0))); return packet; }; } diff --git a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java index 8f34dbb..bb9bf5b 100644 --- a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java +++ b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java @@ -67,7 +67,7 @@ public class ChunkHider9 extends ChunkHider8 { continue; int yOffset = 16*chunkY; - dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+yOffset, z+zOffset), obfuscationTarget, obfuscate, in, out); + dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+yOffset, z+zOffset), obfuscationTarget, obfuscate, in, out, locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ)); } byte[] data = new byte[out.readableBytes()]; out.readBytes(data); @@ -77,25 +77,30 @@ public class ChunkHider9 extends ChunkHider8 { }; } - protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out) { + protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip) { byte bitsPerBlock = in.readByte(); out.writeByte(bitsPerBlock); - int paletteTarget = ChunkHider.processPalette(obfuscationTarget, obfuscate, in, out); + int paletteTarget = ChunkHider.processPalette(obfuscationTarget, skip ? Collections.emptySet() : obfuscate, in, out); if(bitsPerBlock < 13) { obfuscationTarget = paletteTarget; obfuscate = Collections.emptySet(); } - processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock); + processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock, skip); out.writeBytes(in, 4096); //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048 } - protected void processDataArray(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, int bitsPerBlock) { + protected void processDataArray(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, int bitsPerBlock, boolean skip) { int dataArrayLength = ProtocolUtils.readVarInt(in); ProtocolUtils.writeVarInt(out, dataArrayLength); + if(skip) { + out.writeBytes(in, dataArrayLength*8); + return; + } + VariableValueArray values = new VariableValueArray(bitsPerBlock, dataArrayLength, in); for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { From de43c083169f7940d7251f0faedfb7821d73ecbb Mon Sep 17 00:00:00 2001 From: Lixfel Date: Wed, 13 Mar 2024 13:06:47 +0100 Subject: [PATCH 3/3] Improve performance with blockPrecise toggle --- SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java | 4 ++-- SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java | 7 ++++--- SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java | 6 +++--- SpigotCore_Main/src/de/steamwar/techhider/TechHider.java | 4 ++++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java index 9b2ab0b..9a2d50e 100644 --- a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java +++ b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java @@ -27,7 +27,7 @@ import java.util.Set; public class ChunkHider14 extends ChunkHider9 { @Override - protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip) { + protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip, boolean blockPrecise) { out.writeShort(in.readShort()); // Block count byte bitsPerBlock = in.readByte(); out.writeByte(bitsPerBlock); @@ -37,6 +37,6 @@ public class ChunkHider14 extends ChunkHider9 { obfuscate = Collections.emptySet(); } - processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock, skip); + processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock, skip || (!blockPrecise && bitsPerBlock < 9)); } } diff --git a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java index 07d59b2..774cf2d 100644 --- a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java +++ b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java @@ -73,7 +73,8 @@ public class ChunkHider18 implements ChunkHider { int zOffset = 16*chunkZ; for(int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) { int finalYOffset = yOffset; - dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+finalYOffset, z+zOffset), obfuscationTarget, obfuscate, in, out, locationEvaluator.skipChunkSection(p, chunkX, yOffset/16, chunkZ)); + int chunkY = yOffset/16; + dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+finalYOffset, z+zOffset), obfuscationTarget, obfuscate, in, out, locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ), locationEvaluator.blockPrecise(p, chunkX, chunkY, chunkZ)); } out.writeBytes(in); // MC appends a 0 byte at the end if there is a full chunk, idk why @@ -95,7 +96,7 @@ public class ChunkHider18 implements ChunkHider { return !hiddenBlockEntities.contains((String) getName.invoke(getKey.invoke(tileEntityTypes, entityType.get(tile)))); } - private void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip) { + private void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip, boolean blockPrecise) { out.writeShort(in.readShort()); // Block count containerWalker(in, out, 15, obfuscationTarget, skip ? Collections.emptySet() : obfuscate, (paletteTarget, dataArrayLength, bitsPerBlock) -> { @@ -107,7 +108,7 @@ public class ChunkHider18 implements ChunkHider { palettedObfuscate = obfuscate; } - if(skip || dataArrayLength == 0) { + if(skip || dataArrayLength == 0 || (!blockPrecise && bitsPerBlock < 15)) { out.writeBytes(in, dataArrayLength*8); return; } diff --git a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java index bb9bf5b..2e413db 100644 --- a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java +++ b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java @@ -67,7 +67,7 @@ public class ChunkHider9 extends ChunkHider8 { continue; int yOffset = 16*chunkY; - dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+yOffset, z+zOffset), obfuscationTarget, obfuscate, in, out, locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ)); + dataHider((x, y, z) -> locationEvaluator.check(p, x+xOffset, y+yOffset, z+zOffset), obfuscationTarget, obfuscate, in, out, locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ), locationEvaluator.blockPrecise(p, chunkX, chunkY, chunkZ)); } byte[] data = new byte[out.readableBytes()]; out.readBytes(data); @@ -77,7 +77,7 @@ public class ChunkHider9 extends ChunkHider8 { }; } - protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip) { + protected void dataHider(PosEvaluator locationEvaluator, int obfuscationTarget, Set obfuscate, ByteBuf in, ByteBuf out, boolean skip, boolean blockPrecise) { byte bitsPerBlock = in.readByte(); out.writeByte(bitsPerBlock); @@ -87,7 +87,7 @@ public class ChunkHider9 extends ChunkHider8 { obfuscate = Collections.emptySet(); } - processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock, skip); + processDataArray(locationEvaluator, obfuscationTarget, obfuscate, in, out, bitsPerBlock, skip || (!blockPrecise && bitsPerBlock < 9)); out.writeBytes(in, 4096); //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048 } diff --git a/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java b/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java index ebca7b8..24fbb27 100644 --- a/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java +++ b/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java @@ -160,5 +160,9 @@ public class TechHider { default State checkBlockPos(Player player, Object pos) { return check(player, blockPositionX.get(pos), blockPositionY.get(pos), blockPositionZ.get(pos)); } + + default boolean blockPrecise(Player player, int x, int y, int z) { + return false; + } } }