package de.steamwar.fightsystem.utils; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.BlockPosition; import com.comphenix.protocol.wrappers.ChunkCoordIntPair; import com.comphenix.protocol.wrappers.MultiBlockChangeInfo; import com.comphenix.protocol.wrappers.WrappedBlockData; import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.google.common.primitives.Bytes; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import io.netty.buffer.ByteBuf; import io.netty.buffer.UnpooledByteBufAllocator; import javafx.util.Pair; import net.minecraft.server.v1_12_R1.PacketPlayOutMapChunk; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class TechHider { private TechHider(){} private static int arenaMinX; private static int arenaMaxX; private static int arenaMinZ; private static int arenaMaxZ; private static int blueMinX; private static int blueMaxX; private static int blueMinZ; private static int blueMaxZ; private static int redMinX; private static int redMaxX; private static int redMinZ; private static int redMaxZ; private static short obfuscateShift4; private static final short BITMASK = 0x1FF; private static Material obfuscateMaterial; public static void init(){ if(disabled()) return; arenaMinX = posToChunk(Config.ArenaMinX); arenaMinZ = posToChunk(Config.ArenaMinZ); blueMinX = posToChunk(Config.TeamBlueCornerX); blueMinZ = posToChunk(Config.TeamBlueCornerZ); redMinX = posToChunk(Config.TeamRedCornerX); redMinZ = posToChunk(Config.TeamRedCornerZ); arenaMaxX = posToChunk(Config.ArenaMaxX) + 1; arenaMaxZ = posToChunk(Config.ArenaMaxZ) + 1; blueMaxX = posToChunk(Config.TeamBlueCornerX + Config.SchemsizeX) + 1; blueMaxZ = posToChunk(Config.TeamBlueCornerZ + Config.SchemsizeZ) + 1; redMaxX = posToChunk(Config.TeamRedCornerX + Config.SchemsizeX) + 1; redMaxZ = posToChunk(Config.TeamRedCornerZ + Config.SchemsizeZ) + 1; obfuscateShift4 = (short)(Config.ObfuscateWith << 4); obfuscateMaterial = Material.getMaterial(Config.ObfuscateWith); int threadMultiplier = 1; if(Config.event()) threadMultiplier = 4; ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.MAP_CHUNK) { @Override public void onPacketSending(PacketEvent e) { PacketContainer packet = e.getPacket(); StructureModifier ints = packet.getIntegers(); int chunkX = ints.read(0); int chunkZ = ints.read(1); Player p = e.getPlayer(); if(bypass(p, chunkX, chunkZ)) return; packet = packet.deepClone(); e.setPacket(packet); StructureModifier byteArray = packet.getByteArrays(); StructureModifier list = packet.getSpecificModifier(List.class); List nmsTags = list.read(0); boolean changed = false; for(int i = nmsTags.size() - 1; i >= 0; i--){ NbtCompound nbt = NbtFactory.fromNMSCompound(nmsTags.get(i)); if(Config.HiddenBlockEntities.contains(nbt.getString("id"))){ nmsTags.remove(i); changed = true; } } if(changed){ list.write(0, nmsTags); } changed = false; byte [] data = byteArray.read(0); ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length); int i = 0; while(i < data.length){ byte bitsPerBlock = data[i++]; buffer.writeByte(bitsPerBlock); if(bitsPerBlock < 4) bitsPerBlock = 4; else if(bitsPerBlock > 8){ bitsPerBlock = 13; i++; buffer.writeByte(data[1]); } if(bitsPerBlock != 13){ int paletteLength = readVarInt(data, i); int paletteLengthLength = readVarIntLength(data, i); buffer.writeBytes(data, i, paletteLengthLength); i += paletteLengthLength; for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++){ int actPalette = readVarInt(data, i); int actPaletteLength = readVarIntLength(data, i); int blockId = actPalette >> 4; if(Config.HiddenBlocks.contains(blockId)){ byte[] a = writeVarInt(obfuscateShift4); buffer.writeBytes(a); changed = true; }else{ buffer.writeBytes(data, i, actPaletteLength); } i += actPaletteLength; } int dataArrayLength = readVarInt(data, i); int dataArrayLengthLength = readVarIntLength(data, i); buffer.writeBytes(data, i, dataArrayLength * 8 + dataArrayLengthLength); i += dataArrayLengthLength; i += dataArrayLength * 8; }else{ int dataArrayLength = readVarInt(data, i); int dataArrayLengthLength = readVarIntLength(data, i); buffer.writeBytes(data, i, dataArrayLength*8 + dataArrayLengthLength); i += dataArrayLengthLength; /*int arrayEnd = dataArrayLength * 8 + i; int bitsOver = 8; //9 bits (id) + 4 bits (metadata) while(i < arrayEnd){ int blockId = (newData.get(i++) & (BITMASK >> 9 - bitsOver)) << 9-bitsOver; blockId += newData.get(i) >> bitsOver-1; if(Config.HiddenBlocks.contains(blockId)){ final short debug = 44; newData.set(i-1, (byte)(newData.get(i-1) & -(BITMASK >> 9-bitsOver) | debug >> 9-bitsOver)); newData.set(i, (byte)(newData.get(i) & -(BITMASK << bitsOver-1) | debug << bitsOver-1)); System.out.println(blockId + " replaced at " + chunkX + " " + chunkZ + " i:" + i + " " + String.format("%8s", Integer.toBinaryString(newData.get(i-1) & 0xFF)).replace(' ', '0') + String.format("%8s", Integer.toBinaryString(newData.get(i) & 0xFF)).replace(' ', '0') + " " + bitsOver); changed = true; } bitsOver -= 5; // 13-8 if(bitsOver < 1){ i++; bitsOver += 8; } }*/ i += dataArrayLength * 8; } buffer.writeBytes(data, i, 4096); i += 4096; //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048 } if(changed){ buffer.readBytes(data); byteArray.write(0, data); } } }).start(4 * threadMultiplier); ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.BLOCK_CHANGE) { @Override public void onPacketSending(PacketEvent e) { PacketContainer packet = e.getPacket(); BlockPosition pos = packet.getBlockPositionModifier().read(0); Player p = e.getPlayer(); if(bypass(p, posToChunk(pos.getX()), posToChunk(pos.getZ()))) return; packet = packet.deepClone(); e.setPacket(packet); StructureModifier blockStructure = packet.getBlockData(); WrappedBlockData block = blockStructure.read(0); if(Config.HiddenBlocks.contains(block.getType().getId())){ block.setType(obfuscateMaterial); blockStructure.write(0, block); } } }).start(threadMultiplier); ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.MULTI_BLOCK_CHANGE) { @Override public void onPacketSending(PacketEvent e) { PacketContainer packet = e.getPacket(); Player p = e.getPlayer(); ChunkCoordIntPair pos = packet.getChunkCoordIntPairs().read(0); if(bypass(p, pos.getChunkX(), pos.getChunkZ())) return; packet = packet.shallowClone(); e.setPacket(packet); StructureModifier blockStructure = packet.getMultiBlockChangeInfoArrays(); MultiBlockChangeInfo[] changes = blockStructure.read(0).clone(); boolean changed = false; for(MultiBlockChangeInfo mbci : changes){ WrappedBlockData block = mbci.getData(); if(Config.HiddenBlocks.contains(block.getType().getId())){ changed = true; block.setType(obfuscateMaterial); mbci.setData(block); } } if(changed){ blockStructure.write(0, changes); } } }).start(threadMultiplier); ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.BLOCK_ACTION) { @Override public void onPacketSending(PacketEvent e) { PacketContainer packet = e.getPacket(); BlockPosition pos = packet.getBlockPositionModifier().read(0); Player p = e.getPlayer(); if(bypass(p, posToChunk(pos.getX()), posToChunk(pos.getZ()))) return; e.setCancelled(true); } }).start(); ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Client.USE_ITEM) { @Override public void onPacketReceiving(PacketEvent e) { Player p = e.getPlayer(); if(p.getGameMode() == GameMode.SPECTATOR){ e.setCancelled(true); } } }).start(threadMultiplier); ProtocolLibrary.getProtocolManager().getAsynchronousManager().registerAsyncHandler(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Client.USE_ENTITY) { @Override public void onPacketReceiving(PacketEvent e) { Player p = e.getPlayer(); if(p.getGameMode() == GameMode.SPECTATOR){ e.setCancelled(true); } } }).start(threadMultiplier); } private static boolean bypass(Player p, int chunkX, int chunkZ){ if(p == FightSystem.getEventLeiter()) return true; FightTeam ft = Fight.getPlayerTeam(p); if(ft == null){ //Außerhalb der Arena return arenaMinX > chunkX || chunkX > arenaMaxX || arenaMinZ > chunkZ || chunkZ > arenaMaxZ; }else if(ft.isBlue()){ return FightSystem.isEntern() || redMinX > chunkX || chunkX > redMaxX || redMinZ > chunkZ || chunkZ > redMaxZ; }else{ return FightSystem.isEntern() || blueMinX > chunkX || chunkX > blueMaxX || blueMinZ > chunkZ || chunkZ > blueMaxZ; } } public static List> prepareChunkReload(Player p){ if(disabled()) return Collections.emptyList(); List> chunksToReload = new ArrayList<>(); for(int x = arenaMinX; x <= arenaMaxX; x++) for(int z = arenaMinZ; z <= arenaMaxZ; z++) if(!bypass(p, x, z)) chunksToReload.add(new Pair<>(x, z)); return chunksToReload; } public static void reloadChunks(Player p, List> chunksToReload){ if(disabled()) return; Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> { for(Pair chunk : chunksToReload){ if(bypass(p, chunk.getKey(), chunk.getValue())) ((CraftPlayer)p).getHandle().playerConnection.sendPacket(new PacketPlayOutMapChunk(((CraftChunk)p.getWorld().getChunkAt(chunk.getKey(), chunk.getValue())).getHandle(), 65535)); } }, 40); } private static boolean disabled(){ return Config.event() && Config.OnlyPublicSchematics; } private static int posToChunk(int c){ int chunk = c / 16; if(c<0) chunk--; return chunk; } private 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; } private 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; } private 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); } }