/* * 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 com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.bausystem.entities.DetonatorEntity18; import de.steamwar.bausystem.entities.SimulatorEntity18; import de.steamwar.bausystem.entities.TraceEntity18; import de.steamwar.bausystem.entities.WarpEntity18; import de.steamwar.bausystem.features.detonator.AbstractDetonatorEntity; import de.steamwar.bausystem.features.simulator.AbstractSimulatorEntity; import de.steamwar.bausystem.features.tracer.AbstractTraceEntity; import de.steamwar.bausystem.features.util.NoClipCommand; import de.steamwar.bausystem.features.warp.AbstractWarpEntity; import net.minecraft.SystemUtils; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.PlayerInteractManager; import net.minecraft.world.level.EnumGamemode; import net.minecraft.world.phys.Vec3D; import org.bukkit.*; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_18_R2.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 NMSWrapper18 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().d, EnumGamemode.a(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.c())); 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.world.entity.Entity serverEntity = ((CraftEntity) entity).getHandle(); packets.add(new PacketPlayOutEntityMetadata(serverEntity.ae(), serverEntity.ai(), true)); } }); } @Override public void sendTickPackets() { Bukkit.getOnlinePlayers().forEach(player -> { for (Packet p : packets) { TinyProtocol.instance.sendPacket(player, p); } }); } private static final Reflection.FieldAccessor gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12); @Override public void setGameStateChangeReason(Object packet) { gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d); } @Override public void setPlayerBuildAbilities(Player player) { ((CraftPlayer) player).getHandle().fs().d = true; ((CraftPlayer) player).getHandle().fs().e = true; } @Override public Material pathMaterial() { return Material.DIRT_PATH; } private static final int threshold = 2048; @Override public boolean checkItemStack(ItemStack item) { net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item); NBTTagCompound tag = nmsItem.t(); if (tag != null && tag.e("BlockEntityTag")) { NBTTagCompound blockTag = tag.p("BlockEntityTag"); if (blockTag.e("Items")) { return drillDown(blockTag.c("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.e("tag")) { invalid += slot.f("Count"); NBTTagCompound iTag = slot.p("tag"); if (iTag.e("BlockEntityTag")) { NBTTagCompound blockTag = iTag.p("BlockEntityTag"); if (blockTag.e("Items")) { invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid); } } } if (invalid > threshold) break; } return invalid; } @Override public AbstractWarpEntity createWarp(World world, Vector position, String name) { return new WarpEntity18(world, position, name); } @Override public AbstractSimulatorEntity createSimulator(World world, Vector tntPosition, boolean highlight) { return new SimulatorEntity18(world, tntPosition, highlight); } @Override public AbstractDetonatorEntity constructDetonator(World world, Vector position) { return new DetonatorEntity18(world, position); } @Override public AbstractTraceEntity createTrace(World world, Vector tntPosition, boolean tnt) { return new TraceEntity18(world, tntPosition, tnt); } 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), null); } }