/* 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 com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Pair; import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.fight.Fight; import de.steamwar.fightsystem.record.REntity; import net.minecraft.core.IRegistry; import net.minecraft.core.SectionPosition; import net.minecraft.network.protocol.game.PacketPlayOutBlockBreak; import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.level.block.entity.TileEntityTypes; import net.minecraft.world.level.block.state.IBlockData; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; import java.util.function.UnaryOperator; public class ProtocolWrapper18 implements ProtocolWrapper { private static final Reflection.FieldAccessor equipmentStack = Reflection.getField(REntity.equipmentPacket, List.class, 0); @Override public void setEquipmentPacketStack(Object packet, String slot, Object stack) { equipmentStack.set(packet, Collections.singletonList(new Pair<>(getSlot(slot), stack))); } private static final Reflection.FieldAccessor spawnType = Reflection.getField(REntity.spawnPacket, EntityTypes.class, 0); @Override public void setSpawnPacketType(Object packet, EntityType type) { switch(type) { case PRIMED_TNT: spawnType.set(packet, EntityTypes.as); break; case ARROW: spawnType.set(packet, EntityTypes.d); break; case FIREBALL: spawnType.set(packet, EntityTypes.S); break; } } private static final Class enumItemSlot = Reflection.getClass("{nms.world.entity}.EnumItemSlot"); private static final Object[] itemSlots = enumItemSlot.getEnumConstants(); private static Object getSlot(String slot) { switch(slot){ case "HEAD": return itemSlots[5]; case "CHEST": return itemSlots[4]; case "LEGS": return itemSlots[3]; case "FEET": return itemSlots[2]; case "OFFHAND": return itemSlots[1]; case "MAINHAND": default: return itemSlots[0]; } } 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 = ProtocolAPI.arrayCloneGenerator(TechHider.iBlockData); @Override public Object multiBlockChangeHider(Player p, Object packet) { Object chunkCoords = multiBlockChangeChunk.get(packet); if(TechHider.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(block) ? TechHider.obfuscateIBlockData : 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) { return (p, packet) -> { PacketPlayOutBlockBreak breakPacket = (PacketPlayOutBlockBreak) packet; if(TechHider.bypass(p, TechHider.posToChunk(TechHider.blockPositionX.get(breakPacket.b())), TechHider.posToChunk(TechHider.blockPositionZ.get(breakPacket.b())))) return packet; if(!ProtocolWrapper.impl.iBlockDataHidden(breakPacket.c())) return packet; return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) TechHider.obfuscateIBlockData, breakPacket.d(), breakPacket.a()); }; } private static final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(Fight.playerInfoDataClass, GameProfile.class, int.class, Fight.enumGamemode, Fight.iChatBaseComponent); @Override public Object playerInfoDataConstructor(Object packet, GameProfile profile, Object mode) { return playerInfoDataConstructor.invoke(profile, 0, mode, null); } @Override public boolean iBlockDataHidden(Object iBlockData) { return Config.HiddenBlocks.contains(IRegistry.X.b(((IBlockData) iBlockData).b()).a()); } }