diff --git a/FightSystem_14/src/de/steamwar/fightsystem/utils/TechHider14.java b/FightSystem_14/src/de/steamwar/fightsystem/utils/TechHider14.java index 78100f1..a391a50 100644 --- a/FightSystem_14/src/de/steamwar/fightsystem/utils/TechHider14.java +++ b/FightSystem_14/src/de/steamwar/fightsystem/utils/TechHider14.java @@ -19,76 +19,27 @@ package de.steamwar.fightsystem.utils; -import com.comphenix.protocol.PacketType; -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.nbt.NbtBase; -import com.comphenix.protocol.wrappers.nbt.NbtCompound; -import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; import io.netty.buffer.ByteBuf; import io.netty.buffer.UnpooledByteBufAllocator; -import org.bukkit.entity.Player; import java.nio.ByteBuffer; import java.nio.LongBuffer; -import java.util.List; import java.util.Set; +import java.util.function.BiFunction; -import static de.steamwar.fightsystem.utils.TechHider.bypass; - -public class TechHider14 extends PacketAdapter { +public class TechHider14 implements BiFunction { private final Set hiddenBlockIds = BlockIdWrapper.impl.getHiddenBlockIds(); private final int obfuscateWith = BlockIdWrapper.impl.getObfuscateWith(); - public TechHider14(){ - super(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.shallowClone(); - e.setPacket(packet); - StructureModifier>> list = packet.getListNbtModifier(); - List> nmsTags = list.read(0); - boolean changed = false; - for(int i = nmsTags.size() - 1; i >= 0; i--){ - NbtBase nbtBase = nmsTags.get(i); - assert nbtBase instanceof NbtCompound; - NbtCompound nbt = (NbtCompound) nbtBase; - if(Config.HiddenBlockEntities.contains(nbt.getString("id"))){ - nmsTags.remove(i); - changed = true; - } - } - if(changed){ - list.write(0, nmsTags); - } - - changed = false; - StructureModifier byteArray = packet.getByteArrays(); - int primaryBitMask = ints.read(2); - byte[] data = byteArray.read(0); + public byte[] apply(byte[] data, Integer primaryBitMask) { ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100); int i = 0; - //int chunkY = 0; while(primaryBitMask != 0){ while((primaryBitMask & 1) == 0){ primaryBitMask >>= 1; - //chunkY++; } buffer.writeBytes(data, i, 2); // Block count @@ -107,7 +58,6 @@ public class TechHider14 extends PacketAdapter { if(hiddenBlockIds.contains(blockId)){ buffer.writeBytes(TechHider.writeVarInt(obfuscateWith)); - changed = true; }else{ buffer.writeBytes(data, i, actPaletteLength); } @@ -132,7 +82,6 @@ public class TechHider14 extends PacketAdapter { for(int pos = 0; pos < 4096; pos++){ if(hiddenBlockIds.contains(values.get(pos))){ - changed = true; values.set(pos, obfuscateWith); } } @@ -144,15 +93,12 @@ public class TechHider14 extends PacketAdapter { } primaryBitMask >>= 1; - //chunkY++; } buffer.writeBytes(data, i, data.length - i); // MC appends a 0 byte at the end if there is a full chunk, idk why - if(changed){ - data = new byte[buffer.readableBytes()]; - buffer.readBytes(data); - byteArray.write(0, data); - } + data = new byte[buffer.readableBytes()]; + buffer.readBytes(data); + return data; } private static final class VariableValueArray { diff --git a/FightSystem_12/src/de/steamwar/fightsystem/utils/TechHider12.java b/FightSystem_9/src/de/steamwar/fightsystem/utils/TechHider9.java similarity index 57% rename from FightSystem_12/src/de/steamwar/fightsystem/utils/TechHider12.java rename to FightSystem_9/src/de/steamwar/fightsystem/utils/TechHider9.java index f554505..e1f6bef 100644 --- a/FightSystem_12/src/de/steamwar/fightsystem/utils/TechHider12.java +++ b/FightSystem_9/src/de/steamwar/fightsystem/utils/TechHider9.java @@ -1,7 +1,7 @@ -/* +/* This file is a part of the SteamWar software. - - Copyright (C) 2020 SteamWar.de-Serverteam + + 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 @@ -15,68 +15,25 @@ 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.protocol.PacketType; -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.nbt.NbtBase; -import com.comphenix.protocol.wrappers.nbt.NbtCompound; -import de.steamwar.fightsystem.Config; -import de.steamwar.fightsystem.FightSystem; 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.logging.Level; -import static de.steamwar.fightsystem.utils.TechHider.bypass; - -public class TechHider12 extends PacketAdapter { +public class TechHider9 implements BiFunction { private final Set hiddenBlockIds = BlockIdWrapper.impl.getHiddenBlockIds(); private final int obfuscateWith = BlockIdWrapper.impl.getObfuscateWith(); - public TechHider12() { - super(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.shallowClone(); - e.setPacket(packet); - StructureModifier>> list = packet.getListNbtModifier(); - List> nmsTags = list.read(0); - boolean changed = false; - for(int i = nmsTags.size() - 1; i >= 0; i--){ - NbtCompound nbt = (NbtCompound)nmsTags.get(i); - if(Config.HiddenBlockEntities.contains(nbt.getString("id"))){ - nmsTags.remove(i); - changed = true; - } - } - if(changed) - list.write(0, nmsTags); - - changed = false; - StructureModifier byteArray = packet.getByteArrays(); - byte [] data = byteArray.read(0); + public byte[] apply(byte[] data, Integer primaryBitMask) { ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100); int i = 0; @@ -96,7 +53,6 @@ public class TechHider12 extends PacketAdapter { if(hiddenBlockIds.contains(entry)){ entry = obfuscateWith; - changed = true; } buffer.writeBytes(TechHider.writeVarInt(entry)); } @@ -115,10 +71,8 @@ public class TechHider12 extends PacketAdapter { i += 4096; //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048 } - if(changed){ - data = new byte[buffer.readableBytes()]; - buffer.readBytes(data); - byteArray.write(0, data); - } + data = new byte[buffer.readableBytes()]; + buffer.readBytes(data); + return data; } } diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/ProtocolAPI.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/ProtocolAPI.java new file mode 100644 index 0000000..f73d124 --- /dev/null +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/ProtocolAPI.java @@ -0,0 +1,134 @@ +/* + 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.TinyProtocol; +import de.steamwar.fightsystem.FightSystem; +import io.netty.channel.Channel; +import org.bukkit.entity.Player; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.UnaryOperator; + +public class ProtocolAPI { + private ProtocolAPI() {} + + private static final Map, BiFunction> outgoingHandler = new HashMap<>(); + private static final Map, BiFunction> incomingHandler = new HashMap<>(); + + public static final TinyProtocol tinyProtocol = new TinyProtocol(FightSystem.getPlugin()) { + @Override + public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) { + BiFunction handler = outgoingHandler.get(packet.getClass()); + if(handler == null) + return packet; + return handler.apply(receiver, packet); + } + + @Override + public Object onPacketInAsync(Player sender, Channel channel, Object packet) { + BiFunction handler = incomingHandler.get(packet.getClass()); + if(handler == null) + return packet; + return handler.apply(sender, packet); + } + }; + + public static void setOutgoingHandler(Class packetClass, BiFunction handler) { + outgoingHandler.put(packetClass, handler); + } + + public static void removeOutgoingHandler(Class packetClass) { + outgoingHandler.remove(packetClass); + } + + public static void setIncomingHandler(Class packetClass, BiFunction handler) { + incomingHandler.put(packetClass, handler); + } + + public static void removeIncomingHandler(Class packetClass) { + incomingHandler.remove(packetClass); + } + + + 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; + try { + clone = clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException("Could not clone " + clazz.getName(), e); + } + 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); + } + + }; + } +} diff --git a/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHider.java b/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHider.java index f0b0f5c..085ffc7 100644 --- a/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHider.java +++ b/FightSystem_Core/src/de/steamwar/fightsystem/utils/TechHider.java @@ -19,21 +19,10 @@ package de.steamwar.fightsystem.utils; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -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.tinyprotocol.Reflection; import com.google.common.primitives.Bytes; import de.steamwar.core.Core; import de.steamwar.core.events.ChunkListener; -import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.FightSystem; import de.steamwar.fightsystem.VersionDependent; @@ -41,212 +30,198 @@ import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.fight.FightTeam; import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.StateDependent; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.UnpooledByteBufAllocator; import org.bukkit.Bukkit; 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 extends StateDependent { + private static final Class blockPosition = Reflection.getClass("{nms}.BlockPosition"); + private static final Class baseBlockPosition = Reflection.getClass("{nms}.BaseBlockPosition"); + private static final Reflection.FieldAccessor blockPositionX = Reflection.getField(baseBlockPosition, int.class, 0); + private static final Reflection.FieldAccessor blockPositionZ = Reflection.getField(baseBlockPosition, int.class, 2); + + private static final Class iBlockData = Reflection.getClass("{nms}.IBlockData"); + private static final Class block = Reflection.getClass("{nms}.Block"); + private static final Reflection.MethodInvoker getBlockByBlockData = Reflection.getTypedMethod(iBlockData, "getBlock", block); + private static final Reflection.MethodInvoker getBlockDataByBlock = Reflection.getTypedMethod(block, "getBlockData", iBlockData); + + private static final Class craftMagicNumbers = Reflection.getClass("{obc}.util.CraftMagicNumbers"); + private static final Reflection.MethodInvoker getMaterialByBlock = Reflection.getTypedMethod(craftMagicNumbers, "getMaterial", Material.class, block); + private static final Reflection.MethodInvoker getBlockByMaterial = Reflection.getTypedMethod(craftMagicNumbers, "getBlock", block, Material.class); + public static final boolean ENABLED = !Config.OnlyPublicSchematics && !Config.test() && Config.TechhiderActive; - private final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); - private final Map packetCache = new HashMap<>(); - private final Material obfuscateMaterial; - private final PacketAdapter chunkHider; - private final int threadMultiplier; + private final Object obfuscateIBlockData = getBlockDataByBlock.invoke(getBlockByMaterial.invoke(null, Material.getMaterial(Config.ObfuscateWith.toUpperCase()))); + private final Map, BiFunction> techhiders = new HashMap<>(); + private final BiFunction chunkDataHider; public TechHider(){ super(ENABLED, FightState.Schem); - obfuscateMaterial = Material.getMaterial(Config.ObfuscateWith.toUpperCase()); - chunkHider = VersionDependent.getVersionImpl(TechHider.class.getName()); + chunkDataHider = VersionDependent.getVersionImpl(TechHider.class.getName()); - if(Config.mode == ArenaMode.EVENT) - threadMultiplier = 4; - else - threadMultiplier = 1; - - Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), packetCache::clear, 1, 1); + techhiders.put(blockActionPacket, this::blockActionHider); + techhiders.put(blockChangePacket, this::blockChangeHider); + techhiders.put(tileEntityDataPacket, this::tileEntityDataHider); + techhiders.put(multiBlockChangePacket, this::multiBlockChangeHider); + if(Core.getVersion() > 8) { + techhiders.put(mapChunkPacket, this::mapChunkHider); + } + if(Core.getVersion() > 12) { + Class blockBreakClass = Reflection.getClass("{nms}.PacketPlayOutBlockBreak"); + techhiders.put(blockBreakClass, blockBreakHiderGenerator(blockBreakClass)); + } if(Core.getVersion() > 8){ - protocolManager.addPacketListener(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Client.USE_ITEM) { - @Override - public void onPacketReceiving(PacketEvent e) { - Player p = e.getPlayer(); - - if(p == null || p.getGameMode() == GameMode.SPECTATOR) - e.setCancelled(true); - } - }); + ProtocolAPI.setIncomingHandler(Reflection.getClass("{nms}.PacketPlayInUseItem"), (p, packet) -> p.getGameMode() == GameMode.SPECTATOR ? null : packet); } - protocolManager.addPacketListener(new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Client.USE_ENTITY) { - @Override - public void onPacketReceiving(PacketEvent e) { - Player p = e.getPlayer(); + ProtocolAPI.setIncomingHandler(Reflection.getClass("{nms}.PacketPlayInUseEntity"), (p, packet) -> p.getGameMode() == GameMode.SPECTATOR ? null : packet); - if(p.getGameMode() == GameMode.SPECTATOR) - e.setCancelled(true); - } - }); register(); } @Override public void enable() { - protocolManager.addPacketListener(blockHider); - protocolManager.addPacketListener(multiBlockHider); - protocolManager.addPacketListener(blockActionHider); - protocolManager.getAsynchronousManager().registerAsyncHandler(chunkHider).start(threadMultiplier * 4); - if(Core.getVersion() > 8) { - protocolManager.addPacketListener(updateBlockEntity); - } - if(Core.getVersion() > 12) { - protocolManager.addPacketListener(blockBreakHider); - } + techhiders.forEach(ProtocolAPI::setOutgoingHandler); } @Override public void disable() { - protocolManager.removePacketListener(blockHider); - protocolManager.removePacketListener(multiBlockHider); - protocolManager.removePacketListener(blockActionHider); - protocolManager.getAsynchronousManager().unregisterAsyncHandler(chunkHider); - if(Core.getVersion() > 8) { - protocolManager.removePacketListener(updateBlockEntity); - } - if(Core.getVersion() > 12) { - protocolManager.removePacketListener(blockBreakHider); - } + techhiders.keySet().forEach(ProtocolAPI::removeOutgoingHandler); } - private final PacketAdapter multiBlockHider = new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.MULTI_BLOCK_CHANGE) { - @Override - public void onPacketSending(PacketEvent e) { - PacketContainer packet = e.getPacket(); + private static final Class nbtTagCompound = Reflection.getClass("{nms}.NBTTagCompound"); + private static final Reflection.MethodInvoker nbtTagGetString = Reflection.getTypedMethod(nbtTagCompound, "getString", String.class, String.class); - Player p = e.getPlayer(); - ChunkCoordIntPair pos = packet.getChunkCoordIntPairs().read(0); - if(bypass(p, pos.getChunkX(), pos.getChunkZ())) - return; - - PacketContainer cached = packetCache.get(packet); - if(cached != null){ - e.setPacket(cached); - return; - } - - cached = packet.shallowClone(); - packetCache.put(packet, cached); - e.setPacket(cached); - StructureModifier blockStructure = cached.getMultiBlockChangeInfoArrays(); - MultiBlockChangeInfo[] changes = blockStructure.read(0).clone(); - boolean changed = false; - for(MultiBlockChangeInfo mbci : changes){ - WrappedBlockData block = mbci.getData(); - if(Config.HiddenBlocks.contains(block.getType().name().toLowerCase())){ - changed = true; - block.setType(obfuscateMaterial); - mbci.setData(block); - } - } - - if(changed){ - blockStructure.write(0, changes); - } + private static final Class mapChunkPacket = Reflection.getClass("{nms}.PacketPlayOutMapChunk"); + 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; + private static final Reflection.FieldAccessor mapChunkBlockEntities; + private static final Reflection.FieldAccessor mapChunkData; + static { + if(Core.getVersion() > 8) { + mapChunkBitMask = Reflection.getField(mapChunkPacket, int.class, 2); + mapChunkBlockEntities = Reflection.getField(mapChunkPacket, List.class, 0); + mapChunkData = Reflection.getField(mapChunkPacket, byte[].class, 0); + }else { + mapChunkBitMask = null; + mapChunkBlockEntities = null; + mapChunkData = null; } - }; + } + private Object mapChunkHider(Player p, Object packet) { + if(bypass(p, mapChunkX.get(packet), mapChunkZ.get(packet))) + return packet; - private final PacketAdapter blockHider = 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); + 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())); - Player p = e.getPlayer(); - if(bypass(p, posToChunk(pos.getX()), posToChunk(pos.getZ()))) - return; + byte[] data = chunkDataHider.apply(mapChunkData.get(packet), mapChunkBitMask.get(packet)); + ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.directBuffer(data.length + 100); + data = new byte[buffer.readableBytes()]; + buffer.readBytes(data); + mapChunkData.set(packet, data); - PacketContainer cached = packetCache.get(packet); - if(cached != null){ - e.setPacket(cached); - return; + return packet; + } + + private static final Class multiBlockChangePacket = Reflection.getClass("{nms}.PacketPlayOutMultiBlockChange"); + private static final UnaryOperator multiBlockChangeCloner = ProtocolAPI.shallowCloneGenerator(multiBlockChangePacket); + private static final Class chunkCoordinateIntPair = Reflection.getClass("{nms}.ChunkCoordIntPair"); + private static final Reflection.FieldAccessor multiBlockChangeChunk = Reflection.getField(multiBlockChangePacket, chunkCoordinateIntPair, 0); + private static final Reflection.FieldAccessor chunkCoordinateX = Reflection.getField(baseBlockPosition, int.class, 0); + private static final Reflection.FieldAccessor chunkCoordinateZ = Reflection.getField(baseBlockPosition, int.class, 1); + private static final Class multiBlockChangeInfo = Reflection.getClass("{nms}.PacketPlayOutMultiBlockChange.MultiBlockChangeInfo"); + private static final UnaryOperator multiBlockChangeInfoCloner = ProtocolAPI.shallowCloneGenerator(multiBlockChangeInfo); + private static final BiFunction, Object> multiBlockChangeInfoArrayCloner = ProtocolAPI.arrayCloneGenerator(multiBlockChangeInfo); + private static final Reflection.FieldAccessor multiBlockChangeInfoBlock = Reflection.getField(multiBlockChangeInfo, iBlockData, 0); + private static final Class multiBlockChangeInfoArray = Reflection.getClass("[L{nms}.PacketPlayOutMultiBlockChange.MultiBlockChangeInfo;"); + private static final Reflection.FieldAccessor multiBlockChangeInfos = Reflection.getField(multiBlockChangePacket, multiBlockChangeInfoArray, 0); + private Object multiBlockChangeHider(Player p, Object packet) { + Object chunkCoords = multiBlockChangeChunk.get(packet); + if(bypass(p, chunkCoordinateX.get(chunkCoords), chunkCoordinateZ.get(chunkCoords))) + return packet; + + packet = multiBlockChangeCloner.apply(packet); + multiBlockChangeInfos.set(packet, multiBlockChangeInfoArrayCloner.apply(multiBlockChangeInfos.get(packet), mbci -> { + if(Config.HiddenBlocks.contains(getMaterialByIBlockData(multiBlockChangeInfoBlock.get(mbci)).name().toLowerCase())) { + mbci = multiBlockChangeInfoCloner.apply(mbci); + multiBlockChangeInfoBlock.set(mbci, obfuscateIBlockData); } + return mbci; + })); + return packet; + } - cached = packet.deepClone(); - packetCache.put(packet, cached); - e.setPacket(cached); - StructureModifier blockStructure = cached.getBlockData(); - WrappedBlockData block = blockStructure.read(0); - if(Config.HiddenBlocks.contains(block.getType().name().toLowerCase())){ - block.setType(obfuscateMaterial); - blockStructure.write(0, block); + private static final Class blockChangePacket = Reflection.getClass("{nms}.PacketPlayOutBlockChange"); + private static final Function blockChangeCloner = ProtocolAPI.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(p, posToChunk(blockPositionX.get(pos)), posToChunk(blockPositionZ.get(pos)))) + return packet; + + if(Config.HiddenBlocks.contains(getMaterialByIBlockData(blockChangeBlockData.get(packet)).name().toLowerCase())){ + packet = blockChangeCloner.apply(packet); + blockChangeBlockData.set(packet, obfuscateIBlockData); + } + return packet; + } + + private static final Class blockActionPacket = Reflection.getClass("{nms}.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(p, posToChunk(blockPositionX.get(pos)), posToChunk(blockPositionZ.get(pos)))) + return packet; + return null; + } + + private BiFunction blockBreakHiderGenerator(Class blockBreakPacket){ + UnaryOperator blockBreakCloner = ProtocolAPI.shallowCloneGenerator(blockBreakPacket); + Reflection.FieldAccessor blockBreakPosition = Reflection.getField(blockBreakPacket, blockPosition, 0); + Reflection.FieldAccessor blockBreakBlockData = Reflection.getField(blockBreakPacket, iBlockData, 0); + + return (p, packet) -> { + Object pos = blockBreakPosition.get(packet); + if(bypass(p, posToChunk(blockPositionX.get(pos)), posToChunk(blockPositionZ.get(pos)))) + return packet; + + if(Config.HiddenBlocks.contains(getMaterialByIBlockData(blockBreakBlockData.get(packet)).name().toLowerCase())){ + packet = blockBreakCloner.apply(packet); + blockBreakBlockData.set(packet, obfuscateIBlockData); } - } - }; + return packet; + }; + } - private final PacketAdapter blockActionHider = 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); + private static final Class tileEntityDataPacket = Reflection.getClass("{nms}.PacketPlayOutTileEntityData"); + private static final Reflection.FieldAccessor tileEntityDataPosition = Reflection.getField(tileEntityDataPacket, blockPosition, 0); + private static final Reflection.FieldAccessor tileEntityDataAction = Reflection.getField(tileEntityDataPacket, int.class, 0); + private Object tileEntityDataHider(Player p, Object packet) { + Object pos = tileEntityDataPosition.get(packet); + if(bypass(p, posToChunk(blockPositionX.get(pos)), posToChunk(blockPositionZ.get(pos)))) + return packet; - Player p = e.getPlayer(); - if(bypass(p, posToChunk(pos.getX()), posToChunk(pos.getZ()))) - return; - - e.setCancelled(true); - } - }; - - private final PacketAdapter blockBreakHider = new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.BLOCK_BREAK) { - @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; - - - PacketContainer cached = packetCache.get(packet); - if(cached != null){ - e.setPacket(cached); - return; - } - - cached = packet.deepClone(); - packetCache.put(packet, cached); - e.setPacket(cached); - StructureModifier blockStructure = cached.getBlockData(); - WrappedBlockData block = blockStructure.read(0); - if(Config.HiddenBlocks.contains(block.getType().name().toLowerCase())){ - block.setType(obfuscateMaterial); - blockStructure.write(0, block); - } - } - }; - - private final PacketAdapter updateBlockEntity = new PacketAdapter(FightSystem.getPlugin(), PacketType.Play.Server.TILE_ENTITY_DATA) { - @Override - public void onPacketSending(PacketEvent event) { - PacketContainer packet = event.getPacket(); - BlockPosition pos = packet.getBlockPositionModifier().read(0); - - Player p = event.getPlayer(); - if(bypass(p, posToChunk(pos.getX()), posToChunk(pos.getZ()))) - return; - - // 9 == Set sign text - if(packet.getIntegers().read(0) != 9) - return; - - event.setCancelled(true); - } - }; + if(tileEntityDataAction.get(packet) != 9) + return packet; + return null; + } public static List prepareChunkReload(Player p, boolean hide){ if(!ENABLED) @@ -284,6 +259,10 @@ public class TechHider extends StateDependent { } } + private static Material getMaterialByIBlockData(Object iBlockData) { + return (Material) getMaterialByBlock.invoke(null, getBlockByBlockData.invoke(iBlockData)); + } + private static int posToChunk(int c){ int chunk = c / 16; if(c<0)