diff --git a/SpigotCore_14/build.gradle b/SpigotCore_14/build.gradle
index 688968a..af58ea6 100644
--- a/SpigotCore_14/build.gradle
+++ b/SpigotCore_14/build.gradle
@@ -44,6 +44,8 @@ sourceSets {
dependencies {
implementation project(":SpigotCore_Main")
+ compileOnly project(":SpigotCore_8")
+ compileOnly project(":SpigotCore_9")
compileOnly files("${project.rootDir}/lib/Spigot-1.14.jar")
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
diff --git a/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java b/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
new file mode 100644
index 0000000..1a946ef
--- /dev/null
+++ b/SpigotCore_14/src/de/steamwar/techhider/BlockIds14.java
@@ -0,0 +1,52 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import net.minecraft.server.v1_14_R1.*;
+import org.bukkit.Material;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class BlockIds14 implements BlockIds {
+ @Override
+ public int materialToId(Material material) {
+ return Block.getCombinedId(IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getBlockData());
+ }
+
+ @Override
+ public Set materialToAllIds(Material material) {
+ Set ids = new HashSet<>();
+ for(IBlockData data : IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getStates().a()) {
+ ids.add(Block.getCombinedId(data));
+ }
+
+ if(material == Material.WATER){
+ Fluid water = FluidTypes.WATER.a(false);
+ for(IBlockData data : Block.REGISTRY_ID){
+ if(data.p() == water){
+ ids.add(Block.getCombinedId(data));
+ }
+ }
+ }
+
+ return ids;
+ }
+}
diff --git a/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java
new file mode 100644
index 0000000..eae64df
--- /dev/null
+++ b/SpigotCore_14/src/de/steamwar/techhider/ChunkHider14.java
@@ -0,0 +1,141 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+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.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;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+ }
+}
diff --git a/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java b/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java
new file mode 100644
index 0000000..bb52f52
--- /dev/null
+++ b/SpigotCore_14/src/de/steamwar/techhider/ProtocolWrapper14.java
@@ -0,0 +1,50 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.UnaryOperator;
+
+public class ProtocolWrapper14 extends ProtocolWrapper8 {
+
+ @Override
+ public BiFunction blockBreakHiderGenerator(Class> blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) {
+ 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(ProtocolWrapper.impl.iBlockDataHidden(obfuscate, blockBreakBlockData.get(packet))){
+ packet = blockBreakCloner.apply(packet);
+ blockBreakBlockData.set(packet, obfuscationTarget);
+ }
+ return packet;
+ };
+ }
+}
diff --git a/SpigotCore_15/src/de/steamwar/techhider/BlockIds15.java b/SpigotCore_15/src/de/steamwar/techhider/BlockIds15.java
new file mode 100644
index 0000000..15e7c4d
--- /dev/null
+++ b/SpigotCore_15/src/de/steamwar/techhider/BlockIds15.java
@@ -0,0 +1,52 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import net.minecraft.server.v1_15_R1.*;
+import org.bukkit.Material;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class BlockIds15 implements BlockIds {
+ @Override
+ public int materialToId(Material material) {
+ return Block.getCombinedId(IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getBlockData());
+ }
+
+ @Override
+ public Set materialToAllIds(Material material) {
+ Set ids = new HashSet<>();
+ for(IBlockData data : IRegistry.BLOCK.get(new MinecraftKey(material.name().toLowerCase())).getStates().a()) {
+ ids.add(Block.getCombinedId(data));
+ }
+
+ if(material == Material.WATER){
+ Fluid water = FluidTypes.WATER.a(false);
+ for(IBlockData data : Block.REGISTRY_ID){
+ if(data.getFluid() == water){
+ ids.add(Block.getCombinedId(data));
+ }
+ }
+ }
+
+ return ids;
+ }
+}
diff --git a/SpigotCore_18/build.gradle b/SpigotCore_18/build.gradle
index 5181c28..5ff99a8 100644
--- a/SpigotCore_18/build.gradle
+++ b/SpigotCore_18/build.gradle
@@ -49,5 +49,8 @@ dependencies {
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
compileOnly 'org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT'
+ compileOnly 'com.mojang:datafixerupper:4.0.26'
+ compileOnly 'io.netty:netty-all:4.1.68.Final'
+ compileOnly 'com.mojang:authlib:1.5.25'
compileOnly files("${project.rootDir}/lib/Spigot-1.18.jar")
}
diff --git a/SpigotCore_18/src/de/steamwar/techhider/BlockIds18.java b/SpigotCore_18/src/de/steamwar/techhider/BlockIds18.java
new file mode 100644
index 0000000..13cf029
--- /dev/null
+++ b/SpigotCore_18/src/de/steamwar/techhider/BlockIds18.java
@@ -0,0 +1,57 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import net.minecraft.core.IRegistry;
+import net.minecraft.resources.MinecraftKey;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.IBlockData;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.level.material.FluidTypes;
+import org.bukkit.Material;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class BlockIds18 implements BlockIds {
+ @Override
+ public int materialToId(Material material) {
+ return Block.i(IRegistry.U.a(new MinecraftKey(material.name().toLowerCase())).n());
+ }
+
+ @Override
+ public Set materialToAllIds(Material material) {
+ Set ids = new HashSet<>();
+ for(IBlockData data : IRegistry.U.a(new MinecraftKey(material.name().toLowerCase())).m().a()){
+ ids.add(Block.i(data));
+ }
+
+ if(material == Material.WATER){
+ Fluid water = FluidTypes.c.h();
+ for(IBlockData data : Block.o) {
+ if(data.o() == water) {
+ ids.add(Block.i(data));
+ }
+ }
+ }
+
+ return ids;
+ }
+}
diff --git a/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java
new file mode 100644
index 0000000..53dc78f
--- /dev/null
+++ b/SpigotCore_18/src/de/steamwar/techhider/ChunkHider18.java
@@ -0,0 +1,154 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import net.minecraft.core.IRegistry;
+import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
+import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
+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.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;
+
+public class ChunkHider18 implements ChunkHider {
+ @Override
+ public Class> mapChunkPacket() {
+ return ClientboundLevelChunkWithLightPacket.class;
+ }
+
+ 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 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);
+ public static final Class> tileEntity = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$a");
+ protected static final Reflection.FieldAccessor entityType = Reflection.getField(tileEntity, TileEntityTypes.class, 0);
+
+ @Override
+ public BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) {
+ return (p, packet) -> {
+ if(bypass.bypass(p, chunkX.get(packet), chunkZ.get(packet)))
+ return packet;
+
+ packet = chunkPacketCloner.apply(packet);
+ Object data = chunkDataCloner.apply(chunkData.get(packet));
+
+ tileEntities.set(data, ((List>)tileEntities.get(data)).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));
+
+ chunkData.set(packet, data);
+ return packet;
+ };
+ }
+
+ protected boolean tileEntityVisible(Set hiddenBlockEntities, Object tile) {
+ return !hiddenBlockEntities.contains(IRegistry.aa.b(entityType.get(tile)).a());
+ }
+
+ private byte[] dataHider(int obfuscationTarget, Set obfuscate, byte[] data, int sections) {
+ ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100);
+ int i = 0;
+
+ while(sections-- > 0) {
+ buffer.writeBytes(data, i, 2); // Block count
+ i += 2;
+
+ 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);
+
+ for (int pos = 0; pos < 4096; pos++) {
+ if (obfuscate.contains(values.a(pos))) {
+ values.b(pos, obfuscationTarget);
+ }
+ }
+
+ 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;
+ }
+
+ private int containerWalker(byte[] data, ByteBuf buffer, int i, int globalPalette, IntFunction palette, TriConsumer dataArray) {
+ byte bitsPerBlock = data[i++];
+ buffer.writeByte(bitsPerBlock);
+
+ if(bitsPerBlock == 0) {
+ int paletteValue = ProtocolUtils.readVarInt(data, i);
+ i += ProtocolUtils.readVarIntLength(data, i);
+ buffer.writeBytes(ProtocolUtils.writeVarInt(palette.apply(paletteValue)));
+ }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)));
+ }
+ }
+
+ 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;
+ }
+
+ private interface TriConsumer {
+ void accept(X x, Y y, Z z);
+ }
+}
diff --git a/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java b/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java
new file mode 100644
index 0000000..7edbd8d
--- /dev/null
+++ b/SpigotCore_18/src/de/steamwar/techhider/ProtocolWrapper18.java
@@ -0,0 +1,77 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import net.minecraft.core.IRegistry;
+import net.minecraft.core.SectionPosition;
+import net.minecraft.network.protocol.game.PacketPlayOutBlockBreak;
+import net.minecraft.world.level.block.entity.TileEntityTypes;
+import net.minecraft.world.level.block.state.IBlockData;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+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 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) {
+ return (p, packet) -> {
+ Object chunkCoords = multiBlockChangeChunk.get(packet);
+ if(bypass.bypass(p, TechHider.blockPositionX.get(chunkCoords), TechHider.blockPositionZ.get(chunkCoords)))
+ return packet;
+
+ packet = TechHider.multiBlockChangeCloner.apply(packet);
+ multiBlockChangeBlocks.set(packet, iBlockDataArrayCloner.apply(multiBlockChangeBlocks.get(packet), block -> ProtocolWrapper.impl.iBlockDataHidden(obfuscate, block) ? obfuscationTarget : block));
+ return packet;
+ };
+ }
+
+ private static final Reflection.FieldAccessor tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, TileEntityTypes.class, 0);
+ @Override
+ public boolean unfilteredTileEntityDataAction(Object packet) {
+ return tileEntityType.get(packet) != TileEntityTypes.h;
+ }
+
+ @Override
+ public BiFunction blockBreakHiderGenerator(Class> blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) {
+ 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(!ProtocolWrapper.impl.iBlockDataHidden(obfuscate, breakPacket.c()))
+ return packet;
+
+ return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) obfuscationTarget, breakPacket.d(), breakPacket.a());
+ };
+ }
+
+ @Override
+ public boolean iBlockDataHidden(Set obfuscate, Object iBlockData) {
+ return obfuscate.contains(Material.getMaterial(IRegistry.U.b(((IBlockData) iBlockData).b()).a().toUpperCase()));
+ }
+}
diff --git a/SpigotCore_19/build.gradle b/SpigotCore_19/build.gradle
index c7b9f98..e4b4b5c 100644
--- a/SpigotCore_19/build.gradle
+++ b/SpigotCore_19/build.gradle
@@ -45,10 +45,12 @@ sourceSets {
dependencies {
implementation project(":SpigotCore_Main")
implementation project(":SpigotCore_14")
+ compileOnly project(":SpigotCore_18")
compileOnly files("${project.rootDir}/lib/WorldEdit-1.15.jar")
compileOnly 'org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT'
compileOnly 'com.mojang:brigadier:1.0.18'
+ compileOnly 'com.mojang:datafixerupper:4.0.26'
compileOnly files("${project.rootDir}/lib/Spigot-1.19.jar")
}
diff --git a/SpigotCore_19/src/de/steamwar/techhider/BlockIds19.java b/SpigotCore_19/src/de/steamwar/techhider/BlockIds19.java
new file mode 100644
index 0000000..e1e0b54
--- /dev/null
+++ b/SpigotCore_19/src/de/steamwar/techhider/BlockIds19.java
@@ -0,0 +1,57 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import net.minecraft.core.IRegistry;
+import net.minecraft.resources.MinecraftKey;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.IBlockData;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.level.material.FluidTypes;
+import org.bukkit.Material;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class BlockIds19 implements BlockIds {
+ @Override
+ public int materialToId(Material material) {
+ return Block.i(IRegistry.V.a(new MinecraftKey(material.name().toLowerCase())).m());
+ }
+
+ @Override
+ public Set materialToAllIds(Material material) {
+ Set ids = new HashSet<>();
+ for(IBlockData data : IRegistry.V.a(new MinecraftKey(material.name().toLowerCase())).k().a()){
+ ids.add(Block.i(data));
+ }
+
+ if(material == Material.WATER){
+ Fluid water = FluidTypes.c.h();
+ for(IBlockData data : Block.o) {
+ if(data.p() == water) {
+ ids.add(Block.i(data));
+ }
+ }
+ }
+
+ return ids;
+ }
+}
diff --git a/SpigotCore_19/src/de/steamwar/techhider/ChunkHider19.java b/SpigotCore_19/src/de/steamwar/techhider/ChunkHider19.java
new file mode 100644
index 0000000..0ebba1c
--- /dev/null
+++ b/SpigotCore_19/src/de/steamwar/techhider/ChunkHider19.java
@@ -0,0 +1,31 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import net.minecraft.core.IRegistry;
+
+import java.util.Set;
+
+public class ChunkHider19 extends ChunkHider18 {
+ @Override
+ protected boolean tileEntityVisible(Set hiddenBlockEntities, Object tile) {
+ return !hiddenBlockEntities.contains(IRegistry.ab.b(entityType.get(tile)).a());
+ }
+}
diff --git a/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java b/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java
new file mode 100644
index 0000000..240f854
--- /dev/null
+++ b/SpigotCore_19/src/de/steamwar/techhider/ProtocolWrapper19.java
@@ -0,0 +1,67 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import net.minecraft.core.IRegistry;
+import net.minecraft.core.SectionPosition;
+import net.minecraft.world.level.block.entity.TileEntityTypes;
+import net.minecraft.world.level.block.state.IBlockData;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.UnaryOperator;
+
+public class ProtocolWrapper19 implements ProtocolWrapper {
+
+ private static final Reflection.FieldAccessor multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPosition.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) {
+ return (p, packet) -> {
+ Object chunkCoords = multiBlockChangeChunk.get(packet);
+ if(bypass.bypass(p, TechHider.blockPositionX.get(chunkCoords), TechHider.blockPositionZ.get(chunkCoords)))
+ return packet;
+
+ packet = TechHider.multiBlockChangeCloner.apply(packet);
+ multiBlockChangeBlocks.set(packet, iBlockDataArrayCloner.apply(multiBlockChangeBlocks.get(packet), block -> ProtocolWrapper.impl.iBlockDataHidden(obfuscate, block) ? obfuscationTarget : block));
+ return packet;
+ };
+ }
+
+ private static final Reflection.FieldAccessor tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, TileEntityTypes.class, 0);
+ @Override
+ public boolean unfilteredTileEntityDataAction(Object packet) {
+ return tileEntityType.get(packet) != TileEntityTypes.h;
+ }
+
+ @Override
+ public BiFunction blockBreakHiderGenerator(Class> blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) {
+ return null;
+ }
+
+ @Override
+ public boolean iBlockDataHidden(Set obfuscate, Object iBlockData) {
+ return obfuscate.contains(Material.getMaterial(IRegistry.V.b(((IBlockData) iBlockData).b()).a().toUpperCase()));
+ }
+}
diff --git a/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java b/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
new file mode 100644
index 0000000..538e8db
--- /dev/null
+++ b/SpigotCore_8/src/de/steamwar/techhider/BlockIds8.java
@@ -0,0 +1,38 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import org.bukkit.Material;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class BlockIds8 implements BlockIds {
+ @Override
+ @SuppressWarnings("deprecation")
+ public int materialToId(Material material) {
+ return material.getId() << 4;
+ }
+
+ @Override
+ public Set materialToAllIds(Material material) {
+ return Collections.singleton(materialToId(material));
+ }
+}
diff --git a/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java b/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java
new file mode 100644
index 0000000..3cc0d36
--- /dev/null
+++ b/SpigotCore_8/src/de/steamwar/techhider/ChunkHider8.java
@@ -0,0 +1,40 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import org.bukkit.entity.Player;
+
+import java.util.Set;
+import java.util.function.BiFunction;
+
+public class ChunkHider8 implements ChunkHider {
+
+ protected static final Class> mapChunkPacket = Reflection.getClass("{nms}.PacketPlayOutMapChunk");
+ @Override
+ public Class> mapChunkPacket() {
+ return mapChunkPacket;
+ }
+
+ @Override
+ public BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) {
+ return null;
+ }
+}
diff --git a/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java b/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java
new file mode 100644
index 0000000..abc9e61
--- /dev/null
+++ b/SpigotCore_8/src/de/steamwar/techhider/ProtocolWrapper8.java
@@ -0,0 +1,76 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+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");
+ private static final Reflection.FieldAccessor> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, chunkCoordinateIntPair, 0);
+ private static final Reflection.FieldAccessor chunkCoordinateX = Reflection.getField(chunkCoordinateIntPair, int.class, 0);
+ 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) {
+ return (p, packet) -> {
+ Object chunkCoords = multiBlockChangeChunk.get(packet);
+ if(bypass.bypass(p, chunkCoordinateX.get(chunkCoords), chunkCoordinateZ.get(chunkCoords)))
+ return packet;
+
+ Object modpacket = TechHider.multiBlockChangeCloner.apply(packet);
+ multiBlockChangeInfos.set(modpacket, multiBlockChangeInfoArrayCloner.apply(multiBlockChangeInfos.get(modpacket), mbci -> {
+ if(ProtocolWrapper.impl.iBlockDataHidden(obfuscate, multiBlockChangeInfoBlock.get(mbci)))
+ return multiBlockChangeInfoConstructor.invoke(modpacket, multiBlockChangeInfoPos.get(mbci), obfuscationTarget);
+ return mbci;
+ }));
+ return modpacket;
+ };
+ }
+
+ private static final Reflection.FieldAccessor tileEntityDataAction = Reflection.getField(TechHider.tileEntityDataPacket, int.class, 0);
+ @Override
+ public boolean unfilteredTileEntityDataAction(Object packet) {
+ return tileEntityDataAction.get(packet) != 9;
+ }
+
+ @Override
+ public BiFunction blockBreakHiderGenerator(Class> blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass) {
+ return null;
+ }
+
+ private static final Reflection.MethodInvoker getBlockByBlockData = Reflection.getTypedMethod(TechHider.iBlockData, null, TechHider.block);
+ private static final Reflection.MethodInvoker getMaterialByBlock = Reflection.getTypedMethod(TechHider.craftMagicNumbers, "getMaterial", Material.class, TechHider.block);
+ @Override
+ public boolean iBlockDataHidden(Set obfuscate, Object iBlockData) {
+ return obfuscate.contains((Material) getMaterialByBlock.invoke(null, getBlockByBlockData.invoke(iBlockData)));
+ }
+}
diff --git a/SpigotCore_9/build.gradle b/SpigotCore_9/build.gradle
index 064f759..6250558 100644
--- a/SpigotCore_9/build.gradle
+++ b/SpigotCore_9/build.gradle
@@ -44,6 +44,7 @@ sourceSets {
dependencies {
implementation project(":SpigotCore_Main")
+ compileOnly project(":SpigotCore_8")
compileOnly files("${project.rootDir}/lib/Spigot-1.9.jar")
}
diff --git a/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java
new file mode 100644
index 0000000..0272dd6
--- /dev/null
+++ b/SpigotCore_9/src/de/steamwar/techhider/ChunkHider9.java
@@ -0,0 +1,108 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+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 {
+
+ private static final UnaryOperator mapChunkCloner = ProtocolUtils.shallowCloneGenerator(mapChunkPacket);
+
+ private static final Reflection.FieldAccessor mapChunkX = Reflection.getField(mapChunkPacket, int.class, 0);
+ private static final Reflection.FieldAccessor mapChunkZ = Reflection.getField(mapChunkPacket, int.class, 1);
+ private static final Reflection.FieldAccessor mapChunkBitMask = Reflection.getField(mapChunkPacket, int.class, 2);
+ private static final Reflection.FieldAccessor mapChunkBlockEntities = Reflection.getField(mapChunkPacket, List.class, 0);
+ private static final Reflection.FieldAccessor mapChunkData = Reflection.getField(mapChunkPacket, byte[].class, 0);
+
+ private static final Class> nbtTagCompound = Reflection.getClass("{nms.nbt}.NBTTagCompound");
+ 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) {
+ return (p, packet) -> {
+ if(bypass.bypass(p, mapChunkX.get(packet), mapChunkZ.get(packet)))
+ return packet;
+
+ packet = mapChunkCloner.apply(packet);
+ mapChunkBlockEntities.set(packet, ((List>)mapChunkBlockEntities.get(packet)).stream().filter(
+ nbttag -> !hiddenBlockEntities.contains((String) nbtTagGetString.invoke(nbttag, "id"))
+ ).collect(Collectors.toList()));
+
+ byte[] data = dataHider(obfuscationTarget, obfuscate, mapChunkData.get(packet), mapChunkBitMask.get(packet));
+ 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;
+
+ 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
+ }
+
+ data = new byte[buffer.readableBytes()];
+ buffer.readBytes(data);
+ return data;
+ }
+}
diff --git a/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java b/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
new file mode 100644
index 0000000..8e129a1
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/techhider/BlockIds.java
@@ -0,0 +1,33 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import de.steamwar.core.Core;
+import de.steamwar.core.VersionDependent;
+import org.bukkit.Material;
+
+import java.util.Set;
+
+public interface BlockIds {
+ BlockIds impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+ int materialToId(Material material);
+ Set materialToAllIds(Material material);
+}
diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java b/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java
new file mode 100644
index 0000000..b87d83d
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/techhider/ChunkHider.java
@@ -0,0 +1,34 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2022 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import de.steamwar.core.Core;
+import de.steamwar.core.VersionDependent;
+import org.bukkit.entity.Player;
+
+import java.util.Set;
+import java.util.function.BiFunction;
+
+public interface ChunkHider {
+ ChunkHider impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+ Class> mapChunkPacket();
+ BiFunction chunkHiderGenerator(TechHider.BypassEvaluator bypass, int obfuscationTarget, Set obfuscate, Set hiddenBlockEntities);
+}
diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java
new file mode 100644
index 0000000..1fc9e31
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java
@@ -0,0 +1,164 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2022 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.comphenix.tinyprotocol.TinyProtocol;
+import com.google.common.primitives.Bytes;
+import org.bukkit.Bukkit;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.UnaryOperator;
+
+public class ProtocolUtils {
+ private ProtocolUtils() {}
+
+ public static void broadcastPacket(Object packet) {
+ Bukkit.getOnlinePlayers().stream().map(TinyProtocol.instance::getChannel).filter(TinyProtocol.instance::hasInjected).forEach(channel -> TinyProtocol.instance.sendPacket(channel, packet));
+ }
+
+ public static BiFunction, Object> arrayCloneGenerator(Class> elementClass) {
+ return (array, worker) -> {
+ int length = Array.getLength(array);
+ Object result = Array.newInstance(elementClass, length);
+
+ for(int i = 0; i < length; i++)
+ Array.set(result, i, worker.apply(Array.get(array, i)));
+
+ return result;
+ };
+ }
+
+ public static UnaryOperator shallowCloneGenerator(Class> clazz) {
+ BiConsumer filler = shallowFill(clazz);
+
+ return source -> {
+ Object clone = Reflection.newInstance(clazz);
+ filler.accept(source, clone);
+ return clone;
+ };
+ }
+
+ private static BiConsumer shallowFill(Class> clazz) {
+ if(clazz == null)
+ return (source, clone) -> {};
+
+ BiConsumer superFiller = shallowFill(clazz.getSuperclass());
+
+ Field[] fds = clazz.getDeclaredFields();
+ List fields = new ArrayList<>();
+ for(Field field : fds) {
+ if (Modifier.isStatic(field.getModifiers()))
+ continue;
+
+ field.setAccessible(true);
+ fields.add(field);
+ }
+
+ return (source, clone) -> {
+ superFiller.accept(source, clone);
+ try {
+ for(Field field : fields) {
+ field.set(clone, field.get(source));
+ }
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Could not set field", e);
+ }
+
+ };
+ }
+
+ public static int posToChunk(int c){
+ int chunk = c / 16;
+ if(c<0)
+ chunk--;
+ return chunk;
+ }
+
+ public static int readVarInt(byte[] array, int startPos) {
+ int numRead = 0;
+ int result = 0;
+ byte read;
+ do {
+ read = array[startPos + numRead];
+ int value = (read & 0b01111111);
+ result |= (value << (7 * numRead));
+
+ numRead++;
+ if (numRead > 5) {
+ break;
+ }
+ } while ((read & 0b10000000) != 0);
+
+ return result;
+ }
+
+ public static int readVarIntLength(byte[] array, int startPos) {
+ int numRead = 0;
+ byte read;
+ do {
+ read = array[startPos + numRead];
+ numRead++;
+ if (numRead > 5) {
+ break;
+ }
+ } while ((read & 0b10000000) != 0);
+
+ return numRead;
+ }
+
+ public static byte[] writeVarInt(int value) {
+ List buffer = new ArrayList<>(5);
+ do {
+ byte temp = (byte)(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;
+ }
+ buffer.add(temp);
+ } while (value != 0);
+ return Bytes.toArray(buffer);
+ }
+
+ public static class ChunkPos{
+ final int x;
+ final int z;
+
+ public ChunkPos(int x, int z){
+ this.x = x;
+ this.z = z;
+ }
+
+ public final int x(){
+ return x;
+ }
+
+ public final int z(){
+ return z;
+ }
+ }
+}
diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java
new file mode 100644
index 0000000..cc95e03
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolWrapper.java
@@ -0,0 +1,41 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import de.steamwar.core.Core;
+import de.steamwar.core.VersionDependent;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.Set;
+import java.util.function.BiFunction;
+
+public interface ProtocolWrapper {
+ ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
+
+
+ boolean unfilteredTileEntityDataAction(Object packet);
+
+ BiFunction blockBreakHiderGenerator(Class> blockBreakPacket, Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass);
+
+ BiFunction multiBlockChangeGenerator(Object obfuscationTarget, Set obfuscate, TechHider.BypassEvaluator bypass);
+
+ boolean iBlockDataHidden(Set obfuscate, Object iBlockData);
+}
diff --git a/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java b/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
new file mode 100644
index 0000000..7f089e0
--- /dev/null
+++ b/SpigotCore_Main/src/de/steamwar/techhider/TechHider.java
@@ -0,0 +1,128 @@
+/*
+ This file is a part of the SteamWar software.
+
+ Copyright (C) 2021 SteamWar.de-Serverteam
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+ */
+
+package de.steamwar.techhider;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.core.Core;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+
+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 blockPositionZ = Reflection.getField(baseBlockPosition, int.class, 2);
+
+ public static final Class> iBlockData = Reflection.getClass("{nms.world.level.block.state}.IBlockData");
+ public static final Class> block = Reflection.getClass("{nms.world.level.block}.Block");
+ private static final Reflection.MethodInvoker getBlockDataByBlock = Reflection.getTypedMethod(block, null, iBlockData);
+
+ public static final Class> craftMagicNumbers = Reflection.getClass("{obc}.util.CraftMagicNumbers");
+ private static final Reflection.MethodInvoker getBlockByMaterial = Reflection.getTypedMethod(craftMagicNumbers, "getBlock", block, Material.class);
+
+ private final Map, BiFunction> techhiders = new HashMap<>();
+ private final BypassEvaluator bypass;
+ private final Object obfuscationTarget;
+ private final Set obfuscate;
+
+ public TechHider(BypassEvaluator bypass, Material obfuscationTarget, Set obfuscate, Set hiddenBlockEntities) {
+ this.bypass = bypass;
+ 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(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));
+
+ if(Core.getVersion() > 12 && Core.getVersion() < 19) {
+ Class> blockBreakClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockBreak");
+ techhiders.put(blockBreakClass, ProtocolWrapper.impl.blockBreakHiderGenerator(blockBreakClass, obfuscationTarget, obfuscate, bypass));
+ }
+
+ if(Core.getVersion() > 8){
+ techhiders.put(Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseItem"), (p, packet) -> p.getGameMode() == GameMode.SPECTATOR ? null : packet);
+ }
+ techhiders.put(Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseEntity"), (p, packet) -> p.getGameMode() == GameMode.SPECTATOR ? null : packet);
+
+ }
+
+ public void enable() {
+ techhiders.forEach(TinyProtocol.instance::addFilter);
+ }
+
+ public void disable() {
+ techhiders.forEach(TinyProtocol.instance::removeFilter);
+ }
+
+ public static final Class> multiBlockChangePacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutMultiBlockChange");
+ public static final UnaryOperator multiBlockChangeCloner = ProtocolUtils.shallowCloneGenerator(TechHider.multiBlockChangePacket);
+
+ private static final Class> blockChangePacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutBlockChange");
+ private static final Function blockChangeCloner = ProtocolUtils.shallowCloneGenerator(blockChangePacket);
+ 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(ProtocolWrapper.impl.iBlockDataHidden(obfuscate, blockChangeBlockData.get(packet))) {
+ packet = blockChangeCloner.apply(packet);
+ blockChangeBlockData.set(packet, obfuscationTarget);
+ }
+ 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))))
+ return packet;
+ return null;
+ }
+
+ 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;
+ }
+
+ public interface BypassEvaluator {
+ boolean bypass(Player p, int chunkX, int chunkZ);
+ }
+}