/* * 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.bausystem.utils; import com.comphenix.tinyprotocol.Reflection; import de.steamwar.bausystem.entities.DetonatorEntity15; import de.steamwar.bausystem.entities.SimulatorEntity15; import de.steamwar.bausystem.features.detonator.AbstractDetonatorEntity; import de.steamwar.bausystem.features.simulator.AbstractSimulatorEntity; import de.steamwar.bausystem.features.util.NoClipCommand; import net.minecraft.server.v1_15_R1.*; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.List; import java.util.function.LongSupplier; public class NMSWrapper15 implements NMSWrapper { private static final Reflection.FieldAccessor playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0); @Override @SuppressWarnings("deprecation") public void setInternalGameMode(Player player, GameMode gameMode) { playerGameMode.set(((CraftPlayer) player).getHandle().playerInteractManager, EnumGamemode.getById(gameMode.getValue())); } @Override public void setSlotToItemStack(Player player, Object o) { PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o; int index = packetPlayInSetCreativeSlot.b(); if (index >= 36 && index <= 44) { index -= 36; } else if (index > 44) { index -= 5; } else if (index <= 8) { index = index - 8 + 36; } player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItemStack())); if (index < 9) player.getInventory().setHeldItemSlot(index); player.updateInventory(); } @Override public void init(LongSupplier longSupplier) { SystemUtils.a = () -> System.nanoTime() + longSupplier.getAsLong(); } private static final List> packets = new ArrayList<>(); private static final Vec3D noMotion = new Vec3D(0, 0, 0); @Override public void createTickCache(World world) { packets.clear(); world.getEntities().stream().filter(entity -> !(entity instanceof Player)).forEach(entity -> { packets.add(new PacketPlayOutEntityVelocity(entity.getEntityId(), noMotion)); packets.add(new PacketPlayOutEntityTeleport(((CraftEntity) entity).getHandle())); if (entity instanceof TNTPrimed) { net.minecraft.server.v1_15_R1.Entity serverEntity = ((CraftEntity) entity).getHandle(); packets.add(new PacketPlayOutEntityMetadata(serverEntity.getId(), serverEntity.getDataWatcher(), true)); } }); } @Override public void sendTickPackets() { Bukkit.getOnlinePlayers().forEach(player -> { PlayerConnection connection = ((CraftPlayer) player).getHandle().playerConnection; for (Packet p : packets) { connection.sendPacket(p); } }); } private static final Reflection.FieldAccessor gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, int.class, 0); @Override public void setGameStateChangeReason(Object packet) { gameStateChangeReason.set(packet, 3); } @Override public void setPlayerBuildAbilities(Player player) { ((CraftPlayer) player).getHandle().abilities.mayBuild = true; ((CraftPlayer) player).getHandle().abilities.canInstantlyBuild = true; } @Override public Material pathMaterial() { return Material.GRASS_PATH; } private static final int threshold = 2048; @Override public boolean checkItemStack(ItemStack item) { net.minecraft.server.v1_15_R1.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); NBTTagCompound tag = nmsItem.getTag(); if (tag != null && tag.hasKey("BlockEntityTag")) { NBTTagCompound blockTag = tag.getCompound("BlockEntityTag"); if (blockTag.hasKey("Items")) { return drillDown(blockTag.getList("Items", 10), 0, 0) > threshold; } } return false; } private int drillDown(NBTTagList items, int layer, int start) { if (layer > 2) return start + threshold; int invalid = start; for (NBTBase nbtBase : items) { if (!(nbtBase instanceof NBTTagCompound)) continue; NBTTagCompound slot = (NBTTagCompound) nbtBase; if (slot.hasKey("tag")) { invalid += slot.getByte("Count"); NBTTagCompound iTag = slot.getCompound("tag"); if (iTag.hasKey("BlockEntityTag")) { NBTTagCompound blockTag = iTag.getCompound("BlockEntityTag"); if (blockTag.hasKey("Items")) { invalid = drillDown(blockTag.getList("Items", 10), layer + 1, invalid); } } } if (invalid > threshold) break; } return invalid; } @Override public AbstractSimulatorEntity createSimulator(World world, Vector tntPosition, boolean highlight) { return new SimulatorEntity15(world, tntPosition, highlight); } @Override public AbstractDetonatorEntity constructDetonator(World world, Vector position) { return new DetonatorEntity15(world, position); } private final Class explosionPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutExplosion"); private final Reflection.FieldAccessor a = Reflection.getField(explosionPacket, double.class, 0); private final Reflection.FieldAccessor b = Reflection.getField(explosionPacket, double.class, 1); private final Reflection.FieldAccessor c = Reflection.getField(explosionPacket, double.class, 2); private final Reflection.FieldAccessor d = Reflection.getField(explosionPacket, float.class, 0); private final Reflection.FieldAccessor e = Reflection.getField(explosionPacket, List.class, 0); @Override public Object resetExplosionKnockback(Object packet) { PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet; return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), Vec3D.a); } }