forked from SteamWar/SteamWar
Finish initial implementation of logic
This commit is contained in:
@@ -56,11 +56,19 @@ public abstract class ChunkHider {
|
|||||||
|
|
||||||
private final int SECTION_SPAN_SIZE = 16;
|
private final int SECTION_SPAN_SIZE = 16;
|
||||||
private final byte BIT_PER_BLOCK_INDIRECTION_LIMIT = 8;
|
private final byte BIT_PER_BLOCK_INDIRECTION_LIMIT = 8;
|
||||||
|
|
||||||
private final int BLOCKS_PER_SECTION = 4096;
|
private final int BLOCKS_PER_SECTION = 4096;
|
||||||
|
private final int BIOMES_PER_SECTION = 64;
|
||||||
|
|
||||||
private final byte BITS_PER_LONG = 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 entriesPerLong = BITS_PER_LONG / bitsPerEntry;
|
||||||
int dataLengthAsLongCount = (entryCount + entriesPerLong - 1) / entriesPerLong;
|
int dataLengthAsLongCount = (entryCount + entriesPerLong - 1) / entriesPerLong;
|
||||||
|
|
||||||
@@ -73,7 +81,7 @@ public abstract class ChunkHider {
|
|||||||
return dataArray;
|
return dataArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientboundLevelChunkWithLightPacket chunkHiderGenerator(Player player, ClientboundLevelChunkWithLightPacket packet) {
|
public ClientboundLevelChunkWithLightPacket processLevelChunkWithLightPacket(Player player, ClientboundLevelChunkWithLightPacket packet) {
|
||||||
int chunkX = packet.getX();
|
int chunkX = packet.getX();
|
||||||
int chunkZ = packet.getZ();
|
int chunkZ = packet.getZ();
|
||||||
ClientboundLevelChunkPacketData chunkData = packet.getChunkData();
|
ClientboundLevelChunkPacketData chunkData = packet.getChunkData();
|
||||||
@@ -85,15 +93,16 @@ public abstract class ChunkHider {
|
|||||||
int worldMaxHeight = player.getWorld().getMaxHeight();
|
int worldMaxHeight = player.getWorld().getMaxHeight();
|
||||||
|
|
||||||
for (int yOffset = worldMinHeight; yOffset < worldMaxHeight; yOffset += SECTION_SPAN_SIZE) {
|
for (int yOffset = worldMinHeight; yOffset < worldMaxHeight; yOffset += SECTION_SPAN_SIZE) {
|
||||||
// TODO make configurable
|
|
||||||
int blockIdUsedForHiding = 121;
|
|
||||||
|
|
||||||
short blockCount = in.readShort();
|
short blockCount = in.readShort();
|
||||||
|
|
||||||
byte bitsPerBlock = in.readByte();
|
byte bitsPerBlock = in.readByte();
|
||||||
|
|
||||||
if(bitsPerBlock == 0) {
|
if(bitsPerBlock == 0) {
|
||||||
int sectionBlockId = ProtocolUtils.readVarInt(in);
|
int sectionBlockId = ProtocolUtils.readVarInt(in);
|
||||||
|
|
||||||
|
out.writeShort(blockCount);
|
||||||
|
out.writeByte(bitsPerBlock);
|
||||||
|
ProtocolUtils.writeVarInt(out, sectionBlockId);
|
||||||
}
|
}
|
||||||
else if (bitsPerBlock <= BIT_PER_BLOCK_INDIRECTION_LIMIT) {
|
else if (bitsPerBlock <= BIT_PER_BLOCK_INDIRECTION_LIMIT) {
|
||||||
int palletLength = ProtocolUtils.readVarInt(in);
|
int palletLength = ProtocolUtils.readVarInt(in);
|
||||||
@@ -205,6 +214,7 @@ public abstract class ChunkHider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyOverSectionBiomeData(in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in.readableBytes() != 0) {
|
if (in.readableBytes() != 0) {
|
||||||
@@ -258,159 +268,34 @@ public abstract class ChunkHider {
|
|||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void biomes(SectionHider section) {
|
private void copyOverSectionBiomeData(ByteBuf oldData, ByteBuf newData){
|
||||||
section.copyBitsPerBlock();
|
short bitsPerBiome = oldData.readShort();
|
||||||
if (section.getBitsPerBlock() == 0) {
|
newData.writeShort(bitsPerBiome);
|
||||||
section.copyVarInt();
|
|
||||||
} else if (section.getBitsPerBlock() < 6) {
|
if(bitsPerBiome == 0) {
|
||||||
section.skipPalette();
|
int sectionBiomeId = ProtocolUtils.readVarInt(oldData);
|
||||||
section.skipNewDataArray(64);
|
ProtocolUtils.writeVarInt(newData, sectionBiomeId);
|
||||||
} else {
|
|
||||||
// Direct (global) biome IDs – no palette present
|
|
||||||
section.skipNewDataArray(64);
|
|
||||||
}
|
}
|
||||||
}
|
else if(bitsPerBiome <= BIT_PER_BLOCK_INDIRECTION_LIMIT) {
|
||||||
|
int palletLength = ProtocolUtils.readVarInt(oldData);
|
||||||
|
ProtocolUtils.writeVarInt(newData, palletLength);
|
||||||
|
|
||||||
@Getter
|
for(int i = 0; i < palletLength; i++) {
|
||||||
class SectionHider {
|
int palletEntry = ProtocolUtils.readVarInt(oldData);
|
||||||
private final Player player;
|
ProtocolUtils.writeVarInt(newData, palletEntry);
|
||||||
private final ByteBuf in;
|
}
|
||||||
private final ByteBuf out;
|
|
||||||
|
|
||||||
private final int chunkX;
|
long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION);
|
||||||
private final int chunkY;
|
for(long rawDataSegment : rawData ) {
|
||||||
private final int chunkZ;
|
newData.writeLong(rawDataSegment);
|
||||||
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<Integer> 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();
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
public boolean blockPrecise() {
|
long[] rawData = readSectionDataFromBuffer(oldData, bitsPerBiome, BIOMES_PER_SECTION);
|
||||||
return techHider.getLocationEvaluator().blockPrecise(player, chunkX, chunkY, chunkZ);
|
for(long rawDataSegment : rawData ) {
|
||||||
}
|
newData.writeLong(rawDataSegment);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,12 +186,30 @@ public abstract class TechHider {
|
|||||||
|
|
||||||
private final Block blockUsedForObfuscation;
|
private final Block blockUsedForObfuscation;
|
||||||
private final BlockState blockStateUsedForObfuscation;
|
private final BlockState blockStateUsedForObfuscation;
|
||||||
|
private ChunkHider chunkHider;
|
||||||
|
|
||||||
// TODO handle packet bundle
|
// TODO handle packet bundle
|
||||||
public TechHider(Plugin plugin, Block blockUsedForObfuscation) {
|
public TechHider(Plugin plugin, Block blockUsedForObfuscation) {
|
||||||
this.blockUsedForObfuscation = blockUsedForObfuscation;
|
this.blockUsedForObfuscation = blockUsedForObfuscation;
|
||||||
this.blockStateUsedForObfuscation = blockUsedForObfuscation.defaultBlockState();
|
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(
|
this.bypassingPackets = new HashSet<>(List.of(
|
||||||
// --- 5.1.x Login Protocol ---
|
// --- 5.1.x Login Protocol ---
|
||||||
ClientboundLoginDisconnectPacket.class, // 5.1.1 Disconnect
|
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) {
|
private ClientboundLevelChunkWithLightPacket processChunkWithLight(Player p, ClientboundLevelChunkWithLightPacket packet) {
|
||||||
return chunkHider.processLevelChunkWithLightPacket(p, blockEntitiesToHide, this::isPlayerPrivilegedToAccessBlockPos, blockToObfuscateTo, blockIdsToObfuscate, packet);
|
return chunkHider.processLevelChunkWithLightPacket(p, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Packet<? extends PacketListener> processContainerPacket(Player player, int containerId, Packet<? extends PacketListener> packet) {
|
private Packet<? extends PacketListener> processContainerPacket(Player player, int containerId, Packet<? extends PacketListener> packet) {
|
||||||
|
|||||||
Reference in New Issue
Block a user