/* 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.fightsystem.utils; import com.comphenix.tinyprotocol.Reflection; import de.steamwar.fightsystem.Config; 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.UnaryOperator; import java.util.logging.Level; import java.util.stream.Collectors; public class TechHider9 extends TechHider8 { private static final UnaryOperator mapChunkCloner = ProtocolAPI.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); protected final Set hiddenBlockIds = BlockIdWrapper.impl.getHiddenBlockIds(); protected final int obfuscateWith = BlockIdWrapper.impl.getObfuscateWith(); @Override public Object mapChunkHider(Player p, Object packet) { if(TechHider.bypass(p, mapChunkX.get(packet), mapChunkZ.get(packet))) return packet; packet = mapChunkCloner.apply(packet); mapChunkBlockEntities.set(packet, ((List)mapChunkBlockEntities.get(packet)).stream().filter( nbttag -> Config.HiddenBlockEntities.contains((String) nbtTagGetString.invoke(nbttag, "id")) ).collect(Collectors.toList())); byte[] data = dataHider(mapChunkData.get(packet), mapChunkBitMask.get(packet)); mapChunkData.set(packet, data); return packet; } protected byte[] dataHider(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 = TechHider.readVarInt(data, i); int paletteLengthLength = TechHider.readVarIntLength(data, i); buffer.writeBytes(data, i, paletteLengthLength); i += paletteLengthLength; for(int actPaletteId = 0; actPaletteId < paletteLength; actPaletteId++){ int entry = TechHider.readVarInt(data, i); i += TechHider.readVarIntLength(data, i); if(hiddenBlockIds.contains(entry)){ entry = obfuscateWith; } buffer.writeBytes(TechHider.writeVarInt(entry)); } }else{ buffer.writeByte(data[++i]); //Empty palette Bukkit.getLogger().log(Level.SEVERE, "Full chunk occured"); } int dataArrayLength = TechHider.readVarInt(data, i); int dataArrayLengthLength = TechHider.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; } }