From 59caeca6f7b4a5103ddbf7d48949cd7734ecf67f Mon Sep 17 00:00:00 2001 From: yoyosource Date: Sun, 20 Aug 2023 15:57:02 +0200 Subject: [PATCH] Add 1.20 support Signed-off-by: yoyosource --- .../bausystem/utils/NMSWrapper19.java | 1 - BauSystem_20/build.gradle | 62 ++++++ .../bausystem/utils/NMSWrapper20.java | 178 ++++++++++++++++++ .../utils/PlayerMovementWrapper20.java | 80 ++++++++ 4 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 BauSystem_20/build.gradle create mode 100644 BauSystem_20/src/de/steamwar/bausystem/utils/NMSWrapper20.java create mode 100644 BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java diff --git a/BauSystem_19/src/de/steamwar/bausystem/utils/NMSWrapper19.java b/BauSystem_19/src/de/steamwar/bausystem/utils/NMSWrapper19.java index d6c7df29..f7e82cc7 100644 --- a/BauSystem_19/src/de/steamwar/bausystem/utils/NMSWrapper19.java +++ b/BauSystem_19/src/de/steamwar/bausystem/utils/NMSWrapper19.java @@ -55,7 +55,6 @@ public class NMSWrapper19 implements NMSWrapper { @SuppressWarnings("deprecation") public void setInternalGameMode(Player player, GameMode gameMode) { playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue())); - } @Override diff --git a/BauSystem_20/build.gradle b/BauSystem_20/build.gradle new file mode 100644 index 00000000..bfb7c724 --- /dev/null +++ b/BauSystem_20/build.gradle @@ -0,0 +1,62 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 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 . + */ + +plugins { + id 'base' + id 'java' +} + +group 'steamwar' +version '1.0' + +compileJava.options.encoding = 'UTF-8' + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +sourceSets { + main { + java { + srcDirs = ['src/'] + } + resources { + srcDirs = ['src/'] + exclude '**/*.java', '**/*.kt' + } + } +} + +dependencies { + compileOnly 'org.projectlombok:lombok:1.18.22' + testCompileOnly 'org.projectlombok:lombok:1.18.22' + annotationProcessor 'org.projectlombok:lombok:1.18.22' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.22' + + implementation project(":BauSystem_Main") + + compileOnly 'org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT' + compileOnly 'it.unimi.dsi:fastutil:8.5.6' + compileOnly 'com.mojang:datafixerupper:4.0.26' + compileOnly 'io.netty:netty-all:4.1.68.Final' + compileOnly 'com.mojang:authlib:1.5.25' + compileOnly 'com.mojang:brigadier:1.0.18' + + compileOnly swdep('Spigot-1.20') + compileOnly swdep('SpigotCore') +} \ No newline at end of file diff --git a/BauSystem_20/src/de/steamwar/bausystem/utils/NMSWrapper20.java b/BauSystem_20/src/de/steamwar/bausystem/utils/NMSWrapper20.java new file mode 100644 index 00000000..f532eeec --- /dev/null +++ b/BauSystem_20/src/de/steamwar/bausystem/utils/NMSWrapper20.java @@ -0,0 +1,178 @@ +/* + * 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.features.util.NoClipCommand; +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.network.syncher.DataWatcher; +import net.minecraft.server.level.PlayerInteractManager; +import net.minecraft.world.level.EnumGamemode; +import net.minecraft.world.phys.Vec3D; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.LongSupplier; + +public class NMSWrapper20 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.a(); + 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(); + List> list = serverEntity.aj().c(); + if(list != null) + packets.add(new PacketPlayOutEntityMetadata(serverEntity.af(), list)); + } + }); + } + + @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().fO().d = true; + ((CraftPlayer) player).getHandle().fO().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.v(); + 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; + } + + 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); + } +} diff --git a/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java b/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java new file mode 100644 index 00000000..752d79f8 --- /dev/null +++ b/BauSystem_20/src/de/steamwar/bausystem/utils/PlayerMovementWrapper20.java @@ -0,0 +1,80 @@ +/* + * 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 net.minecraft.network.protocol.game.PacketPlayInFlying; +import net.minecraft.server.level.EntityPlayer; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerMovementWrapper20 implements PlayerMovementWrapper { + + private static class Position { + private double x; + private double y; + private double z; + private float yaw; + private float pitch; + } + + private Map playerLocationMap = new HashMap<>(); + + @Override + public void setPosition(Player player, Object object) { + Position position = playerLocationMap.computeIfAbsent(player.getUniqueId(), uuid -> { + Position pos = new Position(); + Location location = player.getLocation(); + pos.x = location.getX(); + pos.y = location.getY(); + pos.z = location.getZ(); + pos.yaw = location.getYaw(); + pos.pitch = location.getPitch(); + return pos; + }); + PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object); + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + if (packetPlayInFlying.h) { + entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e); + position.x = packetPlayInFlying.a; + position.y = packetPlayInFlying.b; + position.z = packetPlayInFlying.c; + position.yaw = packetPlayInFlying.d; + position.pitch = packetPlayInFlying.e; + } else { + entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c); + position.x = packetPlayInFlying.a; + position.y = packetPlayInFlying.b; + position.z = packetPlayInFlying.c; + } + } + + @Override + public void disable(Player player) { + Position position = playerLocationMap.remove(player.getUniqueId()); + if (position != null) { + player.teleport(new Location(player.getWorld(), position.x, position.y, position.z, position.yaw, position.pitch)); + } + } +}