From cf34ef4c0669c31c54ec31036fa90fa946d4b5d9 Mon Sep 17 00:00:00 2001 From: Jitse Boonstra Date: Mon, 12 Nov 2018 21:09:11 +0100 Subject: [PATCH] Started work on v1.2.2 (support for MC 1.13.1 R2). --- .travis.yml | 1 + nms/v1_13_R2/pom.xml | 27 +++++ .../npclib/nms/v1_13_R2/NPC_v1_13_R2.java | 104 ++++++++++++++++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 +++++ .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 ++++++++ .../PacketPlayOutPlayerInfoWrapper.java | 43 ++++++++ .../PacketPlayOutScoreboardTeamWrapper.java | 53 +++++++++ 7 files changed, 301 insertions(+) create mode 100755 nms/v1_13_R2/pom.xml create mode 100755 nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java create mode 100755 nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100755 nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100755 nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100755 nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutScoreboardTeamWrapper.java diff --git a/.travis.yml b/.travis.yml index 8e1c246..0c19481 100755 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: - ls $HOME/.m2/repository/org/spigotmc/spigot/1.10.2-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.10.2 >> /dev/null 2>&1 - ls $HOME/.m2/repository/org/spigotmc/spigot/1.11.2-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.11.2 >> /dev/null 2>&1 - ls $HOME/.m2/repository/org/spigotmc/spigot/1.12.2-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.12.2 >> /dev/null 2>&1 +- ls $HOME/.m2/repository/org/spigotmc/spigot/1.12.2-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.13 >> /dev/null 2>&1 - ls $HOME/.m2/repository/org/spigotmc/spigot/1.12.2-R0.1-SNAPSHOT >> /dev/null 2>&1 || java -jar BuildTools.jar --rev 1.13.1 >> /dev/null 2>&1 script: - mvn clean install \ No newline at end of file diff --git a/nms/v1_13_R2/pom.xml b/nms/v1_13_R2/pom.xml new file mode 100755 index 0000000..fbbb5ea --- /dev/null +++ b/nms/v1_13_R2/pom.xml @@ -0,0 +1,27 @@ + + + + + 4.0.0 + + + net.jitse + npclib-nms + 1.2.1 + + + npclib-nms-v1_13_R2 + + + + org.spigotmc + spigot + 1.13.1-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java new file mode 100755 index 0000000..0efa24f --- /dev/null +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_13_R2; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_13_R2.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_13_R2.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_13_R2.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_13_R2.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_13_R2.*; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_13_R2 extends NPC { + + private Hologram hologram; + private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; + private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; + private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + + public NPC_v1_13_R2(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void createPackets() { + this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); + hologram.generatePackets(true, true); + + this.gameProfile = generateGameProfile(uuid, name); + PacketPlayOutPlayerInfoWrapper packetPlayOutPlayerInfoWrapper = new PacketPlayOutPlayerInfoWrapper(); + + // Packets for spawning the NPC: + this.packetPlayOutScoreboardTeamRegister = new PacketPlayOutScoreboardTeamWrapper() + .createRegisterTeam(name); // First packet to send. + + this.packetPlayOutPlayerInfoAdd = packetPlayOutPlayerInfoWrapper + .create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, gameProfile, name); // Second packet to send. + + this.packetPlayOutNamedEntitySpawn = new PacketPlayOutNamedEntitySpawnWrapper() + .create(uuid, location, entityId); // Third packet to send. + + this.packetPlayOutEntityHeadRotation = new PacketPlayOutEntityHeadRotationWrapper() + .create(location, entityId); // Fourth packet to send. + + this.packetPlayOutPlayerInfoRemove = packetPlayOutPlayerInfoWrapper + .create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, gameProfile, name); // Fifth packet to send (delayed). + + // Packet for destroying the NPC: + this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + + // Second packet to send is "packetPlayOutPlayerInfoRemove". + + this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() + .createUnregisterTeam(name); // Third packet to send. + } + + @Override + public void sendShowPackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); + playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); + playerConnection.sendPacket(packetPlayOutEntityHeadRotation); + + hologram.spawn(player); + + + Bukkit.getScheduler().runTaskLater(plugin, () -> + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove), 50); + } + + @Override + public void sendHidePackets(Player player, boolean scheduler) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + if (scheduler) { + // Sending this a bit later so the player doesn't see the name (for that split second). + Bukkit.getScheduler().runTaskLater(plugin, () -> + playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); + } else { + playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); + } + } +} diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100755 index 0000000..8730bca --- /dev/null +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_13_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_13_R1.PacketPlayOutEntityHeadRotation; +import org.bukkit.Location; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutEntityHeadRotationWrapper { + + public PacketPlayOutEntityHeadRotation create(Location location, int entityId) { + PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation = new PacketPlayOutEntityHeadRotation(); + + Reflection.getField(packetPlayOutEntityHeadRotation.getClass(), "a", int.class). + set(packetPlayOutEntityHeadRotation, entityId); + Reflection.getField(packetPlayOutEntityHeadRotation.getClass(), "b", byte.class) + .set(packetPlayOutEntityHeadRotation, (byte) ((int) location.getYaw() * 256.0F / 360.0F)); + + return packetPlayOutEntityHeadRotation; + } +} diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100755 index 0000000..26cc438 --- /dev/null +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_13_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_13_R1.DataWatcher; +import net.minecraft.server.v1_13_R1.DataWatcherObject; +import net.minecraft.server.v1_13_R1.DataWatcherRegistry; +import net.minecraft.server.v1_13_R1.PacketPlayOutNamedEntitySpawn; +import org.bukkit.Location; + +import java.util.UUID; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutNamedEntitySpawnWrapper { + + public PacketPlayOutNamedEntitySpawn create(UUID uuid, Location location, int entityId) { + PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn = new PacketPlayOutNamedEntitySpawn(); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "a", int.class) + .set(packetPlayOutNamedEntitySpawn, entityId); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "b", UUID.class) + .set(packetPlayOutNamedEntitySpawn, uuid); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "c", double.class) + .set(packetPlayOutNamedEntitySpawn, location.getX()); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", double.class) + .set(packetPlayOutNamedEntitySpawn, location.getY()); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", double.class) + .set(packetPlayOutNamedEntitySpawn, location.getZ()); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "f", byte.class) + .set(packetPlayOutNamedEntitySpawn, (byte) ((int) (location.getYaw() * 256.0F / 360.0F))); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "g", byte.class) + .set(packetPlayOutNamedEntitySpawn, (byte) ((int) (location.getPitch() * 256.0F / 360.0F))); + + DataWatcher dataWatcher = new DataWatcher(null); + dataWatcher.register(new DataWatcherObject<>(13, DataWatcherRegistry.a), (byte) 127); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "h", DataWatcher.class) + .set(packetPlayOutNamedEntitySpawn, dataWatcher); + + return packetPlayOutNamedEntitySpawn; + } +} diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100755 index 0000000..08d94d3 --- /dev/null +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_13_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_13_R1.EnumGamemode; +import net.minecraft.server.v1_13_R1.IChatBaseComponent; +import net.minecraft.server.v1_13_R1.PacketPlayOutPlayerInfo; +import org.bukkit.ChatColor; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutPlayerInfoWrapper { + + private final Class packetPlayOutPlayerInfoClazz = Reflection.getMinecraftClass("PacketPlayOutPlayerInfo"); + private final Class playerInfoDataClazz = Reflection.getMinecraftClass("PacketPlayOutPlayerInfo$PlayerInfoData"); + private final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor(playerInfoDataClazz, + packetPlayOutPlayerInfoClazz, GameProfile.class, int.class, EnumGamemode.class, IChatBaseComponent.class); + + public PacketPlayOutPlayerInfo create(PacketPlayOutPlayerInfo.EnumPlayerInfoAction action, GameProfile gameProfile, String name) { + PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); + Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", PacketPlayOutPlayerInfo.EnumPlayerInfoAction.class) + .set(packetPlayOutPlayerInfo, action); + + Object playerInfoData = playerInfoDataConstructor.invoke(packetPlayOutPlayerInfo, + gameProfile, 1, EnumGamemode.NOT_SET, + IChatBaseComponent.ChatSerializer.b("{\"text\":\"" + ChatColor.BLUE + "[NPC] " + name + "\"}") + ); + + Reflection.FieldAccessor fieldAccessor = Reflection.getField(packetPlayOutPlayerInfo.getClass(), "b", List.class); + List list = fieldAccessor.get(packetPlayOutPlayerInfo); + list.add(playerInfoData); + fieldAccessor.set(packetPlayOutPlayerInfo, list); + + return packetPlayOutPlayerInfo; + } +} diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100755 index 0000000..16d6ef7 --- /dev/null +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_13_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_13_R1.ChatComponentText; +import net.minecraft.server.v1_13_R1.IChatBaseComponent; +import net.minecraft.server.v1_13_R1.PacketPlayOutScoreboardTeam; + +import java.util.Collection; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutScoreboardTeamWrapper { + + public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { + PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); + + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", IChatBaseComponent.class) + .set(packetPlayOutScoreboardTeam, new ChatComponentText(name)); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) + .set(packetPlayOutScoreboardTeam, "never"); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "f", String.class) + .set(packetPlayOutScoreboardTeam, "never"); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "j", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( + packetPlayOutScoreboardTeam.getClass(), "h", Collection.class); + Collection collection = collectionFieldAccessor.get(packetPlayOutScoreboardTeam); + collection.add(name); + collectionFieldAccessor.set(packetPlayOutScoreboardTeam, collection); + + return packetPlayOutScoreboardTeam; + } + + public PacketPlayOutScoreboardTeam createUnregisterTeam(String name) { + PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); + + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +}