From f74d57962aaf8fd81b4b5c1b900dc3f043dddcc9 Mon Sep 17 00:00:00 2001 From: MrMicky Date: Thu, 26 Apr 2018 13:51:48 +0200 Subject: [PATCH 1/3] Add Maven ! --- .gitignore | 3 +- .../comphenix/tinyprotocol/Reflection.java | 393 -------------- .../comphenix/tinyprotocol/TinyProtocol.java | 501 ------------------ src/net/jitse/npclib/NPCLib.java | 112 ---- src/net/jitse/npclib/NPCManager.java | 35 -- src/net/jitse/npclib/api/NPC.java | 174 ------ .../jitse/npclib/events/NPCDestroyEvent.java | 63 --- .../jitse/npclib/events/NPCInteractEvent.java | 49 -- .../jitse/npclib/events/NPCSpawnEvent.java | 62 --- .../jitse/npclib/events/click/ClickType.java | 13 - .../npclib/events/trigger/TriggerType.java | 6 - .../listeners/packet/PacketListener.java | 71 --- .../player/PlayerChangedWorldListener.java | 35 -- .../player/PlayerMoveOrTeleportListener.java | 71 --- .../listeners/player/PlayerQuitListener.java | 32 -- .../listeners/world/ChunkLoadListener.java | 57 -- .../listeners/world/ChunkUnloadListener.java | 44 -- .../jitse/npclib/nms/holograms/Hologram.java | 148 ------ .../npclib/nms/v1_10_R1/NPC_V1_10_R1.java | 108 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 -- .../PacketPlayOutPlayerInfoWrapper.java | 43 -- .../PacketPlayOutScoreboardTeamWrapper.java | 51 -- .../npclib/nms/v1_11_R1/NPC_V1_11_R1.java | 108 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 -- .../PacketPlayOutPlayerInfoWrapper.java | 43 -- .../PacketPlayOutScoreboardTeamWrapper.java | 51 -- .../npclib/nms/v1_12_R1/NPC_V1_12_R1.java | 109 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutEntityTeleportWrapper.java | 38 -- .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 -- .../PacketPlayOutPlayerInfoWrapper.java | 43 -- .../PacketPlayOutScoreboardTeamWrapper.java | 51 -- .../jitse/npclib/nms/v1_8_R1/NPC_V1_8_R1.java | 107 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 45 -- .../PacketPlayOutPlayerInfoWrapper.java | 35 -- .../PacketPlayOutScoreboardTeamWrapper.java | 53 -- .../jitse/npclib/nms/v1_8_R2/NPC_V1_8_R2.java | 108 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 45 -- .../PacketPlayOutPlayerInfoWrapper.java | 37 -- .../PacketPlayOutScoreboardTeamWrapper.java | 53 -- .../jitse/npclib/nms/v1_8_R3/NPC_V1_8_R3.java | 108 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 45 -- .../PacketPlayOutPlayerInfoWrapper.java | 37 -- .../PacketPlayOutScoreboardTeamWrapper.java | 53 -- .../jitse/npclib/nms/v1_9_R1/NPC_V1_9_R1.java | 108 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 -- .../PacketPlayOutPlayerInfoWrapper.java | 38 -- .../PacketPlayOutScoreboardTeamWrapper.java | 51 -- .../jitse/npclib/nms/v1_9_R2/NPC_V1_9_R2.java | 108 ---- ...acketPlayOutEntityHeadRotationWrapper.java | 26 - .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 -- .../PacketPlayOutPlayerInfoWrapper.java | 44 -- .../PacketPlayOutScoreboardTeamWrapper.java | 51 -- src/net/jitse/npclib/plugin/NPCLibPlugin.java | 68 --- .../npclib/plugin/listeners/NPCListener.java | 34 -- .../jitse/npclib/skin/MineSkinFetcher.java | 63 --- src/net/jitse/npclib/skin/Skin.java | 26 - src/net/jitse/npclib/version/Version.java | 50 -- src/plugin.yml | 5 - 65 files changed, 2 insertions(+), 4327 deletions(-) delete mode 100644 src/com/comphenix/tinyprotocol/Reflection.java delete mode 100644 src/com/comphenix/tinyprotocol/TinyProtocol.java delete mode 100644 src/net/jitse/npclib/NPCLib.java delete mode 100644 src/net/jitse/npclib/NPCManager.java delete mode 100644 src/net/jitse/npclib/api/NPC.java delete mode 100644 src/net/jitse/npclib/events/NPCDestroyEvent.java delete mode 100644 src/net/jitse/npclib/events/NPCInteractEvent.java delete mode 100644 src/net/jitse/npclib/events/NPCSpawnEvent.java delete mode 100644 src/net/jitse/npclib/events/click/ClickType.java delete mode 100644 src/net/jitse/npclib/events/trigger/TriggerType.java delete mode 100644 src/net/jitse/npclib/listeners/packet/PacketListener.java delete mode 100644 src/net/jitse/npclib/listeners/player/PlayerChangedWorldListener.java delete mode 100644 src/net/jitse/npclib/listeners/player/PlayerMoveOrTeleportListener.java delete mode 100644 src/net/jitse/npclib/listeners/player/PlayerQuitListener.java delete mode 100644 src/net/jitse/npclib/listeners/world/ChunkLoadListener.java delete mode 100644 src/net/jitse/npclib/listeners/world/ChunkUnloadListener.java delete mode 100644 src/net/jitse/npclib/nms/holograms/Hologram.java delete mode 100644 src/net/jitse/npclib/nms/v1_10_R1/NPC_V1_10_R1.java delete mode 100644 src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_11_R1/NPC_V1_11_R1.java delete mode 100644 src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_12_R1/NPC_V1_12_R1.java delete mode 100644 src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityTeleportWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R1/NPC_V1_8_R1.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R2/NPC_V1_8_R2.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R3/NPC_V1_8_R3.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R1/NPC_V1_9_R1.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R2/NPC_V1_9_R2.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java delete mode 100644 src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java delete mode 100644 src/net/jitse/npclib/plugin/NPCLibPlugin.java delete mode 100644 src/net/jitse/npclib/plugin/listeners/NPCListener.java delete mode 100644 src/net/jitse/npclib/skin/MineSkinFetcher.java delete mode 100644 src/net/jitse/npclib/skin/Skin.java delete mode 100644 src/net/jitse/npclib/version/Version.java delete mode 100644 src/plugin.yml diff --git a/.gitignore b/.gitignore index 06fec2b..b0ae95e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ out # Maven log/ -target/ \ No newline at end of file +target/ +dependency-reduced-pom.xml \ No newline at end of file diff --git a/src/com/comphenix/tinyprotocol/Reflection.java b/src/com/comphenix/tinyprotocol/Reflection.java deleted file mode 100644 index acf0c5f..0000000 --- a/src/com/comphenix/tinyprotocol/Reflection.java +++ /dev/null @@ -1,393 +0,0 @@ -package com.comphenix.tinyprotocol; - -import org.bukkit.Bukkit; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * An utility class that simplifies reflection in Bukkit plugins. - * - * @author Kristian - */ -public final class Reflection { - /** - * An interface for invoking a specific constructor. - */ - public interface ConstructorInvoker { - /** - * Invoke a constructor for a specific class. - * - * @param arguments - the arguments to pass to the constructor. - * @return The constructed object. - */ - Object invoke(Object... arguments); - } - - /** - * An interface for invoking a specific method. - */ - public interface MethodInvoker { - /** - * Invoke a method on a specific target object. - * - * @param target - the target object, or NULL for a static method. - * @param arguments - the arguments to pass to the method. - * @return The return value, or NULL if is void. - */ - Object invoke(Object target, Object... arguments); - } - - /** - * An interface for retrieving the field content. - * - * @param - field type. - */ - public interface FieldAccessor { - /** - * Retrieve the content of a field. - * - * @param target - the target object, or NULL for a static field. - * @return The value of the field. - */ - T get(Object target); - - /** - * Set the content of a field. - * - * @param target - the target object, or NULL for a static field. - * @param value - the new value of the field. - */ - void set(Object target, Object value); - - /** - * Determine if the given object has this field. - * - * @param target - the object to test. - * @return TRUE if it does, FALSE otherwise. - */ - boolean hasField(Object target); - } - - // Deduce the net.minecraft.server.v* package - private static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName(); - private static String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server"); - private static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "").replace(".", ""); - - // Variable replacement - private static Pattern MATCH_VARIABLE = Pattern.compile("\\{([^}]+)\\}"); - - private Reflection() { - // Seal class - } - - /** - * Retrieve a field accessor for a specific field type and name. - * - * @param target - the target type. - * @param name - the name of the field, or NULL to ignore. - * @param fieldType - a compatible field type. - * @return The field accessor. - */ - public static FieldAccessor getField(Class target, String name, Class fieldType) { - return getField(target, name, fieldType, 0); - } - - /** - * Retrieve a field accessor for a specific field type and name. - * - * @param className - lookup name of the class, see {@link #getClass(String)}. - * @param name - the name of the field, or NULL to ignore. - * @param fieldType - a compatible field type. - * @return The field accessor. - */ - public static FieldAccessor getField(String className, String name, Class fieldType) { - return getField(getClass(className), name, fieldType, 0); - } - - /** - * Retrieve a field accessor for a specific field type and name. - * - * @param target - the target type. - * @param fieldType - a compatible field type. - * @param index - the number of compatible fields to skip. - * @return The field accessor. - */ - public static FieldAccessor getField(Class target, Class fieldType, int index) { - return getField(target, null, fieldType, index); - } - - /** - * Retrieve a field accessor for a specific field type and name. - * - * @param className - lookup name of the class, see {@link #getClass(String)}. - * @param fieldType - a compatible field type. - * @param index - the number of compatible fields to skip. - * @return The field accessor. - */ - public static FieldAccessor getField(String className, Class fieldType, int index) { - return getField(getClass(className), fieldType, index); - } - - // Common method - private static FieldAccessor getField(Class target, String name, Class fieldType, int index) { - for (final Field field : target.getDeclaredFields()) { - if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) { - field.setAccessible(true); - - // A function for retrieving a specific field value - return new FieldAccessor() { - - @Override - @SuppressWarnings("unchecked") - public T get(Object target) { - try { - return (T) field.get(target); - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot access reflection.", e); - } - } - - @Override - public void set(Object target, Object value) { - try { - field.set(target, value); - } catch (IllegalAccessException e) { - throw new RuntimeException("Cannot access reflection.", e); - } - } - - @Override - public boolean hasField(Object target) { - // target instanceof DeclaringClass - return field.getDeclaringClass().isAssignableFrom(target.getClass()); - } - }; - } - } - - // Search in parent classes - if (target.getSuperclass() != null) - return getField(target.getSuperclass(), name, fieldType, index); - - throw new IllegalArgumentException("Cannot find field with type " + fieldType); - } - - /** - * Search for the first publicly and privately defined method of the given name and parameter count. - * - * @param className - lookup name of the class, see {@link #getClass(String)}. - * @param methodName - the method name, or NULL to skip. - * @param params - the expected parameters. - * @return An object that invokes this specific method. - * @throws IllegalStateException If we cannot find this method. - */ - public static MethodInvoker getMethod(String className, String methodName, Class... params) { - return getTypedMethod(getClass(className), methodName, null, params); - } - - /** - * Search for the first publicly and privately defined method of the given name and parameter count. - * - * @param clazz - a class to start with. - * @param methodName - the method name, or NULL to skip. - * @param params - the expected parameters. - * @return An object that invokes this specific method. - * @throws IllegalStateException If we cannot find this method. - */ - public static MethodInvoker getMethod(Class clazz, String methodName, Class... params) { - return getTypedMethod(clazz, methodName, null, params); - } - - /** - * Search for the first publicly and privately defined method of the given name and parameter count. - * - * @param clazz - a class to start with. - * @param methodName - the method name, or NULL to skip. - * @param returnType - the expected return type, or NULL to ignore. - * @param params - the expected parameters. - * @return An object that invokes this specific method. - * @throws IllegalStateException If we cannot find this method. - */ - public static MethodInvoker getTypedMethod(Class clazz, String methodName, Class returnType, Class... params) { - for (final Method method : clazz.getDeclaredMethods()) { - if ((methodName == null || method.getName().equals(methodName)) - && (returnType == null || method.getReturnType().equals(returnType)) - && Arrays.equals(method.getParameterTypes(), params)) { - method.setAccessible(true); - - return (target, arguments) -> { - try { - return method.invoke(target, arguments); - } catch (Exception e) { - throw new RuntimeException("Cannot invoke method " + method, e); - } - }; - } - } - - // Search in every superclass - if (clazz.getSuperclass() != null) - return getMethod(clazz.getSuperclass(), methodName, params); - - throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params))); - } - - /** - * Search for the first publically and privately defined constructor of the given name and parameter count. - * - * @param className - lookup name of the class, see {@link #getClass(String)}. - * @param params - the expected parameters. - * @return An object that invokes this constructor. - * @throws IllegalStateException If we cannot find this method. - */ - public static ConstructorInvoker getConstructor(String className, Class... params) { - return getConstructor(getClass(className), params); - } - - /** - * Search for the first publicly and privately defined constructor of the given name and parameter count. - * - * @param clazz - a class to start with. - * @param params - the expected parameters. - * @return An object that invokes this constructor. - * @throws IllegalStateException If we cannot find this method. - */ - public static ConstructorInvoker getConstructor(Class clazz, Class... params) { - for (final Constructor constructor : clazz.getDeclaredConstructors()) { - if (Arrays.equals(constructor.getParameterTypes(), params)) { - constructor.setAccessible(true); - - return arguments -> { - try { - return constructor.newInstance(arguments); - } catch (Exception e) { - throw new RuntimeException("Cannot invoke constructor " + constructor, e); - } - }; - } - } - - throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params))); - } - - /** - * Retrieve a class from its full name, without knowing its type on compile time. - *

- * This is useful when looking up fields by a NMS or OBC type. - *

- * - * @param lookupName - the class name with variables. - * @return The class. - * @see {@link #getClass()} for more information. - */ - public static Class getUntypedClass(String lookupName) { - @SuppressWarnings({"rawtypes", "unchecked"}) - Class clazz = (Class) getClass(lookupName); - return clazz; - } - - /** - * Retrieve a class from its full name. - *

- * Strings enclosed with curly brackets - such as {TEXT} - will be replaced according to the following table: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
VariableContent
{nms}Actual package name of net.minecraft.server.VERSION
{obc}Actual pacakge name of org.bukkit.craftbukkit.VERSION
{version}The current Minecraft package VERSION, if any.
- * - * @param lookupName - the class name with variables. - * @return The looked up class. - * @throws IllegalArgumentException If a variable or class could not be found. - */ - public static Class getClass(String lookupName) { - return getCanonicalClass(expandVariables(lookupName)); - } - - /** - * Retrieve a class in the net.minecraft.server.VERSION.* package. - * - * @param name - the name of the class, excluding the package. - * @throws IllegalArgumentException If the class doesn't exist. - */ - public static Class getMinecraftClass(String name) { - return getCanonicalClass(NMS_PREFIX + "." + name); - } - - /** - * Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package. - * - * @param name - the name of the class, excluding the package. - * @throws IllegalArgumentException If the class doesn't exist. - */ - public static Class getCraftBukkitClass(String name) { - return getCanonicalClass(OBC_PREFIX + "." + name); - } - - /** - * Retrieve a class by its canonical name. - * - * @param canonicalName - the canonical name. - * @return The class. - */ - private static Class getCanonicalClass(String canonicalName) { - try { - return Class.forName(canonicalName); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Cannot find " + canonicalName, e); - } - } - - /** - * Expand variables such as "{nms}" and "{obc}" to their corresponding packages. - * - * @param name - the full name of the class. - * @return The expanded string. - */ - private static String expandVariables(String name) { - StringBuffer output = new StringBuffer(); - Matcher matcher = MATCH_VARIABLE.matcher(name); - - while (matcher.find()) { - String variable = matcher.group(1); - String replacement; - - // Expand all detected variables - if ("nms".equalsIgnoreCase(variable)) - replacement = NMS_PREFIX; - else if ("obc".equalsIgnoreCase(variable)) - replacement = OBC_PREFIX; - else if ("version".equalsIgnoreCase(variable)) - replacement = VERSION; - else - throw new IllegalArgumentException("Unknown variable: " + variable); - - // Assume the expanded variables are all packages, and append a dot - if (replacement.length() > 0 && matcher.end() < name.length() && name.charAt(matcher.end()) != '.') - replacement += "."; - matcher.appendReplacement(output, Matcher.quoteReplacement(replacement)); - } - - matcher.appendTail(output); - return output.toString(); - } -} \ No newline at end of file diff --git a/src/com/comphenix/tinyprotocol/TinyProtocol.java b/src/com/comphenix/tinyprotocol/TinyProtocol.java deleted file mode 100644 index 5623c08..0000000 --- a/src/com/comphenix/tinyprotocol/TinyProtocol.java +++ /dev/null @@ -1,501 +0,0 @@ -package com.comphenix.tinyprotocol; - -import com.comphenix.tinyprotocol.Reflection.FieldAccessor; -import com.comphenix.tinyprotocol.Reflection.MethodInvoker; -import com.google.common.collect.Lists; -import com.google.common.collect.MapMaker; -import com.mojang.authlib.GameProfile; -import io.netty.channel.*; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.server.PluginDisableEvent; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; - -/** - * Represents a very tiny alternative to ProtocolLib. - *

- * It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)! - * - * @author Kristian - */ -public abstract class TinyProtocol { - private static final AtomicInteger ID = new AtomicInteger(0); - - // Used in order to lookup a channel - private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle"); - private static final FieldAccessor getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class); - private static final FieldAccessor getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class); - private static final FieldAccessor getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0); - - // Looking up ServerConnection - private static final Class minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer"); - private static final Class serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection"); - private static final FieldAccessor getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0); - private static final FieldAccessor getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0); - private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass); - - // Packets we have to intercept - private static final Class PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart"); - private static final FieldAccessor getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0); - - // Speedup channel lookup - private Map channelLookup = new MapMaker().weakValues().makeMap(); - private Listener listener; - - // Channels that have already been removed - private Set uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); - - // List of network markers - private List networkManagers; - - // Injected channel handlers - private List serverChannels = Lists.newArrayList(); - private ChannelInboundHandlerAdapter serverChannelHandler; - private ChannelInitializer beginInitProtocol; - private ChannelInitializer endInitProtocol; - - // Current handler name - private String handlerName; - - protected volatile boolean closed; - protected Plugin plugin; - - /** - * Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients. - *

- * You can construct multiple instances per plugin. - * - * @param plugin - the plugin. - */ - public TinyProtocol(final Plugin plugin) { - this.plugin = plugin; - - // Compute handler name - this.handlerName = getHandlerName(); - - // Prepare existing players - registerBukkitEvents(); - - try { - registerChannelHandler(); - registerPlayers(plugin); - } catch (IllegalArgumentException ex) { - // Damn you, late bind - plugin.getLogger().info("[TinyProtocol] Delaying server channel injection due to late bind."); - - new BukkitRunnable() { - @Override - public void run() { - registerChannelHandler(); - registerPlayers(plugin); - plugin.getLogger().info("[TinyProtocol] Late bind injection successful."); - } - }.runTask(plugin); - } - } - - private void createServerChannelHandler() { - // Handle connected channels - endInitProtocol = new ChannelInitializer() { - - @Override - protected void initChannel(Channel channel) throws Exception { - try { - // This can take a while, so we need to stop the main thread from interfering - synchronized (networkManagers) { - // Stop injecting channels - if (!closed) { - channel.eventLoop().submit(() -> injectChannelInternal(channel)); - } - } - } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e); - } - } - - }; - - // This is executed before Minecraft's channel handler - beginInitProtocol = new ChannelInitializer() { - - @Override - protected void initChannel(Channel channel) throws Exception { - channel.pipeline().addLast(endInitProtocol); - } - - }; - - serverChannelHandler = new ChannelInboundHandlerAdapter() { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - Channel channel = (Channel) msg; - - // Prepare to initialize ths channel - channel.pipeline().addFirst(beginInitProtocol); - ctx.fireChannelRead(msg); - } - - }; - } - - /** - * Register bukkit events. - */ - private void registerBukkitEvents() { - listener = new Listener() { - - @EventHandler(priority = EventPriority.LOWEST) - public final void onPlayerLogin(PlayerLoginEvent e) { - if (closed) - return; - - Channel channel = getChannel(e.getPlayer()); - - // Don't inject players that have been explicitly uninjected - if (!uninjectedChannels.contains(channel)) { - injectPlayer(e.getPlayer()); - } - } - - @EventHandler - public final void onPluginDisable(PluginDisableEvent e) { - if (e.getPlugin().equals(plugin)) { - close(); - } - } - - }; - - plugin.getServer().getPluginManager().registerEvents(listener, plugin); - } - - @SuppressWarnings("unchecked") - private void registerChannelHandler() { - Object mcServer = getMinecraftServer.get(Bukkit.getServer()); - Object serverConnection = getServerConnection.get(mcServer); - boolean looking = true; - - // We need to synchronize against this list - networkManagers = (List) getNetworkMarkers.invoke(null, serverConnection); - createServerChannelHandler(); - - // Find the correct list, or implicitly throw an exception - for (int i = 0; looking; i++) { - List list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); - - for (Object item : list) { - if (!ChannelFuture.class.isInstance(item)) - break; - - // Channel future that contains the server connection - Channel serverChannel = ((ChannelFuture) item).channel(); - - serverChannels.add(serverChannel); - serverChannel.pipeline().addFirst(serverChannelHandler); - looking = false; - } - } - } - - private void unregisterChannelHandler() { - if (serverChannelHandler == null) - return; - - for (Channel serverChannel : serverChannels) { - final ChannelPipeline pipeline = serverChannel.pipeline(); - - // Remove channel handler - serverChannel.eventLoop().execute(new Runnable() { - - @Override - public void run() { - try { - pipeline.remove(serverChannelHandler); - } catch (NoSuchElementException e) { - // That's fine - } - } - - }); - } - } - - private void registerPlayers(Plugin plugin) { - for (Player player : plugin.getServer().getOnlinePlayers()) { - injectPlayer(player); - } - } - - /** - * Invoked when the server is starting to send a packet to a player. - *

- * Note that this is not executed on the main thread. - * - * @param receiver - the receiving player, NULL for early login/status packets. - * @param channel - the channel that received the packet. Never NULL. - * @param packet - the packet being sent. - * @return The packet to send instead, or NULL to cancel the transmission. - */ - public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) { - return packet; - } - - /** - * Invoked when the server has received a packet from a given player. - *

- * Use {@link Channel#remoteAddress()} to get the remote address of the client. - * - * @param sender - the player that sent the packet, NULL for early login/status packets. - * @param channel - channel that received the packet. Never NULL. - * @param packet - the packet being received. - * @return The packet to recieve instead, or NULL to cancel. - */ - public Object onPacketInAsync(Player sender, Channel channel, Object packet) { - return packet; - } - - /** - * Send a packet to a particular player. - *

- * Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet. - * - * @param player - the destination player. - * @param packet - the packet to send. - */ - public void sendPacket(Player player, Object packet) { - sendPacket(getChannel(player), packet); - } - - /** - * Send a packet to a particular client. - *

- * Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet. - * - * @param channel - client identified by a channel. - * @param packet - the packet to send. - */ - public void sendPacket(Channel channel, Object packet) { - channel.pipeline().writeAndFlush(packet); - } - - /** - * Pretend that a given packet has been received from a player. - *

- * Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet. - * - * @param player - the player that sent the packet. - * @param packet - the packet that will be received by the server. - */ - public void receivePacket(Player player, Object packet) { - receivePacket(getChannel(player), packet); - } - - /** - * Pretend that a given packet has been received from a given client. - *

- * Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet. - * - * @param channel - client identified by a channel. - * @param packet - the packet that will be received by the server. - */ - public void receivePacket(Channel channel, Object packet) { - channel.pipeline().context("encoder").fireChannelRead(packet); - } - - /** - * Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID. - *

- * Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances. - * - * @return A unique channel handler name. - */ - protected String getHandlerName() { - return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet(); - } - - /** - * Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets. - *

- * This will automatically be called when a player has logged in. - * - * @param player - the player to inject. - */ - public void injectPlayer(Player player) { - injectChannelInternal(getChannel(player)).player = player; - } - - /** - * Add a custom channel handler to the given channel. - * - * @param channel - the channel to inject. - */ - public void injectChannel(Channel channel) { - injectChannelInternal(channel); - } - - /** - * Add a custom channel handler to the given channel. - * - * @param channel - the channel to inject. - * @return The packet interceptor. - */ - private PacketInterceptor injectChannelInternal(Channel channel) { - try { - PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName); - - // Inject our packet interceptor - if (interceptor == null) { - interceptor = new PacketInterceptor(); - channel.pipeline().addBefore("packet_handler", handlerName, interceptor); - uninjectedChannels.remove(channel); - } - - return interceptor; - } catch (IllegalArgumentException e) { - // Try again - return (PacketInterceptor) channel.pipeline().get(handlerName); - } - } - - /** - * Retrieve the Netty channel associated with a player. This is cached. - * - * @param player - the player. - * @return The Netty channel. - */ - public Channel getChannel(Player player) { - Channel channel = channelLookup.get(player.getName()); - - // Lookup channel again - if (channel == null) { - Object connection = getConnection.get(getPlayerHandle.invoke(player)); - Object manager = getManager.get(connection); - - channelLookup.put(player.getName(), channel = getChannel.get(manager)); - } - - return channel; - } - - /** - * Uninject a specific player. - * - * @param player - the injected player. - */ - public void uninjectPlayer(Player player) { - uninjectChannel(getChannel(player)); - } - - /** - * Uninject a specific channel. - *

- * This will also disable the automatic channel injection that occurs when a player has properly logged in. - * - * @param channel - the injected channel. - */ - public void uninjectChannel(final Channel channel) { - // No need to guard against this if we're closing - if (!closed) { - uninjectedChannels.add(channel); - } - - // See ChannelInjector in ProtocolLib, line 590 - channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName)); - } - - /** - * Determine if the given player has been injected by TinyProtocol. - * - * @param player - the player. - * @return TRUE if it is, FALSE otherwise. - */ - public boolean hasInjected(Player player) { - return hasInjected(getChannel(player)); - } - - /** - * Determine if the given channel has been injected by TinyProtocol. - * - * @param channel - the channel. - * @return TRUE if it is, FALSE otherwise. - */ - public boolean hasInjected(Channel channel) { - return channel.pipeline().get(handlerName) != null; - } - - /** - * Cease listening for packets. This is called automatically when your plugin is disabled. - */ - public final void close() { - if (!closed) { - closed = true; - - // Remove our handlers - for (Player player : plugin.getServer().getOnlinePlayers()) { - uninjectPlayer(player); - } - - // Clean up Bukkit - HandlerList.unregisterAll(listener); - unregisterChannelHandler(); - } - } - - /** - * Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets. - * - * @author Kristian - */ - private final class PacketInterceptor extends ChannelDuplexHandler { - // Updated by the login event - public volatile Player player; - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - // Intercept channel - final Channel channel = ctx.channel(); - handleLoginStart(channel, msg); - - try { - msg = onPacketInAsync(player, channel, msg); - } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e); - } - - if (msg != null) { - super.channelRead(ctx, msg); - } - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - try { - msg = onPacketOutAsync(player, ctx.channel(), msg); - } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e); - } - - if (msg != null) { - super.write(ctx, msg, promise); - } - } - - private void handleLoginStart(Channel channel, Object packet) { - if (PACKET_LOGIN_IN_START.isInstance(packet)) { - GameProfile profile = getGameProfile.get(packet); - channelLookup.put(profile.getName(), channel); - } - } - } -} \ No newline at end of file diff --git a/src/net/jitse/npclib/NPCLib.java b/src/net/jitse/npclib/NPCLib.java deleted file mode 100644 index b154612..0000000 --- a/src/net/jitse/npclib/NPCLib.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.listeners.packet.PacketListener; -import net.jitse.npclib.listeners.player.PlayerChangedWorldListener; -import net.jitse.npclib.listeners.player.PlayerMoveOrTeleportListener; -import net.jitse.npclib.listeners.player.PlayerQuitListener; -import net.jitse.npclib.listeners.world.ChunkLoadListener; -import net.jitse.npclib.listeners.world.ChunkUnloadListener; -import net.jitse.npclib.skin.Skin; -import net.jitse.npclib.version.Version; -import org.bukkit.ChatColor; -import org.bukkit.Server; -import org.bukkit.plugin.PluginManager; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPCLib { - - private final Server server; - private final JavaPlugin plugin; - private final Version version; - - public NPCLib(JavaPlugin plugin) { - this.plugin = plugin; - this.server = plugin.getServer(); - - String versionName = server.getClass().getPackage().getName().split("\\.")[3]; - version = Version.getByName(versionName).orElse(null); - - if (version == null) { - server.getConsoleSender().sendMessage(ChatColor.RED + "NPCLib failed to initiate. Your server's version (" - + versionName + ") is not supported."); - } - - server.getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + ChatColor.WHITE + "Enabled for version " + version.toString() + "."); - - registerInternal(); - } - - private void registerInternal() { - PluginManager pluginManager = server.getPluginManager(); - - pluginManager.registerEvents(new PlayerChangedWorldListener(), plugin); - pluginManager.registerEvents(new PlayerQuitListener(), plugin); - pluginManager.registerEvents(new PlayerMoveOrTeleportListener(), plugin); - pluginManager.registerEvents(new ChunkLoadListener(), plugin); - pluginManager.registerEvents(new ChunkUnloadListener(), plugin); - - new PacketListener().start(plugin); - } - - /** - * Create a new non-player character (NPC). - * - * @param skin The skin you want the NPC to have. - * @param autoHideDistance Distance from where you want to NPC to hide from the player (50 recommended). - * @param lines The text you want to sendShowPackets above the NPC (null = no text). - * @return The NPC object you may use to sendShowPackets it to players. - */ - public NPC createNPC(Skin skin, double autoHideDistance, List lines) { - try { - return version.createNPC(plugin, skin, autoHideDistance, lines); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException exception) { - server.getConsoleSender().sendMessage(ChatColor.RED + "NPCLib failed to create NPC. Please report this stacktrace:"); - exception.printStackTrace(); - } - - return null; - } - - /** - * Create a new non-player character (NPC). - * - * @param skin The skin you want the NPC to have. - * @param lines The text you want to sendShowPackets above the NPC (null = no text). - * @return The NPC object you may use to sendShowPackets it to players. - */ - public NPC createNPC(Skin skin, List lines) { - return createNPC(skin, 50, lines); - } - - - /** - * Create a new non-player character (NPC). - * - * @param skin The skin you want the NPC to have. - * @return The NPC object you may use to sendShowPackets it to players. - */ - public NPC createNPC(Skin skin) { - return createNPC(skin, 50, null); - } - - - /** - * Create a new non-player character (NPC). - * - * @return The NPC object you may use to sendShowPackets it to players. - */ - public NPC createNPC() { - return createNPC(null, 50, null); - } -} diff --git a/src/net/jitse/npclib/NPCManager.java b/src/net/jitse/npclib/NPCManager.java deleted file mode 100644 index 476ea46..0000000 --- a/src/net/jitse/npclib/NPCManager.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib; - -import net.jitse.npclib.api.NPC; - -import java.util.HashSet; -import java.util.Set; - -/** - * @author Jitse Boonstra - */ -public final class NPCManager { - - private static Set npcs = new HashSet<>(); - - public static Set getAllNPCs() { - return npcs; - } - - public static void add(NPC npc) { - npcs.add(npc); - } - - public static void remove(NPC npc) { - npcs.remove(npc); - } - - private NPCManager() { - throw new SecurityException("You cannot initialize this class."); - } - -} diff --git a/src/net/jitse/npclib/api/NPC.java b/src/net/jitse/npclib/api/NPC.java deleted file mode 100644 index de88353..0000000 --- a/src/net/jitse/npclib/api/NPC.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.api; - -import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.events.NPCDestroyEvent; -import net.jitse.npclib.events.NPCSpawnEvent; -import net.jitse.npclib.events.trigger.TriggerType; -import net.jitse.npclib.skin.Skin; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.*; - -/** - * @author Jitse Boonstra - */ -public abstract class NPC { - - protected final UUID uuid = UUID.randomUUID(); - protected final String name = uuid.toString().replace("-", "").substring(0, 10); - protected final int entityId = (int) Math.ceil(Math.random() * 100000) + 100000; - - private final Set shown = new HashSet<>(); - private final Set autoHidden = new HashSet<>(); - - protected final double autoHideDistance; - protected final Skin skin; - protected final List lines; - - protected JavaPlugin plugin; - protected GameProfile gameProfile; - protected Location location; - - public NPC(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - this.plugin = plugin; - this.skin = skin; - this.autoHideDistance = autoHideDistance; - this.lines = (lines == null ? Collections.emptyList() : lines); - - NPCManager.add(this); - } - - protected GameProfile generateGameProfile(UUID uuid, String name) { - GameProfile gameProfile = new GameProfile(uuid, name); - - if (skin != null) { - gameProfile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature())); - } - - return gameProfile; - } - - public void destroy() { - NPCManager.remove(this); - - // Destroy NPC for every player that is still seeing it. - for (UUID uuid : shown) { - if (autoHidden.contains(uuid)) { - continue; - } - - hide(Bukkit.getPlayer(uuid), true); - } - } - - public Set getShown() { - return shown; - } - - public Set getAutoHidden() { - return autoHidden; - } - - public Location getLocation() { - return location; - } - - public double getAutoHideDistance() { - return autoHideDistance; - } - - public int getEntityId() { - return entityId; - } - - public boolean isActuallyShown(Player player) { - return shown.contains(player.getUniqueId()) && !autoHidden.contains(player.getUniqueId()); - } - - // Generate packets. - public abstract void create(Location location); - - public void show(Player player) { - show(player, false); - } - - public void show(Player player, boolean auto) { - NPCSpawnEvent event = new NPCSpawnEvent(this, player, auto ? TriggerType.AUTOMATIC : TriggerType.MANUAL); - plugin.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - - if (auto) { - sendShowPackets(player); - } else { - if (shown.contains(player.getUniqueId())) { - throw new RuntimeException("Cannot call show method twice."); - } - - shown.add(player.getUniqueId()); - - if (player.getLocation().distance(location) <= autoHideDistance) { - sendShowPackets(player); - } else { - if (!autoHidden.contains(player.getUniqueId())) { - autoHidden.add(player.getUniqueId()); - } - } - } - } - - // Internal method. - protected abstract void sendShowPackets(Player player); - - public void hide(Player player) { - hide(player, false); - } - - public void hide(Player player, boolean auto) { - NPCDestroyEvent event = new NPCDestroyEvent(this, player, auto ? TriggerType.AUTOMATIC : TriggerType.MANUAL); - plugin.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - - if (auto) { - sendHidePackets(player); - } else { - if (!shown.contains(player.getUniqueId())) { - throw new RuntimeException("Cannot call hide method without calling NPC#show."); - } - - shown.remove(player.getUniqueId()); - - if (player.getWorld().equals(location.getWorld()) && player.getLocation().distance(location) <= autoHideDistance) { - sendHidePackets(player); - } else { - if (autoHidden.contains(player.getUniqueId())) { - autoHidden.remove(player.getUniqueId()); - } - } - } - } - - // Internal method. - protected abstract void sendHidePackets(Player player); - - public void teleport(Player player, Location location) { - this.location = location; - - sendTeleportationPackets(player); - } - - // Internal method. - public abstract void sendTeleportationPackets(Player player); -} diff --git a/src/net/jitse/npclib/events/NPCDestroyEvent.java b/src/net/jitse/npclib/events/NPCDestroyEvent.java deleted file mode 100644 index 6fc0c36..0000000 --- a/src/net/jitse/npclib/events/NPCDestroyEvent.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.events; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.events.trigger.TriggerType; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * @author Jitse Boonstra - */ -public class NPCDestroyEvent extends Event implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - - private boolean cancelled = false; - - private final NPC npc; - private final Player player; - private final TriggerType trigger; - - public NPCDestroyEvent(NPC npc, Player player, TriggerType trigger) { - this.npc = npc; - this.player = player; - this.trigger = trigger; - } - - @Override - public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; - } - - public NPC getNPC() { - return npc; - } - - public Player getPlayer() { - return player; - } - - public TriggerType getTrigger() { - return trigger; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} - diff --git a/src/net/jitse/npclib/events/NPCInteractEvent.java b/src/net/jitse/npclib/events/NPCInteractEvent.java deleted file mode 100644 index ae79a44..0000000 --- a/src/net/jitse/npclib/events/NPCInteractEvent.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.events; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.events.click.ClickType; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * @author Jitse Boonstra - */ -public class NPCInteractEvent extends Event { - - private static final HandlerList handlers = new HandlerList(); - - private final Player player; - private final ClickType clickType; - private final NPC npc; - - public NPCInteractEvent(Player player, ClickType clickType, NPC npc) { - this.player = player; - this.clickType = clickType; - this.npc = npc; - } - - public Player getWhoClicked() { - return this.player; - } - - public ClickType getClickType() { - return this.clickType; - } - - public NPC getNPC() { - return this.npc; - } - - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/src/net/jitse/npclib/events/NPCSpawnEvent.java b/src/net/jitse/npclib/events/NPCSpawnEvent.java deleted file mode 100644 index 5d4ba73..0000000 --- a/src/net/jitse/npclib/events/NPCSpawnEvent.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.events; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.events.trigger.TriggerType; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * @author Jitse Boonstra - */ -public class NPCSpawnEvent extends Event implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - - private boolean cancelled = false; - - private final NPC npc; - private final Player player; - private final TriggerType trigger; - - public NPCSpawnEvent(NPC npc, Player player, TriggerType trigger) { - this.npc = npc; - this.player = player; - this.trigger = trigger; - } - - @Override - public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; - } - - public NPC getNPC() { - return npc; - } - - public Player getPlayer() { - return player; - } - - public TriggerType getTrigger() { - return trigger; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - public HandlerList getHandlers() { - return handlers; - } - - public static HandlerList getHandlerList() { - return handlers; - } -} diff --git a/src/net/jitse/npclib/events/click/ClickType.java b/src/net/jitse/npclib/events/click/ClickType.java deleted file mode 100644 index f8d84a7..0000000 --- a/src/net/jitse/npclib/events/click/ClickType.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.events.click; - -/** - * @author Jitse Boonstra - */ -public enum ClickType { - - LEFT_CLICK, RIGHT_CLICK -} diff --git a/src/net/jitse/npclib/events/trigger/TriggerType.java b/src/net/jitse/npclib/events/trigger/TriggerType.java deleted file mode 100644 index 824db90..0000000 --- a/src/net/jitse/npclib/events/trigger/TriggerType.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.jitse.npclib.events.trigger; - -public enum TriggerType { - - MANUAL, AUTOMATIC -} diff --git a/src/net/jitse/npclib/listeners/packet/PacketListener.java b/src/net/jitse/npclib/listeners/packet/PacketListener.java deleted file mode 100644 index 432c273..0000000 --- a/src/net/jitse/npclib/listeners/packet/PacketListener.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.listeners.packet; - -import com.comphenix.tinyprotocol.Reflection; -import com.comphenix.tinyprotocol.TinyProtocol; -import io.netty.channel.Channel; -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.events.NPCInteractEvent; -import net.jitse.npclib.events.click.ClickType; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -/** - * @author Jitse Boonstra - */ -public class PacketListener { - - // Classes: - private final Class packetPlayInUseEntityClazz = Reflection.getMinecraftClass("PacketPlayInUseEntity"); - - // Fields: - private final Reflection.FieldAccessor entityIdField = Reflection.getField(packetPlayInUseEntityClazz, "a", int.class); - private final Reflection.FieldAccessor actionField = Reflection.getField(packetPlayInUseEntityClazz, "action", Object.class); - - // Prevent players from clicking at very high speeds. - private final Set delay = new HashSet<>(); - - public void start(JavaPlugin plugin) { - new TinyProtocol(plugin) { - - @Override - public Object onPacketInAsync(Player player, Channel channel, Object packet) { - if (packetPlayInUseEntityClazz.isInstance(packet)) { - NPC npc = NPCManager.getAllNPCs().stream().filter( - check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet)) - .findFirst().orElse(null); - - if (npc == null) { - // Default player, not doing magic with the packet. - return super.onPacketInAsync(player, channel, packet); - } - - if (delay.contains(player.getUniqueId())) { - return null; - } - - ClickType clickType = actionField.get(packet).toString() - .equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK; - - Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc)); - - UUID uuid = player.getUniqueId(); - delay.add(uuid); - Bukkit.getScheduler().runTaskLater(plugin, () -> delay.remove(uuid), 1); - return null; - } else { - return super.onPacketInAsync(player, channel, packet); - } - } - }; - } -} diff --git a/src/net/jitse/npclib/listeners/player/PlayerChangedWorldListener.java b/src/net/jitse/npclib/listeners/player/PlayerChangedWorldListener.java deleted file mode 100644 index 11a83ca..0000000 --- a/src/net/jitse/npclib/listeners/player/PlayerChangedWorldListener.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.listeners.player; - -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.api.NPC; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerChangedWorldEvent; - -/** - * @author Jitse Boonstra - */ -public class PlayerChangedWorldListener implements Listener { - - @EventHandler - public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { - Player player = event.getPlayer(); - World from = event.getFrom(); - - // The PlayerTeleportEvent is call, and will handle visibility in the new world. - for (NPC npc : NPCManager.getAllNPCs()) { - if (npc.getLocation().getWorld().equals(from)) { - if (!npc.getAutoHidden().contains(player.getUniqueId())) { - npc.getAutoHidden().add(player.getUniqueId()); - npc.hide(player, true); - } - } - } - } -} diff --git a/src/net/jitse/npclib/listeners/player/PlayerMoveOrTeleportListener.java b/src/net/jitse/npclib/listeners/player/PlayerMoveOrTeleportListener.java deleted file mode 100644 index b4e42c6..0000000 --- a/src/net/jitse/npclib/listeners/player/PlayerMoveOrTeleportListener.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.listeners.player; - -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.api.NPC; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerTeleportEvent; - -/** - * @author Jitse Boonstra - */ -public class PlayerMoveOrTeleportListener implements Listener { - - @EventHandler - public void onPlayerMove(PlayerMoveEvent event) { - Location from = event.getFrom(); - Location to = event.getTo(); - - if (from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ()) { - return; - } - - handleMove(event.getPlayer()); - } - - @EventHandler - public void onPlayerTeleport(PlayerTeleportEvent event) { - handleMove(event.getPlayer()); - } - - private void handleMove(Player player) { - World world = player.getWorld(); - for (NPC npc : NPCManager.getAllNPCs()) { - if (!npc.getShown().contains(player.getUniqueId())) { - continue; // NPC was never supposed to be shown to the player. - } - - if (!npc.getLocation().getWorld().equals(world)) { - continue; // NPC is not in the same world. - } - - // If Bukkit doesn't track the NPC entity anymore, bypass the hiding distance variable. - // This will cause issues otherwise (e.g. custom skin disappearing). - double hideDistance = npc.getAutoHideDistance(); - double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); - boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4); - if (npc.getAutoHidden().contains(player.getUniqueId())) { - // Check if the player and NPC are within the range to sendShowPackets it again. - if (inRange) { - npc.show(player, true); - npc.getAutoHidden().remove(player.getUniqueId()); - } - } else { - // Check if the player and NPC are out of range to sendHidePackets it. - if (!inRange) { - npc.hide(player, true); - npc.getAutoHidden().add(player.getUniqueId()); - } - } - } - } -} diff --git a/src/net/jitse/npclib/listeners/player/PlayerQuitListener.java b/src/net/jitse/npclib/listeners/player/PlayerQuitListener.java deleted file mode 100644 index becb046..0000000 --- a/src/net/jitse/npclib/listeners/player/PlayerQuitListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.listeners.player; - -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.api.NPC; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; - -/** - * @author Jitse Boonstra - */ -public class PlayerQuitListener implements Listener { - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - for (NPC npc : NPCManager.getAllNPCs()) { - if (npc.getAutoHidden().contains(player.getUniqueId())) { - npc.getAutoHidden().remove(player.getUniqueId()); - } - - if (npc.isActuallyShown(player)) { - npc.hide(player); - } - } - } -} diff --git a/src/net/jitse/npclib/listeners/world/ChunkLoadListener.java b/src/net/jitse/npclib/listeners/world/ChunkLoadListener.java deleted file mode 100644 index 618c6cd..0000000 --- a/src/net/jitse/npclib/listeners/world/ChunkLoadListener.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.listeners.world; - -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.api.NPC; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; - -import java.util.UUID; - -/** - * @author Jitse Boonstra - */ -public class ChunkLoadListener implements Listener { - - @EventHandler - public void onChunkLoad(ChunkLoadEvent event) { - Chunk chunk = event.getChunk(); - - for (NPC npc : NPCManager.getAllNPCs()) { - Chunk npcChunk = npc.getLocation().getChunk(); - - if (chunk.equals(npcChunk)) { - // Loaded chunk with NPC in it. Showing it to the players again. - - for (UUID uuid : npc.getShown()) { - // Make sure not to respawn a not-hidden NPC. - if (!npc.getAutoHidden().contains(uuid)) { - continue; - } - - Player player = Bukkit.getPlayer(uuid); - - if (!npcChunk.getWorld().equals(player.getWorld())) { - continue; // Player and NPC are not in the same world. - } - - double hideDistance = npc.getAutoHideDistance(); - double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); - boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4); - - // Show the NPC (if in range). - if (inRange) { - npc.show(Bukkit.getPlayer(uuid), true); - } - } - } - } - } -} diff --git a/src/net/jitse/npclib/listeners/world/ChunkUnloadListener.java b/src/net/jitse/npclib/listeners/world/ChunkUnloadListener.java deleted file mode 100644 index a88bbe9..0000000 --- a/src/net/jitse/npclib/listeners/world/ChunkUnloadListener.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.listeners.world; - -import net.jitse.npclib.NPCManager; -import net.jitse.npclib.api.NPC; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkUnloadEvent; - -import java.util.UUID; - -/** - * @author Jitse Boonstra - */ -public class ChunkUnloadListener implements Listener { - - @EventHandler - public void onChunkUnload(ChunkUnloadEvent event) { - Chunk chunk = event.getChunk(); - - for (NPC npc : NPCManager.getAllNPCs()) { - Chunk npcChunk = npc.getLocation().getChunk(); - - if (chunk.equals(npcChunk)) { - // Unloaded chunk with NPC in it. Hiding it from all players currently shown to. - - for (UUID uuid : npc.getShown()) { - // Safety check so it doesn't send packets if the NPC has already - // been automatically despawned by the system. - if (npc.getAutoHidden().contains(uuid)) { - continue; - } - - npc.hide(Bukkit.getPlayer(uuid), true); - } - } - } - } -} diff --git a/src/net/jitse/npclib/nms/holograms/Hologram.java b/src/net/jitse/npclib/nms/holograms/Hologram.java deleted file mode 100644 index 6512eb5..0000000 --- a/src/net/jitse/npclib/nms/holograms/Hologram.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.holograms; - -import com.comphenix.tinyprotocol.Reflection; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @author Jitse Boonstra - */ -public class Hologram { - - private final double delta = 0.3; - - private List armorStands = new ArrayList<>(); - private Set spawnPackets = new HashSet<>(); - private Set destroyPackets = new HashSet<>(); - - // Classes: - private static final Class ENTITY_ARMOR_STAND_CLAZZ = Reflection.getMinecraftClass("EntityArmorStand"); - private static final Class ENTITY_LIVING_CLAZZ = Reflection.getMinecraftClass("EntityLiving"); - private static final Class ENTITY_CLAZZ = Reflection.getMinecraftClass("Entity"); - private static final Class CRAFT_BUKKIT_CLASS = Reflection.getCraftBukkitClass("CraftWorld"); - private static final Class CRAFT_PLAYER_CLAZZ = Reflection.getCraftBukkitClass("entity.CraftPlayer"); - private static final Class PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CLAZZ = Reflection.getMinecraftClass( - "PacketPlayOutSpawnEntityLiving"); - private static final Class PACKET_PLAY_OUT_ENTITY_DESTROY_CLAZZ = Reflection.getMinecraftClass( - "PacketPlayOutEntityDestroy"); - private static final Class ENTITY_PLAYER_CLAZZ = Reflection.getMinecraftClass("EntityPlayer"); - private static final Class PLAYER_CONNECTION_CLAZZ = Reflection.getMinecraftClass("PlayerConnection"); - private static final Class PACKET_CLAZZ = Reflection.getMinecraftClass("Packet"); - - // Constructors: - private static final Reflection.ConstructorInvoker PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CONSTRUCTOR = Reflection - .getConstructor(PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CLAZZ, ENTITY_LIVING_CLAZZ); - private static final Reflection.ConstructorInvoker PACKET_PLAY_OUT_ENTITY_DESTROY_CONSTRUCTOR = Reflection - .getConstructor(PACKET_PLAY_OUT_ENTITY_DESTROY_CLAZZ, int[].class); - - // Fields: - private static final Reflection.FieldAccessor playerConnectionField = Reflection.getField(ENTITY_PLAYER_CLAZZ, - "playerConnection", PLAYER_CONNECTION_CLAZZ); - - // Methods: - private static final Reflection.MethodInvoker SET_LOCATION_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setLocation", double.class, double.class, double.class, float.class, float.class); - private static final Reflection.MethodInvoker SET_CUSTOM_NAME_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setCustomName", String.class); - private static final Reflection.MethodInvoker SET_CUSTOM_NAME_VISIBLE_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setCustomNameVisible", boolean.class); - private static final Reflection.MethodInvoker SET_SMALL_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setSmall", boolean.class); - private static final Reflection.MethodInvoker SET_INVISIBLE_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setInvisible", boolean.class); - private static final Reflection.MethodInvoker SET_BASE_PLATE_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setBasePlate", boolean.class); - private static final Reflection.MethodInvoker SET_ARMS_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setArms", boolean.class); - private static final Reflection.MethodInvoker PLAYER_GET_HANDLE_METHOD = Reflection.getMethod(CRAFT_PLAYER_CLAZZ, - "getHandle"); - private static final Reflection.MethodInvoker SEND_PACKET_METHOD = Reflection.getMethod(PLAYER_CONNECTION_CLAZZ, - "sendPacket", PACKET_CLAZZ); - private static final Reflection.MethodInvoker GET_ID_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "getId"); - - private final Location start; - private final List lines; - private final Object worldServer; - - public Hologram(Location location, List lines) { - this.start = location; - this.lines = lines; - - this.worldServer = Reflection.getMethod(CRAFT_BUKKIT_CLASS, "getHandle") - .invoke(CRAFT_BUKKIT_CLASS.cast(location.getWorld())); - - } - - public void generatePackets(boolean above1_9_r2) { - Reflection.MethodInvoker gravityMethod = (above1_9_r2 ? Reflection.getMethod(ENTITY_CLAZZ, - "setNoGravity", boolean.class) : Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, - "setGravity", boolean.class)); - - Location location = start.clone().add(0, delta * lines.size(), 0); - Class worldClass = worldServer.getClass().getSuperclass(); - - if (start.getWorld().getEnvironment() != World.Environment.NORMAL) { - worldClass = worldClass.getSuperclass(); - } - - Reflection.ConstructorInvoker entityArmorStandConstructor = Reflection - .getConstructor(ENTITY_ARMOR_STAND_CLAZZ, worldClass); - - for (String line : lines) { - Object entityArmorStand = entityArmorStandConstructor.invoke(worldServer); - - SET_LOCATION_METHOD.invoke(entityArmorStand, location.getX(), location.getY(), location.getZ(), 0, 0); - SET_CUSTOM_NAME_METHOD.invoke(entityArmorStand, line); - SET_CUSTOM_NAME_VISIBLE_METHOD.invoke(entityArmorStand, true); - gravityMethod.invoke(entityArmorStand, above1_9_r2); - SET_SMALL_METHOD.invoke(entityArmorStand, true); - SET_INVISIBLE_METHOD.invoke(entityArmorStand, true); - SET_BASE_PLATE_METHOD.invoke(entityArmorStand, false); - SET_ARMS_METHOD.invoke(entityArmorStand, false); - - location.subtract(0, delta, 0); - - if (line.isEmpty()) { - continue; - } - - armorStands.add(entityArmorStand); - - Object spawnPacket = PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CONSTRUCTOR.invoke(entityArmorStand); - spawnPackets.add(spawnPacket); - - Object destroyPacket = PACKET_PLAY_OUT_ENTITY_DESTROY_CONSTRUCTOR - .invoke(new int[]{(int) GET_ID_METHOD.invoke(entityArmorStand)}); - destroyPackets.add(destroyPacket); - } - } - - public void spawn(Player player) { - Object playerConnection = playerConnectionField.get(PLAYER_GET_HANDLE_METHOD - .invoke(CRAFT_PLAYER_CLAZZ.cast(player))); - - for (Object packet : spawnPackets) { - SEND_PACKET_METHOD.invoke(playerConnection, packet); - } - } - - public void destroy(Player player) { - Object playerConnection = playerConnectionField.get(PLAYER_GET_HANDLE_METHOD - .invoke(CRAFT_PLAYER_CLAZZ.cast(player))); - - for (Object packet : destroyPackets) { - SEND_PACKET_METHOD.invoke(playerConnection, packet); - } - } -} diff --git a/src/net/jitse/npclib/nms/v1_10_R1/NPC_V1_10_R1.java b/src/net/jitse/npclib/nms/v1_10_R1/NPC_V1_10_R1.java deleted file mode 100644 index 315f508..0000000 --- a/src/net/jitse/npclib/nms/v1_10_R1/NPC_V1_10_R1.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_10_R1; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_10_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPC_V1_10_R1 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_10_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().subtract(0, 0.5, 0), lines); - hologram.generatePackets(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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 86a6457..0000000 --- a/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_10_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_10_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/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index 3a81184..0000000 --- a/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_10_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_10_R1.DataWatcher; -import net.minecraft.server.v1_10_R1.DataWatcherObject; -import net.minecraft.server.v1_10_R1.DataWatcherRegistry; -import net.minecraft.server.v1_10_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/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index d07e54a..0000000 --- a/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_10_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_10_R1.EnumGamemode; -import net.minecraft.server.v1_10_R1.IChatBaseComponent; -import net.minecraft.server.v1_10_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/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index 9d66c1f..0000000 --- a/src/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_10_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_10_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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_11_R1/NPC_V1_11_R1.java b/src/net/jitse/npclib/nms/v1_11_R1/NPC_V1_11_R1.java deleted file mode 100644 index 0ad2666..0000000 --- a/src/net/jitse/npclib/nms/v1_11_R1/NPC_V1_11_R1.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_11_R1; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_11_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPC_V1_11_R1 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_11_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); - hologram.generatePackets(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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 6de5178..0000000 --- a/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_11_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_11_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/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index d6e1cff..0000000 --- a/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_11_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_11_R1.DataWatcher; -import net.minecraft.server.v1_11_R1.DataWatcherObject; -import net.minecraft.server.v1_11_R1.DataWatcherRegistry; -import net.minecraft.server.v1_11_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/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index 52413e5..0000000 --- a/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_11_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_11_R1.EnumGamemode; -import net.minecraft.server.v1_11_R1.IChatBaseComponent; -import net.minecraft.server.v1_11_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/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index 72f6f3b..0000000 --- a/src/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_11_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_11_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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_12_R1/NPC_V1_12_R1.java b/src/net/jitse/npclib/nms/v1_12_R1/NPC_V1_12_R1.java deleted file mode 100644 index 3c61459..0000000 --- a/src/net/jitse/npclib/nms/v1_12_R1/NPC_V1_12_R1.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_12_R1; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_12_R1.packets.*; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_12_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPC_V1_12_R1 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_12_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); - hologram.generatePackets(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); - - // Todo: Test this new delay speed (custom skin render issue). - Bukkit.getScheduler().runTaskLater(plugin, () -> - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove), 10); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - PacketPlayOutEntityTeleport packetPlayOutEntityTeleport = new PacketPlayOutEntityTeleportWrapper().create(entityId, location); - - playerConnection.sendPacket(packetPlayOutEntityTeleport); - } -} diff --git a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 2abba78..0000000 --- a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_12_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_12_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/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityTeleportWrapper.java b/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityTeleportWrapper.java deleted file mode 100644 index a1eeba3..0000000 --- a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityTeleportWrapper.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_12_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_12_R1.PacketPlayOutEntityTeleport; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.BlockFace; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutEntityTeleportWrapper { - - public PacketPlayOutEntityTeleport create(int entityId, Location location) { - PacketPlayOutEntityTeleport packetPlayOutEntityTeleport = new PacketPlayOutEntityTeleport(); - - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "a", int.class) - .set(packetPlayOutEntityTeleport, entityId); - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "b", double.class) - .set(packetPlayOutEntityTeleport, location.getX()); - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "c", double.class) - .set(packetPlayOutEntityTeleport, location.getY()); - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "d", double.class) - .set(packetPlayOutEntityTeleport, location.getZ()); - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "e", byte.class) - .set(packetPlayOutEntityTeleport, (byte) ((int) (location.getYaw() * 256.0F / 360.0F))); - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "f", byte.class) - .set(packetPlayOutEntityTeleport, (byte) ((int) (location.getPitch() * 256.0F / 360.0F))); - Reflection.getField(packetPlayOutEntityTeleport.getClass(), "g", boolean.class) - .set(packetPlayOutEntityTeleport, location.getBlock().getRelative(BlockFace.DOWN).getType() != Material.AIR); - - return packetPlayOutEntityTeleport; - } -} diff --git a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index 323abde..0000000 --- a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_12_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_12_R1.DataWatcher; -import net.minecraft.server.v1_12_R1.DataWatcherObject; -import net.minecraft.server.v1_12_R1.DataWatcherRegistry; -import net.minecraft.server.v1_12_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/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index f13a0a4..0000000 --- a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_12_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_12_R1.EnumGamemode; -import net.minecraft.server.v1_12_R1.IChatBaseComponent; -import net.minecraft.server.v1_12_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/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index 6a1d4a5..0000000 --- a/src/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_12_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_12_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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R1/NPC_V1_8_R1.java b/src/net/jitse/npclib/nms/v1_8_R1/NPC_V1_8_R1.java deleted file mode 100644 index 1ae0055..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R1/NPC_V1_8_R1.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R1; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_8_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPC_V1_8_R1 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_8_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); - hologram.generatePackets(false); - - 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(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(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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 4d6eb40..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_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/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index eac29db..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R1.DataWatcher; -import net.minecraft.server.v1_8_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", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D)); - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D)); - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D)); - 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.a(10, (byte) 127); - - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class) - .set(packetPlayOutNamedEntitySpawn, dataWatcher); - - return packetPlayOutNamedEntitySpawn; - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index 283b46e..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_8_R1.*; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutPlayerInfoWrapper { - - public PacketPlayOutPlayerInfo create(EnumPlayerInfoAction action, GameProfile gameProfile, String name) { - PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); - Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", EnumPlayerInfoAction.class) - .set(packetPlayOutPlayerInfo, action); - - PlayerInfoData playerInfoData = new PlayerInfoData(packetPlayOutPlayerInfo, gameProfile, - 1, EnumGamemode.NOT_SET, ChatSerializer.a(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/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index e682a39..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R1.PacketPlayOutScoreboardTeam; -import org.bukkit.ChatColor; - -import java.util.Collection; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutScoreboardTeamWrapper { - - public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { - PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); - - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "h", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) - .set(packetPlayOutScoreboardTeam, "never"); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) - .set(packetPlayOutScoreboardTeam, 1); - // Could not get this working in the PacketPlayOutPlayerInfoWrapper class. - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class) - .set(packetPlayOutScoreboardTeam, ChatColor.BLUE + "[NPC] "); - Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( - packetPlayOutScoreboardTeam.getClass(), "g", 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(), "h", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R2/NPC_V1_8_R2.java b/src/net/jitse/npclib/nms/v1_8_R2/NPC_V1_8_R2.java deleted file mode 100644 index 25b52f3..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R2/NPC_V1_8_R2.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R2; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_8_R2.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_8_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_8_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_8_R2(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); - hologram.generatePackets(false); - - 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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 5ac6220..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R2.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/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index f48b8c8..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R2.DataWatcher; -import net.minecraft.server.v1_8_R2.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", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D)); - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D)); - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D)); - 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.a(10, (byte) 127); - - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class) - .set(packetPlayOutNamedEntitySpawn, dataWatcher); - - return packetPlayOutNamedEntitySpawn; - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index bca9688..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_8_R2.IChatBaseComponent; -import net.minecraft.server.v1_8_R2.PacketPlayOutPlayerInfo; -import net.minecraft.server.v1_8_R2.WorldSettings; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutPlayerInfoWrapper { - - 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); - - PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = packetPlayOutPlayerInfo.new PlayerInfoData(gameProfile, 1, - WorldSettings.EnumGamemode.NOT_SET, IChatBaseComponent.ChatSerializer.a(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/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index 89a6e7a..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R2.PacketPlayOutScoreboardTeam; -import org.bukkit.ChatColor; - -import java.util.Collection; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutScoreboardTeamWrapper { - - public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { - PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); - - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "h", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) - .set(packetPlayOutScoreboardTeam, "never"); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) - .set(packetPlayOutScoreboardTeam, 1); - // Could not get this working in the PacketPlayOutPlayerInfoWrapper class. - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class) - .set(packetPlayOutScoreboardTeam, ChatColor.BLUE + "[NPC] "); - Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( - packetPlayOutScoreboardTeam.getClass(), "g", 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(), "h", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R3/NPC_V1_8_R3.java b/src/net/jitse/npclib/nms/v1_8_R3/NPC_V1_8_R3.java deleted file mode 100644 index 05b1caf..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R3/NPC_V1_8_R3.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R3; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_8_R3.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPC_V1_8_R3 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_8_R3(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); - hologram.generatePackets(false); - - 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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index e50ebb9..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R3.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R3.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/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index b23b72b..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R3.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R3.DataWatcher; -import net.minecraft.server.v1_8_R3.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", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D)); - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D)); - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class) - .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D)); - 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.a(10, (byte) 127); - - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class) - .set(packetPlayOutNamedEntitySpawn, dataWatcher); - - return packetPlayOutNamedEntitySpawn; - } -} diff --git a/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index 3c411df..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R3.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_8_R3.IChatBaseComponent; -import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; -import net.minecraft.server.v1_8_R3.WorldSettings; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutPlayerInfoWrapper { - - 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); - - PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = packetPlayOutPlayerInfo.new PlayerInfoData(gameProfile, 1, - WorldSettings.EnumGamemode.NOT_SET, IChatBaseComponent.ChatSerializer.a(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/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index 3b6b53c..0000000 --- a/src/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_8_R3.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_8_R3.PacketPlayOutScoreboardTeam; -import org.bukkit.ChatColor; - -import java.util.Collection; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutScoreboardTeamWrapper { - - public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { - PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); - - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "h", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) - .set(packetPlayOutScoreboardTeam, "never"); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) - .set(packetPlayOutScoreboardTeam, 1); - // Could not get this working in the PacketPlayOutPlayerInfoWrapper class. - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class) - .set(packetPlayOutScoreboardTeam, ChatColor.BLUE + "[NPC] "); - Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( - packetPlayOutScoreboardTeam.getClass(), "g", 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(), "h", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_9_R1/NPC_V1_9_R1.java b/src/net/jitse/npclib/nms/v1_9_R1/NPC_V1_9_R1.java deleted file mode 100644 index 905a52a..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R1/NPC_V1_9_R1.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R1; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_9_R1.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class NPC_V1_9_R1 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_9_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().subtract(0, 0.5, 0), lines); - hologram.generatePackets(false); - - 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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 72b2a04..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_9_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/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index d0a2504..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_9_R1.DataWatcher; -import net.minecraft.server.v1_9_R1.DataWatcherObject; -import net.minecraft.server.v1_9_R1.DataWatcherRegistry; -import net.minecraft.server.v1_9_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<>(12, DataWatcherRegistry.a), (byte) 127); - - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "h", DataWatcher.class) - .set(packetPlayOutNamedEntitySpawn, dataWatcher); - - return packetPlayOutNamedEntitySpawn; - } -} diff --git a/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index 43695c7..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_9_R1.IChatBaseComponent; -import net.minecraft.server.v1_9_R1.PacketPlayOutPlayerInfo; -import net.minecraft.server.v1_9_R1.WorldSettings; -import org.bukkit.ChatColor; - -import java.util.List; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutPlayerInfoWrapper { - - 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); - - PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = new PacketPlayOutPlayerInfo().new PlayerInfoData(gameProfile, 1, - WorldSettings.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/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index ea81eee..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R1.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_9_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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/nms/v1_9_R2/NPC_V1_9_R2.java b/src/net/jitse/npclib/nms/v1_9_R2/NPC_V1_9_R2.java deleted file mode 100644 index 5ec349d..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R2/NPC_V1_9_R2.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R2; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.holograms.Hologram; -import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutEntityHeadRotationWrapper; -import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutNamedEntitySpawnWrapper; -import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutPlayerInfoWrapper; -import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutScoreboardTeamWrapper; -import net.jitse.npclib.skin.Skin; -import net.minecraft.server.v1_9_R2.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_9_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_9_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_9_R2(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { - super(plugin, skin, autoHideDistance, lines); - } - - @Override - public void create(Location location) { - this.location = location; - - this.hologram = new Hologram(location.clone().subtract(0, 0.5, 0), lines); - hologram.generatePackets(false); - - 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), 5); - } - - @Override - public void sendHidePackets(Player player) { - PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - - playerConnection.sendPacket(packetPlayOutEntityDestroy); - playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - - hologram.destroy(player); - - // 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); - } - - @Override - public void sendTeleportationPackets(Player player) { - // Todo create this method. - } -} diff --git a/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java b/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java deleted file mode 100644 index 6b2d008..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_9_R2.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/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java deleted file mode 100644 index 39f5a3c..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_9_R2.DataWatcher; -import net.minecraft.server.v1_9_R2.DataWatcherObject; -import net.minecraft.server.v1_9_R2.DataWatcherRegistry; -import net.minecraft.server.v1_9_R2.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<>(12, DataWatcherRegistry.a), (byte) 127); - - Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "h", DataWatcher.class) - .set(packetPlayOutNamedEntitySpawn, dataWatcher); - - return packetPlayOutNamedEntitySpawn; - } -} diff --git a/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java b/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java deleted file mode 100644 index 67afd64..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.v1_9_R2.IChatBaseComponent; -import net.minecraft.server.v1_9_R2.PacketPlayOutPlayerInfo; -import net.minecraft.server.v1_9_R2.WorldSettings; -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, WorldSettings.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, WorldSettings.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/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java b/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java deleted file mode 100644 index 38e4b3e..0000000 --- a/src/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.nms.v1_9_R2.packets; - -import com.comphenix.tinyprotocol.Reflection; -import net.minecraft.server.v1_9_R2.PacketPlayOutScoreboardTeam; - -import java.util.Collection; - -/** - * @author Jitse Boonstra - */ -public class PacketPlayOutScoreboardTeamWrapper { - - public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { - PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); - - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 0); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) - .set(packetPlayOutScoreboardTeam, name); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) - .set(packetPlayOutScoreboardTeam, 1); - Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) - .set(packetPlayOutScoreboardTeam, name); - - return packetPlayOutScoreboardTeam; - } -} diff --git a/src/net/jitse/npclib/plugin/NPCLibPlugin.java b/src/net/jitse/npclib/plugin/NPCLibPlugin.java deleted file mode 100644 index b3fbab9..0000000 --- a/src/net/jitse/npclib/plugin/NPCLibPlugin.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.plugin; - -import net.jitse.npclib.NPCLib; -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.plugin.listeners.NPCListener; -import net.jitse.npclib.skin.MineSkinFetcher; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerToggleSneakEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Arrays; - -/** - * @author Jitse Boonstra - */ -public class NPCLibPlugin extends JavaPlugin implements Listener { - - private NPCLib npcLib; - private NPC npc; - - @Override - public void onEnable() { - this.npcLib = new NPCLib(this); - getServer().getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + ChatColor.WHITE + "plugin enabled."); - getServer().getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + - ChatColor.GRAY + "This is a test plugin usually used for development reasons. " + - "You can spawn NPCs by pressing [shift] in game."); - - getServer().getPluginManager().registerEvents(this, this); - getServer().getPluginManager().registerEvents(new NPCListener(), this); - } - - @Override - public void onDisable() { - getServer().getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + ChatColor.WHITE + "plugin disabled."); - } - - @EventHandler - public void onPlayerShift(PlayerToggleSneakEvent event) { - if (event.isSneaking()) { - return; - } - - if (npc != null) { - npc.teleport(event.getPlayer(), event.getPlayer().getLocation()); - } else { - MineSkinFetcher.fetchSkinFromIdAsync(168841, skin -> { - npc = npcLib.createNPC(skin, Arrays.asList( - ChatColor.BOLD + "NPC Library", "", - "Create your own", "non-player characters", - "with the simplistic", "API of NPCLib!" - )); - npc.create(event.getPlayer().getLocation()); - - for (Player player : getServer().getOnlinePlayers()) { - npc.show(player); - } - }); - } - } -} diff --git a/src/net/jitse/npclib/plugin/listeners/NPCListener.java b/src/net/jitse/npclib/plugin/listeners/NPCListener.java deleted file mode 100644 index 14d3ef3..0000000 --- a/src/net/jitse/npclib/plugin/listeners/NPCListener.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.plugin.listeners; - -import net.jitse.npclib.events.NPCDestroyEvent; -import net.jitse.npclib.events.NPCInteractEvent; -import net.jitse.npclib.events.NPCSpawnEvent; -import org.bukkit.ChatColor; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -/** - * @author Jitse Boonstra - */ -public class NPCListener implements Listener { - - @EventHandler - public void onNPCSpawn(NPCSpawnEvent event) { - event.getPlayer().sendMessage(ChatColor.GREEN + "Spawned NPC " + event.getNPC().getEntityId()); - } - - @EventHandler - public void onNPCDestroy(NPCDestroyEvent event) { - event.getPlayer().sendMessage(ChatColor.RED + "Destroyed NPC " + event.getNPC().getEntityId()); - } - - @EventHandler - public void onNPCInteract(NPCInteractEvent event) { - event.getWhoClicked().sendMessage(ChatColor.BLUE + "Interacted with NPC " - + event.getNPC().getEntityId() + " type " + event.getClickType()); - } -} diff --git a/src/net/jitse/npclib/skin/MineSkinFetcher.java b/src/net/jitse/npclib/skin/MineSkinFetcher.java deleted file mode 100644 index d2dccd9..0000000 --- a/src/net/jitse/npclib/skin/MineSkinFetcher.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.skin; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Scanner; - -/** - * @author Jitse Boonstra - */ -public class MineSkinFetcher { - - private static final String MINESKIN_API = "https://api.mineskin.org/get/id/"; - - public static void fetchSkinFromIdAsync(int id, Callback callback) { - new Thread(() -> { - try { - StringBuilder builder = new StringBuilder(); - HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(MINESKIN_API + id).openConnection(); - httpURLConnection.setRequestMethod("GET"); - httpURLConnection.setDoOutput(true); - httpURLConnection.setDoInput(true); - httpURLConnection.connect(); - - Scanner scanner = new Scanner(httpURLConnection.getInputStream()); - while (scanner.hasNextLine()) { - builder.append(scanner.nextLine()); - } - - scanner.close(); - httpURLConnection.disconnect(); - - JsonObject jsonObject = (JsonObject) new JsonParser().parse(builder.toString()); - JsonObject textures = jsonObject.get("data").getAsJsonObject().get("texture").getAsJsonObject(); - String value = textures.get("value").getAsString(); - String signature = textures.get("signature").getAsString(); - - callback.call(new Skin(value, signature)); - } catch (IOException exception) { - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "Could not fetch skin! (Id: " + id + "). Message: " + exception.getMessage()); - exception.printStackTrace(); - callback.failed(); - } - }).start(); - } - - public interface Callback { - - void call(Skin skinData); - - default void failed() { - } - } -} diff --git a/src/net/jitse/npclib/skin/Skin.java b/src/net/jitse/npclib/skin/Skin.java deleted file mode 100644 index 181a4f0..0000000 --- a/src/net/jitse/npclib/skin/Skin.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.skin; - -/** - * @author Jitse Boonstra - */ -public class Skin { - - private final String value, signature; - - public Skin(String value, String signature) { - this.value = value; - this.signature = signature; - } - - public String getValue() { - return this.value; - } - - public String getSignature() { - return this.signature; - } -} diff --git a/src/net/jitse/npclib/version/Version.java b/src/net/jitse/npclib/version/Version.java deleted file mode 100644 index a2acc90..0000000 --- a/src/net/jitse/npclib/version/Version.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2018 Jitse Boonstra - */ - -package net.jitse.npclib.version; - -import net.jitse.npclib.api.NPC; -import net.jitse.npclib.nms.v1_10_R1.NPC_V1_10_R1; -import net.jitse.npclib.nms.v1_11_R1.NPC_V1_11_R1; -import net.jitse.npclib.nms.v1_12_R1.NPC_V1_12_R1; -import net.jitse.npclib.nms.v1_8_R1.NPC_V1_8_R1; -import net.jitse.npclib.nms.v1_8_R2.NPC_V1_8_R2; -import net.jitse.npclib.nms.v1_8_R3.NPC_V1_8_R3; -import net.jitse.npclib.nms.v1_9_R1.NPC_V1_9_R1; -import net.jitse.npclib.nms.v1_9_R2.NPC_V1_9_R2; - -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Optional; - -/** - * @author Jitse Boonstra - */ -public enum Version { - - V1_8_R1("v1_8_R1", NPC_V1_8_R1.class), - V1_8_R2("v1_8_R2", NPC_V1_8_R2.class), - V1_8_R3("v1_8_R3", NPC_V1_8_R3.class), - V1_9_R1("v1_9_R1", NPC_V1_9_R1.class), - V1_9_R2("v1_9_R2", NPC_V1_9_R2.class), - V1_10_R1("v1_10_R1", NPC_V1_10_R1.class), - V1_11_R1("v1_11_R1", NPC_V1_11_R1.class), - V1_12_R1("v1_12_R1", NPC_V1_12_R1.class); - - private String version; - private Class clazz; - - Version(String version, Class clazz) { - this.version = version; - this.clazz = clazz; - } - - public NPC createNPC(Object... params) throws InstantiationException, IllegalAccessException, InvocationTargetException { - return (NPC) clazz.getConstructors()[0].newInstance(params); - } - - public static Optional getByName(String version) { - return Arrays.stream(values()).filter(value -> value.version.equals(version)).findFirst(); - } -} diff --git a/src/plugin.yml b/src/plugin.yml deleted file mode 100644 index 2f76287..0000000 --- a/src/plugin.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: NPCLib -version: 1.0.4 -author: JitseB -main: net.jitse.npclib.plugin.NPCLibPlugin -description: An NPC library. \ No newline at end of file From c9a58ccd484f012b5860a1fc2cbb5268fec612c7 Mon Sep 17 00:00:00 2001 From: MrMicky Date: Thu, 26 Apr 2018 13:52:49 +0200 Subject: [PATCH 2/3] Add Maven ! --- api/pom.xml | 71 +++ commons/pom.xml | 15 + .../comphenix/tinyprotocol/Reflection.java | 393 ++++++++++++++ .../comphenix/tinyprotocol/TinyProtocol.java | 501 ++++++++++++++++++ .../main/java/net/jitse/npclib/NPCLib.java | 115 ++++ .../java/net/jitse/npclib/NPCManager.java | 35 ++ .../main/java/net/jitse/npclib/api/NPC.java | 165 ++++++ .../jitse/npclib/events/NPCDestroyEvent.java | 63 +++ .../jitse/npclib/events/NPCInteractEvent.java | 49 ++ .../jitse/npclib/events/NPCSpawnEvent.java | 62 +++ .../jitse/npclib/events/click/ClickType.java | 13 + .../npclib/events/trigger/TriggerType.java | 6 + .../jitse/npclib/listeners/ChunkListener.java | 81 +++ .../npclib/listeners/PacketListener.java | 72 +++ .../npclib/listeners/PlayerListener.java | 104 ++++ .../jitse/npclib/nms/holograms/Hologram.java | 148 ++++++ .../jitse/npclib/skin/MineSkinFetcher.java | 63 +++ .../main/java/net/jitse/npclib/skin/Skin.java | 26 + nms/pom.xml | 34 ++ nms/v1_10_R1/pom.xml | 23 + .../npclib/nms/v1_10_R1/NPC_v1_10_R1.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 ++ .../PacketPlayOutPlayerInfoWrapper.java | 43 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 51 ++ nms/v1_11_R1/pom.xml | 23 + .../npclib/nms/v1_11_R1/NPC_v1_11_R1.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 ++ .../PacketPlayOutPlayerInfoWrapper.java | 43 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 51 ++ nms/v1_12_R1/pom.xml | 23 + .../npclib/nms/v1_12_R1/NPC_v1_12_R1.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 ++ .../PacketPlayOutPlayerInfoWrapper.java | 43 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 51 ++ nms/v1_8_R1/pom.xml | 23 + .../jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java | 102 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 45 ++ .../PacketPlayOutPlayerInfoWrapper.java | 35 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 53 ++ nms/v1_8_R2/pom.xml | 23 + .../jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 45 ++ .../PacketPlayOutPlayerInfoWrapper.java | 37 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 53 ++ nms/v1_8_R3/pom.xml | 23 + .../jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 45 ++ .../PacketPlayOutPlayerInfoWrapper.java | 37 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 53 ++ nms/v1_9_R1/pom.xml | 23 + .../jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 ++ .../PacketPlayOutPlayerInfoWrapper.java | 38 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 51 ++ nms/v1_9_R2/pom.xml | 23 + .../jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java | 103 ++++ ...acketPlayOutEntityHeadRotationWrapper.java | 26 + .../PacketPlayOutNamedEntitySpawnWrapper.java | 47 ++ .../PacketPlayOutPlayerInfoWrapper.java | 44 ++ .../PacketPlayOutScoreboardTeamWrapper.java | 51 ++ plugin/pom.xml | 33 ++ .../net/jitse/npclib/plugin/NPCLibPlugin.java | 64 +++ .../npclib/plugin/listeners/NPCListener.java | 34 ++ plugin/src/main/resources/plugin.yml | 5 + pom.xml | 86 +++ 72 files changed, 4557 insertions(+) create mode 100644 api/pom.xml create mode 100644 commons/pom.xml create mode 100644 commons/src/main/java/com/comphenix/tinyprotocol/Reflection.java create mode 100644 commons/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java create mode 100644 commons/src/main/java/net/jitse/npclib/NPCLib.java create mode 100644 commons/src/main/java/net/jitse/npclib/NPCManager.java create mode 100644 commons/src/main/java/net/jitse/npclib/api/NPC.java create mode 100644 commons/src/main/java/net/jitse/npclib/events/NPCDestroyEvent.java create mode 100644 commons/src/main/java/net/jitse/npclib/events/NPCInteractEvent.java create mode 100644 commons/src/main/java/net/jitse/npclib/events/NPCSpawnEvent.java create mode 100644 commons/src/main/java/net/jitse/npclib/events/click/ClickType.java create mode 100644 commons/src/main/java/net/jitse/npclib/events/trigger/TriggerType.java create mode 100644 commons/src/main/java/net/jitse/npclib/listeners/ChunkListener.java create mode 100644 commons/src/main/java/net/jitse/npclib/listeners/PacketListener.java create mode 100644 commons/src/main/java/net/jitse/npclib/listeners/PlayerListener.java create mode 100644 commons/src/main/java/net/jitse/npclib/nms/holograms/Hologram.java create mode 100644 commons/src/main/java/net/jitse/npclib/skin/MineSkinFetcher.java create mode 100644 commons/src/main/java/net/jitse/npclib/skin/Skin.java create mode 100644 nms/pom.xml create mode 100644 nms/v1_10_R1/pom.xml create mode 100644 nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java create mode 100644 nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_11_R1/pom.xml create mode 100644 nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java create mode 100644 nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_12_R1/pom.xml create mode 100644 nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java create mode 100644 nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_8_R1/pom.xml create mode 100644 nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java create mode 100644 nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_8_R2/pom.xml create mode 100644 nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java create mode 100644 nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_8_R3/pom.xml create mode 100644 nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java create mode 100644 nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_9_R1/pom.xml create mode 100644 nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java create mode 100644 nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 nms/v1_9_R2/pom.xml create mode 100644 nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java create mode 100644 nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java create mode 100644 nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java create mode 100644 nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java create mode 100644 nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java create mode 100644 plugin/pom.xml create mode 100644 plugin/src/main/java/net/jitse/npclib/plugin/NPCLibPlugin.java create mode 100644 plugin/src/main/java/net/jitse/npclib/plugin/listeners/NPCListener.java create mode 100644 plugin/src/main/resources/plugin.yml create mode 100644 pom.xml diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 0000000..a955c4c --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + + net.jitse + npclib + 1.0.4 + + + npclib-api + + + + ${project.parent.groupId} + npclib-commons + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_8_R1 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_8_R2 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_8_R3 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_9_R1 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_9_R2 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_10_R1 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_11_R1 + ${project.parent.version} + compile + + + ${project.parent.groupId} + npclib-nms-v1_12_R1 + ${project.parent.version} + compile + + + diff --git a/commons/pom.xml b/commons/pom.xml new file mode 100644 index 0000000..6016a07 --- /dev/null +++ b/commons/pom.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + + + net.jitse + npclib + 1.0.4 + + + npclib-commons + + diff --git a/commons/src/main/java/com/comphenix/tinyprotocol/Reflection.java b/commons/src/main/java/com/comphenix/tinyprotocol/Reflection.java new file mode 100644 index 0000000..acf0c5f --- /dev/null +++ b/commons/src/main/java/com/comphenix/tinyprotocol/Reflection.java @@ -0,0 +1,393 @@ +package com.comphenix.tinyprotocol; + +import org.bukkit.Bukkit; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * An utility class that simplifies reflection in Bukkit plugins. + * + * @author Kristian + */ +public final class Reflection { + /** + * An interface for invoking a specific constructor. + */ + public interface ConstructorInvoker { + /** + * Invoke a constructor for a specific class. + * + * @param arguments - the arguments to pass to the constructor. + * @return The constructed object. + */ + Object invoke(Object... arguments); + } + + /** + * An interface for invoking a specific method. + */ + public interface MethodInvoker { + /** + * Invoke a method on a specific target object. + * + * @param target - the target object, or NULL for a static method. + * @param arguments - the arguments to pass to the method. + * @return The return value, or NULL if is void. + */ + Object invoke(Object target, Object... arguments); + } + + /** + * An interface for retrieving the field content. + * + * @param - field type. + */ + public interface FieldAccessor { + /** + * Retrieve the content of a field. + * + * @param target - the target object, or NULL for a static field. + * @return The value of the field. + */ + T get(Object target); + + /** + * Set the content of a field. + * + * @param target - the target object, or NULL for a static field. + * @param value - the new value of the field. + */ + void set(Object target, Object value); + + /** + * Determine if the given object has this field. + * + * @param target - the object to test. + * @return TRUE if it does, FALSE otherwise. + */ + boolean hasField(Object target); + } + + // Deduce the net.minecraft.server.v* package + private static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName(); + private static String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server"); + private static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "").replace(".", ""); + + // Variable replacement + private static Pattern MATCH_VARIABLE = Pattern.compile("\\{([^}]+)\\}"); + + private Reflection() { + // Seal class + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param target - the target type. + * @param name - the name of the field, or NULL to ignore. + * @param fieldType - a compatible field type. + * @return The field accessor. + */ + public static FieldAccessor getField(Class target, String name, Class fieldType) { + return getField(target, name, fieldType, 0); + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param name - the name of the field, or NULL to ignore. + * @param fieldType - a compatible field type. + * @return The field accessor. + */ + public static FieldAccessor getField(String className, String name, Class fieldType) { + return getField(getClass(className), name, fieldType, 0); + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param target - the target type. + * @param fieldType - a compatible field type. + * @param index - the number of compatible fields to skip. + * @return The field accessor. + */ + public static FieldAccessor getField(Class target, Class fieldType, int index) { + return getField(target, null, fieldType, index); + } + + /** + * Retrieve a field accessor for a specific field type and name. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param fieldType - a compatible field type. + * @param index - the number of compatible fields to skip. + * @return The field accessor. + */ + public static FieldAccessor getField(String className, Class fieldType, int index) { + return getField(getClass(className), fieldType, index); + } + + // Common method + private static FieldAccessor getField(Class target, String name, Class fieldType, int index) { + for (final Field field : target.getDeclaredFields()) { + if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) { + field.setAccessible(true); + + // A function for retrieving a specific field value + return new FieldAccessor() { + + @Override + @SuppressWarnings("unchecked") + public T get(Object target) { + try { + return (T) field.get(target); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot access reflection.", e); + } + } + + @Override + public void set(Object target, Object value) { + try { + field.set(target, value); + } catch (IllegalAccessException e) { + throw new RuntimeException("Cannot access reflection.", e); + } + } + + @Override + public boolean hasField(Object target) { + // target instanceof DeclaringClass + return field.getDeclaringClass().isAssignableFrom(target.getClass()); + } + }; + } + } + + // Search in parent classes + if (target.getSuperclass() != null) + return getField(target.getSuperclass(), name, fieldType, index); + + throw new IllegalArgumentException("Cannot find field with type " + fieldType); + } + + /** + * Search for the first publicly and privately defined method of the given name and parameter count. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param methodName - the method name, or NULL to skip. + * @param params - the expected parameters. + * @return An object that invokes this specific method. + * @throws IllegalStateException If we cannot find this method. + */ + public static MethodInvoker getMethod(String className, String methodName, Class... params) { + return getTypedMethod(getClass(className), methodName, null, params); + } + + /** + * Search for the first publicly and privately defined method of the given name and parameter count. + * + * @param clazz - a class to start with. + * @param methodName - the method name, or NULL to skip. + * @param params - the expected parameters. + * @return An object that invokes this specific method. + * @throws IllegalStateException If we cannot find this method. + */ + public static MethodInvoker getMethod(Class clazz, String methodName, Class... params) { + return getTypedMethod(clazz, methodName, null, params); + } + + /** + * Search for the first publicly and privately defined method of the given name and parameter count. + * + * @param clazz - a class to start with. + * @param methodName - the method name, or NULL to skip. + * @param returnType - the expected return type, or NULL to ignore. + * @param params - the expected parameters. + * @return An object that invokes this specific method. + * @throws IllegalStateException If we cannot find this method. + */ + public static MethodInvoker getTypedMethod(Class clazz, String methodName, Class returnType, Class... params) { + for (final Method method : clazz.getDeclaredMethods()) { + if ((methodName == null || method.getName().equals(methodName)) + && (returnType == null || method.getReturnType().equals(returnType)) + && Arrays.equals(method.getParameterTypes(), params)) { + method.setAccessible(true); + + return (target, arguments) -> { + try { + return method.invoke(target, arguments); + } catch (Exception e) { + throw new RuntimeException("Cannot invoke method " + method, e); + } + }; + } + } + + // Search in every superclass + if (clazz.getSuperclass() != null) + return getMethod(clazz.getSuperclass(), methodName, params); + + throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params))); + } + + /** + * Search for the first publically and privately defined constructor of the given name and parameter count. + * + * @param className - lookup name of the class, see {@link #getClass(String)}. + * @param params - the expected parameters. + * @return An object that invokes this constructor. + * @throws IllegalStateException If we cannot find this method. + */ + public static ConstructorInvoker getConstructor(String className, Class... params) { + return getConstructor(getClass(className), params); + } + + /** + * Search for the first publicly and privately defined constructor of the given name and parameter count. + * + * @param clazz - a class to start with. + * @param params - the expected parameters. + * @return An object that invokes this constructor. + * @throws IllegalStateException If we cannot find this method. + */ + public static ConstructorInvoker getConstructor(Class clazz, Class... params) { + for (final Constructor constructor : clazz.getDeclaredConstructors()) { + if (Arrays.equals(constructor.getParameterTypes(), params)) { + constructor.setAccessible(true); + + return arguments -> { + try { + return constructor.newInstance(arguments); + } catch (Exception e) { + throw new RuntimeException("Cannot invoke constructor " + constructor, e); + } + }; + } + } + + throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params))); + } + + /** + * Retrieve a class from its full name, without knowing its type on compile time. + *

+ * This is useful when looking up fields by a NMS or OBC type. + *

+ * + * @param lookupName - the class name with variables. + * @return The class. + * @see {@link #getClass()} for more information. + */ + public static Class getUntypedClass(String lookupName) { + @SuppressWarnings({"rawtypes", "unchecked"}) + Class clazz = (Class) getClass(lookupName); + return clazz; + } + + /** + * Retrieve a class from its full name. + *

+ * Strings enclosed with curly brackets - such as {TEXT} - will be replaced according to the following table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
VariableContent
{nms}Actual package name of net.minecraft.server.VERSION
{obc}Actual pacakge name of org.bukkit.craftbukkit.VERSION
{version}The current Minecraft package VERSION, if any.
+ * + * @param lookupName - the class name with variables. + * @return The looked up class. + * @throws IllegalArgumentException If a variable or class could not be found. + */ + public static Class getClass(String lookupName) { + return getCanonicalClass(expandVariables(lookupName)); + } + + /** + * Retrieve a class in the net.minecraft.server.VERSION.* package. + * + * @param name - the name of the class, excluding the package. + * @throws IllegalArgumentException If the class doesn't exist. + */ + public static Class getMinecraftClass(String name) { + return getCanonicalClass(NMS_PREFIX + "." + name); + } + + /** + * Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package. + * + * @param name - the name of the class, excluding the package. + * @throws IllegalArgumentException If the class doesn't exist. + */ + public static Class getCraftBukkitClass(String name) { + return getCanonicalClass(OBC_PREFIX + "." + name); + } + + /** + * Retrieve a class by its canonical name. + * + * @param canonicalName - the canonical name. + * @return The class. + */ + private static Class getCanonicalClass(String canonicalName) { + try { + return Class.forName(canonicalName); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Cannot find " + canonicalName, e); + } + } + + /** + * Expand variables such as "{nms}" and "{obc}" to their corresponding packages. + * + * @param name - the full name of the class. + * @return The expanded string. + */ + private static String expandVariables(String name) { + StringBuffer output = new StringBuffer(); + Matcher matcher = MATCH_VARIABLE.matcher(name); + + while (matcher.find()) { + String variable = matcher.group(1); + String replacement; + + // Expand all detected variables + if ("nms".equalsIgnoreCase(variable)) + replacement = NMS_PREFIX; + else if ("obc".equalsIgnoreCase(variable)) + replacement = OBC_PREFIX; + else if ("version".equalsIgnoreCase(variable)) + replacement = VERSION; + else + throw new IllegalArgumentException("Unknown variable: " + variable); + + // Assume the expanded variables are all packages, and append a dot + if (replacement.length() > 0 && matcher.end() < name.length() && name.charAt(matcher.end()) != '.') + replacement += "."; + matcher.appendReplacement(output, Matcher.quoteReplacement(replacement)); + } + + matcher.appendTail(output); + return output.toString(); + } +} \ No newline at end of file diff --git a/commons/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java b/commons/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java new file mode 100644 index 0000000..5623c08 --- /dev/null +++ b/commons/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java @@ -0,0 +1,501 @@ +package com.comphenix.tinyprotocol; + +import com.comphenix.tinyprotocol.Reflection.FieldAccessor; +import com.comphenix.tinyprotocol.Reflection.MethodInvoker; +import com.google.common.collect.Lists; +import com.google.common.collect.MapMaker; +import com.mojang.authlib.GameProfile; +import io.netty.channel.*; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; + +/** + * Represents a very tiny alternative to ProtocolLib. + *

+ * It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)! + * + * @author Kristian + */ +public abstract class TinyProtocol { + private static final AtomicInteger ID = new AtomicInteger(0); + + // Used in order to lookup a channel + private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle"); + private static final FieldAccessor getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class); + private static final FieldAccessor getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class); + private static final FieldAccessor getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0); + + // Looking up ServerConnection + private static final Class minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer"); + private static final Class serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection"); + private static final FieldAccessor getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0); + private static final FieldAccessor getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0); + private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass); + + // Packets we have to intercept + private static final Class PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart"); + private static final FieldAccessor getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0); + + // Speedup channel lookup + private Map channelLookup = new MapMaker().weakValues().makeMap(); + private Listener listener; + + // Channels that have already been removed + private Set uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); + + // List of network markers + private List networkManagers; + + // Injected channel handlers + private List serverChannels = Lists.newArrayList(); + private ChannelInboundHandlerAdapter serverChannelHandler; + private ChannelInitializer beginInitProtocol; + private ChannelInitializer endInitProtocol; + + // Current handler name + private String handlerName; + + protected volatile boolean closed; + protected Plugin plugin; + + /** + * Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients. + *

+ * You can construct multiple instances per plugin. + * + * @param plugin - the plugin. + */ + public TinyProtocol(final Plugin plugin) { + this.plugin = plugin; + + // Compute handler name + this.handlerName = getHandlerName(); + + // Prepare existing players + registerBukkitEvents(); + + try { + registerChannelHandler(); + registerPlayers(plugin); + } catch (IllegalArgumentException ex) { + // Damn you, late bind + plugin.getLogger().info("[TinyProtocol] Delaying server channel injection due to late bind."); + + new BukkitRunnable() { + @Override + public void run() { + registerChannelHandler(); + registerPlayers(plugin); + plugin.getLogger().info("[TinyProtocol] Late bind injection successful."); + } + }.runTask(plugin); + } + } + + private void createServerChannelHandler() { + // Handle connected channels + endInitProtocol = new ChannelInitializer() { + + @Override + protected void initChannel(Channel channel) throws Exception { + try { + // This can take a while, so we need to stop the main thread from interfering + synchronized (networkManagers) { + // Stop injecting channels + if (!closed) { + channel.eventLoop().submit(() -> injectChannelInternal(channel)); + } + } + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e); + } + } + + }; + + // This is executed before Minecraft's channel handler + beginInitProtocol = new ChannelInitializer() { + + @Override + protected void initChannel(Channel channel) throws Exception { + channel.pipeline().addLast(endInitProtocol); + } + + }; + + serverChannelHandler = new ChannelInboundHandlerAdapter() { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + Channel channel = (Channel) msg; + + // Prepare to initialize ths channel + channel.pipeline().addFirst(beginInitProtocol); + ctx.fireChannelRead(msg); + } + + }; + } + + /** + * Register bukkit events. + */ + private void registerBukkitEvents() { + listener = new Listener() { + + @EventHandler(priority = EventPriority.LOWEST) + public final void onPlayerLogin(PlayerLoginEvent e) { + if (closed) + return; + + Channel channel = getChannel(e.getPlayer()); + + // Don't inject players that have been explicitly uninjected + if (!uninjectedChannels.contains(channel)) { + injectPlayer(e.getPlayer()); + } + } + + @EventHandler + public final void onPluginDisable(PluginDisableEvent e) { + if (e.getPlugin().equals(plugin)) { + close(); + } + } + + }; + + plugin.getServer().getPluginManager().registerEvents(listener, plugin); + } + + @SuppressWarnings("unchecked") + private void registerChannelHandler() { + Object mcServer = getMinecraftServer.get(Bukkit.getServer()); + Object serverConnection = getServerConnection.get(mcServer); + boolean looking = true; + + // We need to synchronize against this list + networkManagers = (List) getNetworkMarkers.invoke(null, serverConnection); + createServerChannelHandler(); + + // Find the correct list, or implicitly throw an exception + for (int i = 0; looking; i++) { + List list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); + + for (Object item : list) { + if (!ChannelFuture.class.isInstance(item)) + break; + + // Channel future that contains the server connection + Channel serverChannel = ((ChannelFuture) item).channel(); + + serverChannels.add(serverChannel); + serverChannel.pipeline().addFirst(serverChannelHandler); + looking = false; + } + } + } + + private void unregisterChannelHandler() { + if (serverChannelHandler == null) + return; + + for (Channel serverChannel : serverChannels) { + final ChannelPipeline pipeline = serverChannel.pipeline(); + + // Remove channel handler + serverChannel.eventLoop().execute(new Runnable() { + + @Override + public void run() { + try { + pipeline.remove(serverChannelHandler); + } catch (NoSuchElementException e) { + // That's fine + } + } + + }); + } + } + + private void registerPlayers(Plugin plugin) { + for (Player player : plugin.getServer().getOnlinePlayers()) { + injectPlayer(player); + } + } + + /** + * Invoked when the server is starting to send a packet to a player. + *

+ * Note that this is not executed on the main thread. + * + * @param receiver - the receiving player, NULL for early login/status packets. + * @param channel - the channel that received the packet. Never NULL. + * @param packet - the packet being sent. + * @return The packet to send instead, or NULL to cancel the transmission. + */ + public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) { + return packet; + } + + /** + * Invoked when the server has received a packet from a given player. + *

+ * Use {@link Channel#remoteAddress()} to get the remote address of the client. + * + * @param sender - the player that sent the packet, NULL for early login/status packets. + * @param channel - channel that received the packet. Never NULL. + * @param packet - the packet being received. + * @return The packet to recieve instead, or NULL to cancel. + */ + public Object onPacketInAsync(Player sender, Channel channel, Object packet) { + return packet; + } + + /** + * Send a packet to a particular player. + *

+ * Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet. + * + * @param player - the destination player. + * @param packet - the packet to send. + */ + public void sendPacket(Player player, Object packet) { + sendPacket(getChannel(player), packet); + } + + /** + * Send a packet to a particular client. + *

+ * Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet. + * + * @param channel - client identified by a channel. + * @param packet - the packet to send. + */ + public void sendPacket(Channel channel, Object packet) { + channel.pipeline().writeAndFlush(packet); + } + + /** + * Pretend that a given packet has been received from a player. + *

+ * Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet. + * + * @param player - the player that sent the packet. + * @param packet - the packet that will be received by the server. + */ + public void receivePacket(Player player, Object packet) { + receivePacket(getChannel(player), packet); + } + + /** + * Pretend that a given packet has been received from a given client. + *

+ * Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet. + * + * @param channel - client identified by a channel. + * @param packet - the packet that will be received by the server. + */ + public void receivePacket(Channel channel, Object packet) { + channel.pipeline().context("encoder").fireChannelRead(packet); + } + + /** + * Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID. + *

+ * Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances. + * + * @return A unique channel handler name. + */ + protected String getHandlerName() { + return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet(); + } + + /** + * Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets. + *

+ * This will automatically be called when a player has logged in. + * + * @param player - the player to inject. + */ + public void injectPlayer(Player player) { + injectChannelInternal(getChannel(player)).player = player; + } + + /** + * Add a custom channel handler to the given channel. + * + * @param channel - the channel to inject. + */ + public void injectChannel(Channel channel) { + injectChannelInternal(channel); + } + + /** + * Add a custom channel handler to the given channel. + * + * @param channel - the channel to inject. + * @return The packet interceptor. + */ + private PacketInterceptor injectChannelInternal(Channel channel) { + try { + PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName); + + // Inject our packet interceptor + if (interceptor == null) { + interceptor = new PacketInterceptor(); + channel.pipeline().addBefore("packet_handler", handlerName, interceptor); + uninjectedChannels.remove(channel); + } + + return interceptor; + } catch (IllegalArgumentException e) { + // Try again + return (PacketInterceptor) channel.pipeline().get(handlerName); + } + } + + /** + * Retrieve the Netty channel associated with a player. This is cached. + * + * @param player - the player. + * @return The Netty channel. + */ + public Channel getChannel(Player player) { + Channel channel = channelLookup.get(player.getName()); + + // Lookup channel again + if (channel == null) { + Object connection = getConnection.get(getPlayerHandle.invoke(player)); + Object manager = getManager.get(connection); + + channelLookup.put(player.getName(), channel = getChannel.get(manager)); + } + + return channel; + } + + /** + * Uninject a specific player. + * + * @param player - the injected player. + */ + public void uninjectPlayer(Player player) { + uninjectChannel(getChannel(player)); + } + + /** + * Uninject a specific channel. + *

+ * This will also disable the automatic channel injection that occurs when a player has properly logged in. + * + * @param channel - the injected channel. + */ + public void uninjectChannel(final Channel channel) { + // No need to guard against this if we're closing + if (!closed) { + uninjectedChannels.add(channel); + } + + // See ChannelInjector in ProtocolLib, line 590 + channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName)); + } + + /** + * Determine if the given player has been injected by TinyProtocol. + * + * @param player - the player. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean hasInjected(Player player) { + return hasInjected(getChannel(player)); + } + + /** + * Determine if the given channel has been injected by TinyProtocol. + * + * @param channel - the channel. + * @return TRUE if it is, FALSE otherwise. + */ + public boolean hasInjected(Channel channel) { + return channel.pipeline().get(handlerName) != null; + } + + /** + * Cease listening for packets. This is called automatically when your plugin is disabled. + */ + public final void close() { + if (!closed) { + closed = true; + + // Remove our handlers + for (Player player : plugin.getServer().getOnlinePlayers()) { + uninjectPlayer(player); + } + + // Clean up Bukkit + HandlerList.unregisterAll(listener); + unregisterChannelHandler(); + } + } + + /** + * Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets. + * + * @author Kristian + */ + private final class PacketInterceptor extends ChannelDuplexHandler { + // Updated by the login event + public volatile Player player; + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + // Intercept channel + final Channel channel = ctx.channel(); + handleLoginStart(channel, msg); + + try { + msg = onPacketInAsync(player, channel, msg); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e); + } + + if (msg != null) { + super.channelRead(ctx, msg); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + try { + msg = onPacketOutAsync(player, ctx.channel(), msg); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e); + } + + if (msg != null) { + super.write(ctx, msg, promise); + } + } + + private void handleLoginStart(Channel channel, Object packet) { + if (PACKET_LOGIN_IN_START.isInstance(packet)) { + GameProfile profile = getGameProfile.get(packet); + channelLookup.put(profile.getName(), channel); + } + } + } +} \ No newline at end of file diff --git a/commons/src/main/java/net/jitse/npclib/NPCLib.java b/commons/src/main/java/net/jitse/npclib/NPCLib.java new file mode 100644 index 0000000..213aa4c --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/NPCLib.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.listeners.ChunkListener; +import net.jitse.npclib.listeners.PacketListener; +import net.jitse.npclib.listeners.PlayerListener; +import net.jitse.npclib.skin.Skin; +import org.bukkit.ChatColor; +import org.bukkit.Server; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPCLib { + + private final Server server; + private final JavaPlugin plugin; + private final Class npcClass; + + public NPCLib(JavaPlugin plugin) { + this.plugin = plugin; + this.server = plugin.getServer(); + + String versionName = server.getClass().getPackage().getName().split("\\.")[3]; + + Class npcClass = null; + + try { + npcClass = Class.forName("net.jitse.npclib.nms." + versionName + ".NPC_" + versionName); + } catch (ClassNotFoundException e) { + // Version not supported, error below + } + + this.npcClass = npcClass; + + if (npcClass == null) { + server.getConsoleSender().sendMessage(ChatColor.RED + "NPCLib failed to initiate. Your server's version (" + + versionName + ") is not supported."); + return; + } + + server.getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + ChatColor.WHITE + "Enabled for version " + versionName + "."); + + registerInternal(); + } + + private void registerInternal() { + PluginManager pluginManager = server.getPluginManager(); + + pluginManager.registerEvents(new PlayerListener(), plugin); + pluginManager.registerEvents(new ChunkListener(), plugin); + + new PacketListener().start(plugin); + } + + /** + * Create a new non-player character (NPC). + * + * @param skin The skin you want the NPC to have. + * @param autoHideDistance Distance from where you want to NPC to hide from the player (50 recommended). + * @param lines The text you want to sendShowPackets above the NPC (null = no text). + * @return The NPC object you may use to sendShowPackets it to players. + */ + public NPC createNPC(Skin skin, double autoHideDistance, List lines) { + try { + return (NPC) npcClass.getConstructors()[0].newInstance(plugin, skin, autoHideDistance, lines); + } catch (Exception exception) { + server.getConsoleSender().sendMessage(ChatColor.RED + "NPCLib failed to create NPC. Please report this stacktrace:"); + exception.printStackTrace(); + } + + return null; + } + + /** + * Create a new non-player character (NPC). + * + * @param skin The skin you want the NPC to have. + * @param lines The text you want to sendShowPackets above the NPC (null = no text). + * @return The NPC object you may use to sendShowPackets it to players. + */ + public NPC createNPC(Skin skin, List lines) { + return createNPC(skin, 50, lines); + } + + + /** + * Create a new non-player character (NPC). + * + * @param skin The skin you want the NPC to have. + * @return The NPC object you may use to sendShowPackets it to players. + */ + public NPC createNPC(Skin skin) { + return createNPC(skin, 50, null); + } + + + /** + * Create a new non-player character (NPC). + * + * @return The NPC object you may use to sendShowPackets it to players. + */ + public NPC createNPC() { + return createNPC(null, 50, null); + } + +} diff --git a/commons/src/main/java/net/jitse/npclib/NPCManager.java b/commons/src/main/java/net/jitse/npclib/NPCManager.java new file mode 100644 index 0000000..476ea46 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/NPCManager.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib; + +import net.jitse.npclib.api.NPC; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Jitse Boonstra + */ +public final class NPCManager { + + private static Set npcs = new HashSet<>(); + + public static Set getAllNPCs() { + return npcs; + } + + public static void add(NPC npc) { + npcs.add(npc); + } + + public static void remove(NPC npc) { + npcs.remove(npc); + } + + private NPCManager() { + throw new SecurityException("You cannot initialize this class."); + } + +} diff --git a/commons/src/main/java/net/jitse/npclib/api/NPC.java b/commons/src/main/java/net/jitse/npclib/api/NPC.java new file mode 100644 index 0000000..ca7b90b --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/api/NPC.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.api; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.jitse.npclib.NPCManager; +import net.jitse.npclib.events.NPCDestroyEvent; +import net.jitse.npclib.events.NPCSpawnEvent; +import net.jitse.npclib.events.trigger.TriggerType; +import net.jitse.npclib.skin.Skin; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.*; + +/** + * @author Jitse Boonstra + */ +public abstract class NPC { + + protected final UUID uuid = UUID.randomUUID(); + protected final String name = uuid.toString().replace("-", "").substring(0, 10); + protected final int entityId = (int) Math.ceil(Math.random() * 100000) + 100000; + + private final Set shown = new HashSet<>(); + private final Set autoHidden = new HashSet<>(); + + protected final double autoHideDistance; + protected final Skin skin; + protected final List lines; + + protected JavaPlugin plugin; + protected GameProfile gameProfile; + protected Location location; + + public NPC(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + this.plugin = plugin; + this.skin = skin; + this.autoHideDistance = autoHideDistance; + this.lines = (lines == null ? Collections.emptyList() : lines); + + NPCManager.add(this); + } + + protected GameProfile generateGameProfile(UUID uuid, String name) { + GameProfile gameProfile = new GameProfile(uuid, name); + + if (skin != null) { + gameProfile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature())); + } + + return gameProfile; + } + + public void destroy() { + NPCManager.remove(this); + + // Destroy NPC for every player that is still seeing it. + for (UUID uuid : shown) { + if (autoHidden.contains(uuid)) { + continue; + } + + hide(Bukkit.getPlayer(uuid), true); + } + } + + public Set getShown() { + return shown; + } + + public Set getAutoHidden() { + return autoHidden; + } + + public Location getLocation() { + return location; + } + + public double getAutoHideDistance() { + return autoHideDistance; + } + + public int getEntityId() { + return entityId; + } + + public boolean isActuallyShown(Player player) { + return shown.contains(player.getUniqueId()) && !autoHidden.contains(player.getUniqueId()); + } + + // Generate packets. + public abstract void create(Location location); + + public void show(Player player) { + show(player, false); + } + + public void show(Player player, boolean auto) { + NPCSpawnEvent event = new NPCSpawnEvent(this, player, auto ? TriggerType.AUTOMATIC : TriggerType.MANUAL); + plugin.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + + if (auto) { + sendShowPackets(player); + } else { + if (shown.contains(player.getUniqueId())) { + throw new RuntimeException("Cannot call show method twice."); + } + + shown.add(player.getUniqueId()); + + if (player.getLocation().distance(location) <= autoHideDistance) { + sendShowPackets(player); + } else { + if (!autoHidden.contains(player.getUniqueId())) { + autoHidden.add(player.getUniqueId()); + } + } + } + } + + // Internal method. + protected abstract void sendShowPackets(Player player); + + public void hide(Player player) { + hide(player, false); + } + + public void hide(Player player, boolean auto) { + NPCDestroyEvent event = new NPCDestroyEvent(this, player, auto ? TriggerType.AUTOMATIC : TriggerType.MANUAL); + plugin.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + + if (auto) { + sendHidePackets(player); + } else { + if (!shown.contains(player.getUniqueId())) { + throw new RuntimeException("Cannot call hide method without calling NPC#show."); + } + + shown.remove(player.getUniqueId()); + + if (player.getWorld().equals(location.getWorld()) && player.getLocation().distance(location) <= autoHideDistance) { + sendHidePackets(player); + } else { + if (autoHidden.contains(player.getUniqueId())) { + autoHidden.remove(player.getUniqueId()); + } + } + } + } + + // Internal method. + protected abstract void sendHidePackets(Player player); +} diff --git a/commons/src/main/java/net/jitse/npclib/events/NPCDestroyEvent.java b/commons/src/main/java/net/jitse/npclib/events/NPCDestroyEvent.java new file mode 100644 index 0000000..6fc0c36 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/events/NPCDestroyEvent.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.events; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.events.trigger.TriggerType; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * @author Jitse Boonstra + */ +public class NPCDestroyEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + private boolean cancelled = false; + + private final NPC npc; + private final Player player; + private final TriggerType trigger; + + public NPCDestroyEvent(NPC npc, Player player, TriggerType trigger) { + this.npc = npc; + this.player = player; + this.trigger = trigger; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + public NPC getNPC() { + return npc; + } + + public Player getPlayer() { + return player; + } + + public TriggerType getTrigger() { + return trigger; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} + diff --git a/commons/src/main/java/net/jitse/npclib/events/NPCInteractEvent.java b/commons/src/main/java/net/jitse/npclib/events/NPCInteractEvent.java new file mode 100644 index 0000000..ae79a44 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/events/NPCInteractEvent.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.events; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.events.click.ClickType; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * @author Jitse Boonstra + */ +public class NPCInteractEvent extends Event { + + private static final HandlerList handlers = new HandlerList(); + + private final Player player; + private final ClickType clickType; + private final NPC npc; + + public NPCInteractEvent(Player player, ClickType clickType, NPC npc) { + this.player = player; + this.clickType = clickType; + this.npc = npc; + } + + public Player getWhoClicked() { + return this.player; + } + + public ClickType getClickType() { + return this.clickType; + } + + public NPC getNPC() { + return this.npc; + } + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/commons/src/main/java/net/jitse/npclib/events/NPCSpawnEvent.java b/commons/src/main/java/net/jitse/npclib/events/NPCSpawnEvent.java new file mode 100644 index 0000000..5d4ba73 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/events/NPCSpawnEvent.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.events; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.events.trigger.TriggerType; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * @author Jitse Boonstra + */ +public class NPCSpawnEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + private boolean cancelled = false; + + private final NPC npc; + private final Player player; + private final TriggerType trigger; + + public NPCSpawnEvent(NPC npc, Player player, TriggerType trigger) { + this.npc = npc; + this.player = player; + this.trigger = trigger; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + public NPC getNPC() { + return npc; + } + + public Player getPlayer() { + return player; + } + + public TriggerType getTrigger() { + return trigger; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/commons/src/main/java/net/jitse/npclib/events/click/ClickType.java b/commons/src/main/java/net/jitse/npclib/events/click/ClickType.java new file mode 100644 index 0000000..f8d84a7 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/events/click/ClickType.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.events.click; + +/** + * @author Jitse Boonstra + */ +public enum ClickType { + + LEFT_CLICK, RIGHT_CLICK +} diff --git a/commons/src/main/java/net/jitse/npclib/events/trigger/TriggerType.java b/commons/src/main/java/net/jitse/npclib/events/trigger/TriggerType.java new file mode 100644 index 0000000..824db90 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/events/trigger/TriggerType.java @@ -0,0 +1,6 @@ +package net.jitse.npclib.events.trigger; + +public enum TriggerType { + + MANUAL, AUTOMATIC +} diff --git a/commons/src/main/java/net/jitse/npclib/listeners/ChunkListener.java b/commons/src/main/java/net/jitse/npclib/listeners/ChunkListener.java new file mode 100644 index 0000000..4094128 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/listeners/ChunkListener.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.listeners; + +import net.jitse.npclib.NPCManager; +import net.jitse.npclib.api.NPC; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.ChunkUnloadEvent; + +import java.util.UUID; + +/** + * @author Jitse Boonstras + */ +public class ChunkListener implements Listener { + + @EventHandler + public void onChunkUnload(ChunkUnloadEvent event) { + Chunk chunk = event.getChunk(); + + for (NPC npc : NPCManager.getAllNPCs()) { + Chunk npcChunk = npc.getLocation().getChunk(); + + if (chunk.equals(npcChunk)) { + // Unloaded chunk with NPC in it. Hiding it from all players currently shown to. + + for (UUID uuid : npc.getShown()) { + // Safety check so it doesn't send packets if the NPC has already + // been automatically despawned by the system. + if (npc.getAutoHidden().contains(uuid)) { + continue; + } + + npc.hide(Bukkit.getPlayer(uuid), true); + } + } + } + } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + Chunk chunk = event.getChunk(); + + for (NPC npc : NPCManager.getAllNPCs()) { + Chunk npcChunk = npc.getLocation().getChunk(); + + if (chunk.equals(npcChunk)) { + // Loaded chunk with NPC in it. Showing it to the players again. + + for (UUID uuid : npc.getShown()) { + // Make sure not to respawn a not-hidden NPC. + if (!npc.getAutoHidden().contains(uuid)) { + continue; + } + + Player player = Bukkit.getPlayer(uuid); + + if (!npcChunk.getWorld().equals(player.getWorld())) { + continue; // Player and NPC are not in the same world. + } + + double hideDistance = npc.getAutoHideDistance(); + double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); + boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4); + + // Show the NPC (if in range). + if (inRange) { + npc.show(Bukkit.getPlayer(uuid), true); + } + } + } + } + } +} diff --git a/commons/src/main/java/net/jitse/npclib/listeners/PacketListener.java b/commons/src/main/java/net/jitse/npclib/listeners/PacketListener.java new file mode 100644 index 0000000..1deb175 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/listeners/PacketListener.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.listeners; + +import com.comphenix.tinyprotocol.Reflection; +import com.comphenix.tinyprotocol.TinyProtocol; +import io.netty.channel.Channel; +import net.jitse.npclib.NPCManager; +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.events.NPCInteractEvent; +import net.jitse.npclib.events.click.ClickType; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author Jitse Boonstra + */ +public class PacketListener { + + // Classes: + private final Class packetPlayInUseEntityClazz = Reflection.getMinecraftClass("PacketPlayInUseEntity"); + + // Fields: + private final Reflection.FieldAccessor entityIdField = Reflection.getField(packetPlayInUseEntityClazz, "a", int.class); + private final Reflection.FieldAccessor actionField = Reflection.getField(packetPlayInUseEntityClazz, "action", Object.class); + + // Prevent players from clicking at very high speeds. + private final Set delay = new HashSet<>(); + + public void start(JavaPlugin plugin) { + new TinyProtocol(plugin) { + + @Override + public Object onPacketInAsync(Player player, Channel channel, Object packet) { + + if (packetPlayInUseEntityClazz.isInstance(packet)) { + NPC npc = NPCManager.getAllNPCs().stream().filter( + check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet)) + .findFirst().orElse(null); + + if (npc == null) { + // Default player, not doing magic with the packet. + return super.onPacketInAsync(player, channel, packet); + } + + if (delay.contains(player.getUniqueId())) { + return null; + } + + ClickType clickType = actionField.get(packet).toString() + .equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK; + + Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc)); + + UUID uuid = player.getUniqueId(); + delay.add(uuid); + Bukkit.getScheduler().runTaskLater(plugin, () -> delay.remove(uuid), 1); + return null; + } else { + return super.onPacketInAsync(player, channel, packet); + } + } + }; + } +} diff --git a/commons/src/main/java/net/jitse/npclib/listeners/PlayerListener.java b/commons/src/main/java/net/jitse/npclib/listeners/PlayerListener.java new file mode 100644 index 0000000..cff5a98 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/listeners/PlayerListener.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.listeners; + +import net.jitse.npclib.NPCManager; +import net.jitse.npclib.api.NPC; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; + +/** + * @author Jitse Boonstra + */ +public class PlayerListener implements Listener { + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + for (NPC npc : NPCManager.getAllNPCs()) { + if (npc.getAutoHidden().contains(player.getUniqueId())) { + npc.getAutoHidden().remove(player.getUniqueId()); + } + + // Don't need to use NPC#hide since the entity is not registered in the NMS server. + if (npc.getShown().contains(player.getUniqueId())) { + npc.getShown().remove(player.getUniqueId()); + } + } + } + + @EventHandler + public void onPlayerChangedWorld(PlayerChangedWorldEvent event) { + Player player = event.getPlayer(); + World from = event.getFrom(); + + // The PlayerTeleportEvent is call, and will handle visibility in the new world. + for (NPC npc : NPCManager.getAllNPCs()) { + if (npc.getLocation().getWorld().equals(from)) { + if (!npc.getAutoHidden().contains(player.getUniqueId())) { + npc.getAutoHidden().add(player.getUniqueId()); + npc.hide(player, true); + } + } + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Location from = event.getFrom(); + Location to = event.getTo(); + + if (from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ()) { + return; + } + + handleMove(event.getPlayer()); + } + + @EventHandler + public void onPlayerTeleport(PlayerTeleportEvent event) { + handleMove(event.getPlayer()); + } + + private void handleMove(Player player) { + World world = player.getWorld(); + for (NPC npc : NPCManager.getAllNPCs()) { + if (!npc.getShown().contains(player.getUniqueId())) { + continue; // NPC was never supposed to be shown to the player. + } + + if (!npc.getLocation().getWorld().equals(world)) { + continue; // NPC is not in the same world. + } + + // If Bukkit doesn't track the NPC entity anymore, bypass the hiding distance variable. + // This will cause issues otherwise (e.g. custom skin disappearing). + double hideDistance = npc.getAutoHideDistance(); + double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); + boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4); + if (npc.getAutoHidden().contains(player.getUniqueId())) { + // Check if the player and NPC are within the range to sendShowPackets it again. + if (inRange) { + npc.show(player, true); + npc.getAutoHidden().remove(player.getUniqueId()); + } + } else { + // Check if the player and NPC are out of range to sendHidePackets it. + if (!inRange) { + npc.hide(player, true); + npc.getAutoHidden().add(player.getUniqueId()); + } + } + } + } +} diff --git a/commons/src/main/java/net/jitse/npclib/nms/holograms/Hologram.java b/commons/src/main/java/net/jitse/npclib/nms/holograms/Hologram.java new file mode 100644 index 0000000..6512eb5 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/nms/holograms/Hologram.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.holograms; + +import com.comphenix.tinyprotocol.Reflection; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Jitse Boonstra + */ +public class Hologram { + + private final double delta = 0.3; + + private List armorStands = new ArrayList<>(); + private Set spawnPackets = new HashSet<>(); + private Set destroyPackets = new HashSet<>(); + + // Classes: + private static final Class ENTITY_ARMOR_STAND_CLAZZ = Reflection.getMinecraftClass("EntityArmorStand"); + private static final Class ENTITY_LIVING_CLAZZ = Reflection.getMinecraftClass("EntityLiving"); + private static final Class ENTITY_CLAZZ = Reflection.getMinecraftClass("Entity"); + private static final Class CRAFT_BUKKIT_CLASS = Reflection.getCraftBukkitClass("CraftWorld"); + private static final Class CRAFT_PLAYER_CLAZZ = Reflection.getCraftBukkitClass("entity.CraftPlayer"); + private static final Class PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CLAZZ = Reflection.getMinecraftClass( + "PacketPlayOutSpawnEntityLiving"); + private static final Class PACKET_PLAY_OUT_ENTITY_DESTROY_CLAZZ = Reflection.getMinecraftClass( + "PacketPlayOutEntityDestroy"); + private static final Class ENTITY_PLAYER_CLAZZ = Reflection.getMinecraftClass("EntityPlayer"); + private static final Class PLAYER_CONNECTION_CLAZZ = Reflection.getMinecraftClass("PlayerConnection"); + private static final Class PACKET_CLAZZ = Reflection.getMinecraftClass("Packet"); + + // Constructors: + private static final Reflection.ConstructorInvoker PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CONSTRUCTOR = Reflection + .getConstructor(PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CLAZZ, ENTITY_LIVING_CLAZZ); + private static final Reflection.ConstructorInvoker PACKET_PLAY_OUT_ENTITY_DESTROY_CONSTRUCTOR = Reflection + .getConstructor(PACKET_PLAY_OUT_ENTITY_DESTROY_CLAZZ, int[].class); + + // Fields: + private static final Reflection.FieldAccessor playerConnectionField = Reflection.getField(ENTITY_PLAYER_CLAZZ, + "playerConnection", PLAYER_CONNECTION_CLAZZ); + + // Methods: + private static final Reflection.MethodInvoker SET_LOCATION_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setLocation", double.class, double.class, double.class, float.class, float.class); + private static final Reflection.MethodInvoker SET_CUSTOM_NAME_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setCustomName", String.class); + private static final Reflection.MethodInvoker SET_CUSTOM_NAME_VISIBLE_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setCustomNameVisible", boolean.class); + private static final Reflection.MethodInvoker SET_SMALL_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setSmall", boolean.class); + private static final Reflection.MethodInvoker SET_INVISIBLE_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setInvisible", boolean.class); + private static final Reflection.MethodInvoker SET_BASE_PLATE_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setBasePlate", boolean.class); + private static final Reflection.MethodInvoker SET_ARMS_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setArms", boolean.class); + private static final Reflection.MethodInvoker PLAYER_GET_HANDLE_METHOD = Reflection.getMethod(CRAFT_PLAYER_CLAZZ, + "getHandle"); + private static final Reflection.MethodInvoker SEND_PACKET_METHOD = Reflection.getMethod(PLAYER_CONNECTION_CLAZZ, + "sendPacket", PACKET_CLAZZ); + private static final Reflection.MethodInvoker GET_ID_METHOD = Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "getId"); + + private final Location start; + private final List lines; + private final Object worldServer; + + public Hologram(Location location, List lines) { + this.start = location; + this.lines = lines; + + this.worldServer = Reflection.getMethod(CRAFT_BUKKIT_CLASS, "getHandle") + .invoke(CRAFT_BUKKIT_CLASS.cast(location.getWorld())); + + } + + public void generatePackets(boolean above1_9_r2) { + Reflection.MethodInvoker gravityMethod = (above1_9_r2 ? Reflection.getMethod(ENTITY_CLAZZ, + "setNoGravity", boolean.class) : Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, + "setGravity", boolean.class)); + + Location location = start.clone().add(0, delta * lines.size(), 0); + Class worldClass = worldServer.getClass().getSuperclass(); + + if (start.getWorld().getEnvironment() != World.Environment.NORMAL) { + worldClass = worldClass.getSuperclass(); + } + + Reflection.ConstructorInvoker entityArmorStandConstructor = Reflection + .getConstructor(ENTITY_ARMOR_STAND_CLAZZ, worldClass); + + for (String line : lines) { + Object entityArmorStand = entityArmorStandConstructor.invoke(worldServer); + + SET_LOCATION_METHOD.invoke(entityArmorStand, location.getX(), location.getY(), location.getZ(), 0, 0); + SET_CUSTOM_NAME_METHOD.invoke(entityArmorStand, line); + SET_CUSTOM_NAME_VISIBLE_METHOD.invoke(entityArmorStand, true); + gravityMethod.invoke(entityArmorStand, above1_9_r2); + SET_SMALL_METHOD.invoke(entityArmorStand, true); + SET_INVISIBLE_METHOD.invoke(entityArmorStand, true); + SET_BASE_PLATE_METHOD.invoke(entityArmorStand, false); + SET_ARMS_METHOD.invoke(entityArmorStand, false); + + location.subtract(0, delta, 0); + + if (line.isEmpty()) { + continue; + } + + armorStands.add(entityArmorStand); + + Object spawnPacket = PACKET_PLAY_OUT_SPAWN_ENTITY_LIVING_CONSTRUCTOR.invoke(entityArmorStand); + spawnPackets.add(spawnPacket); + + Object destroyPacket = PACKET_PLAY_OUT_ENTITY_DESTROY_CONSTRUCTOR + .invoke(new int[]{(int) GET_ID_METHOD.invoke(entityArmorStand)}); + destroyPackets.add(destroyPacket); + } + } + + public void spawn(Player player) { + Object playerConnection = playerConnectionField.get(PLAYER_GET_HANDLE_METHOD + .invoke(CRAFT_PLAYER_CLAZZ.cast(player))); + + for (Object packet : spawnPackets) { + SEND_PACKET_METHOD.invoke(playerConnection, packet); + } + } + + public void destroy(Player player) { + Object playerConnection = playerConnectionField.get(PLAYER_GET_HANDLE_METHOD + .invoke(CRAFT_PLAYER_CLAZZ.cast(player))); + + for (Object packet : destroyPackets) { + SEND_PACKET_METHOD.invoke(playerConnection, packet); + } + } +} diff --git a/commons/src/main/java/net/jitse/npclib/skin/MineSkinFetcher.java b/commons/src/main/java/net/jitse/npclib/skin/MineSkinFetcher.java new file mode 100644 index 0000000..d2dccd9 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/skin/MineSkinFetcher.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.skin; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Scanner; + +/** + * @author Jitse Boonstra + */ +public class MineSkinFetcher { + + private static final String MINESKIN_API = "https://api.mineskin.org/get/id/"; + + public static void fetchSkinFromIdAsync(int id, Callback callback) { + new Thread(() -> { + try { + StringBuilder builder = new StringBuilder(); + HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(MINESKIN_API + id).openConnection(); + httpURLConnection.setRequestMethod("GET"); + httpURLConnection.setDoOutput(true); + httpURLConnection.setDoInput(true); + httpURLConnection.connect(); + + Scanner scanner = new Scanner(httpURLConnection.getInputStream()); + while (scanner.hasNextLine()) { + builder.append(scanner.nextLine()); + } + + scanner.close(); + httpURLConnection.disconnect(); + + JsonObject jsonObject = (JsonObject) new JsonParser().parse(builder.toString()); + JsonObject textures = jsonObject.get("data").getAsJsonObject().get("texture").getAsJsonObject(); + String value = textures.get("value").getAsString(); + String signature = textures.get("signature").getAsString(); + + callback.call(new Skin(value, signature)); + } catch (IOException exception) { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "Could not fetch skin! (Id: " + id + "). Message: " + exception.getMessage()); + exception.printStackTrace(); + callback.failed(); + } + }).start(); + } + + public interface Callback { + + void call(Skin skinData); + + default void failed() { + } + } +} diff --git a/commons/src/main/java/net/jitse/npclib/skin/Skin.java b/commons/src/main/java/net/jitse/npclib/skin/Skin.java new file mode 100644 index 0000000..181a4f0 --- /dev/null +++ b/commons/src/main/java/net/jitse/npclib/skin/Skin.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.skin; + +/** + * @author Jitse Boonstra + */ +public class Skin { + + private final String value, signature; + + public Skin(String value, String signature) { + this.value = value; + this.signature = signature; + } + + public String getValue() { + return this.value; + } + + public String getSignature() { + return this.signature; + } +} diff --git a/nms/pom.xml b/nms/pom.xml new file mode 100644 index 0000000..8fb4986 --- /dev/null +++ b/nms/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + pom + + net.jitse + npclib + 1.0.4 + + + npclib-nms + + + v1_8_R1 + v1_8_R2 + v1_8_R3 + v1_9_R1 + v1_9_R2 + v1_10_R1 + v1_11_R1 + v1_12_R1 + + + + + ${project.parent.groupId} + npclib-commons + ${project.parent.version} + provided + + + diff --git a/nms/v1_10_R1/pom.xml b/nms/v1_10_R1/pom.xml new file mode 100644 index 0000000..3dcb2d9 --- /dev/null +++ b/nms/v1_10_R1/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_10_R1 + + + + org.spigotmc + spigot + 1.10.2-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java new file mode 100644 index 0000000..9387c26 --- /dev/null +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_10_R1; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_10_R1.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_10_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_10_R1 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_10_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().subtract(0, 0.5, 0), lines); + hologram.generatePackets(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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..86a6457 --- /dev/null +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_10_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_10_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_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..3a81184 --- /dev/null +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_10_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_10_R1.DataWatcher; +import net.minecraft.server.v1_10_R1.DataWatcherObject; +import net.minecraft.server.v1_10_R1.DataWatcherRegistry; +import net.minecraft.server.v1_10_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_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..d07e54a --- /dev/null +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_10_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_10_R1.EnumGamemode; +import net.minecraft.server.v1_10_R1.IChatBaseComponent; +import net.minecraft.server.v1_10_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_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..9d66c1f --- /dev/null +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_10_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_10_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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_11_R1/pom.xml b/nms/v1_11_R1/pom.xml new file mode 100644 index 0000000..00e211e --- /dev/null +++ b/nms/v1_11_R1/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_11_R1 + + + + org.spigotmc + spigot + 1.11.2-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java new file mode 100644 index 0000000..2a5e65f --- /dev/null +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_11_R1; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_11_R1.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_11_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_11_R1 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_11_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); + hologram.generatePackets(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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..6de5178 --- /dev/null +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_11_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_11_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_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..d6e1cff --- /dev/null +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_11_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_11_R1.DataWatcher; +import net.minecraft.server.v1_11_R1.DataWatcherObject; +import net.minecraft.server.v1_11_R1.DataWatcherRegistry; +import net.minecraft.server.v1_11_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_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..52413e5 --- /dev/null +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_11_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_11_R1.EnumGamemode; +import net.minecraft.server.v1_11_R1.IChatBaseComponent; +import net.minecraft.server.v1_11_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_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..72f6f3b --- /dev/null +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_11_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_11_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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_12_R1/pom.xml b/nms/v1_12_R1/pom.xml new file mode 100644 index 0000000..b15f1af --- /dev/null +++ b/nms/v1_12_R1/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_12_R1 + + + + org.spigotmc + spigot + 1.12.2-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java new file mode 100644 index 0000000..385e3b0 --- /dev/null +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_12_R1; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_12_R1.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_12_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_12_R1.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_12_R1.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_12_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_12_R1 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_12_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); + hologram.generatePackets(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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..2abba78 --- /dev/null +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_12_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_12_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_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..323abde --- /dev/null +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_12_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_12_R1.DataWatcher; +import net.minecraft.server.v1_12_R1.DataWatcherObject; +import net.minecraft.server.v1_12_R1.DataWatcherRegistry; +import net.minecraft.server.v1_12_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_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..f13a0a4 --- /dev/null +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_12_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_12_R1.EnumGamemode; +import net.minecraft.server.v1_12_R1.IChatBaseComponent; +import net.minecraft.server.v1_12_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_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..6a1d4a5 --- /dev/null +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_12_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_12_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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_8_R1/pom.xml b/nms/v1_8_R1/pom.xml new file mode 100644 index 0000000..b7996ae --- /dev/null +++ b/nms/v1_8_R1/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_8_R1 + + + + org.spigotmc + spigot + 1.8-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java new file mode 100644 index 0000000..c606689 --- /dev/null +++ b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R1; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_8_R1.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_8_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_8_R1 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_8_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); + hologram.generatePackets(false); + + 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(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(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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..4d6eb40 --- /dev/null +++ b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_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_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..eac29db --- /dev/null +++ b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R1.DataWatcher; +import net.minecraft.server.v1_8_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", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D)); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D)); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D)); + 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.a(10, (byte) 127); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class) + .set(packetPlayOutNamedEntitySpawn, dataWatcher); + + return packetPlayOutNamedEntitySpawn; + } +} diff --git a/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..283b46e --- /dev/null +++ b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_8_R1.*; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutPlayerInfoWrapper { + + public PacketPlayOutPlayerInfo create(EnumPlayerInfoAction action, GameProfile gameProfile, String name) { + PacketPlayOutPlayerInfo packetPlayOutPlayerInfo = new PacketPlayOutPlayerInfo(); + Reflection.getField(packetPlayOutPlayerInfo.getClass(), "a", EnumPlayerInfoAction.class) + .set(packetPlayOutPlayerInfo, action); + + PlayerInfoData playerInfoData = new PlayerInfoData(packetPlayOutPlayerInfo, gameProfile, + 1, EnumGamemode.NOT_SET, ChatSerializer.a(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_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..e682a39 --- /dev/null +++ b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R1.PacketPlayOutScoreboardTeam; +import org.bukkit.ChatColor; + +import java.util.Collection; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutScoreboardTeamWrapper { + + public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { + PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); + + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "h", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) + .set(packetPlayOutScoreboardTeam, "never"); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) + .set(packetPlayOutScoreboardTeam, 1); + // Could not get this working in the PacketPlayOutPlayerInfoWrapper class. + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class) + .set(packetPlayOutScoreboardTeam, ChatColor.BLUE + "[NPC] "); + Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( + packetPlayOutScoreboardTeam.getClass(), "g", 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(), "h", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_8_R2/pom.xml b/nms/v1_8_R2/pom.xml new file mode 100644 index 0000000..9e5a42f --- /dev/null +++ b/nms/v1_8_R2/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_8_R2 + + + + org.spigotmc + spigot + 1.8.3-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java new file mode 100644 index 0000000..3e15747 --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R2; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_8_R2.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_8_R2.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_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_8_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_8_R2(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); + hologram.generatePackets(false); + + 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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..5ac6220 --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R2.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_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..f48b8c8 --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R2.DataWatcher; +import net.minecraft.server.v1_8_R2.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", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D)); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D)); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D)); + 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.a(10, (byte) 127); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class) + .set(packetPlayOutNamedEntitySpawn, dataWatcher); + + return packetPlayOutNamedEntitySpawn; + } +} diff --git a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..bca9688 --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_8_R2.IChatBaseComponent; +import net.minecraft.server.v1_8_R2.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_8_R2.WorldSettings; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutPlayerInfoWrapper { + + 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); + + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = packetPlayOutPlayerInfo.new PlayerInfoData(gameProfile, 1, + WorldSettings.EnumGamemode.NOT_SET, IChatBaseComponent.ChatSerializer.a(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_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..89a6e7a --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R2.PacketPlayOutScoreboardTeam; +import org.bukkit.ChatColor; + +import java.util.Collection; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutScoreboardTeamWrapper { + + public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { + PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); + + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "h", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) + .set(packetPlayOutScoreboardTeam, "never"); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) + .set(packetPlayOutScoreboardTeam, 1); + // Could not get this working in the PacketPlayOutPlayerInfoWrapper class. + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class) + .set(packetPlayOutScoreboardTeam, ChatColor.BLUE + "[NPC] "); + Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( + packetPlayOutScoreboardTeam.getClass(), "g", 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(), "h", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_8_R3/pom.xml b/nms/v1_8_R3/pom.xml new file mode 100644 index 0000000..5738747 --- /dev/null +++ b/nms/v1_8_R3/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_8_R3 + + + + org.spigotmc + spigot + 1.8.8-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java new file mode 100644 index 0000000..52895c1 --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R3; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_8_R3.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_8_R3.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_8_R3 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_8_R3(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().add(0, 0.5, 0), lines); + hologram.generatePackets(false); + + 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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..e50ebb9 --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R3.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R3.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_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..b23b72b --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R3.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R3.DataWatcher; +import net.minecraft.server.v1_8_R3.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", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getX() * 32.0D)); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "d", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getY() * 32.0D)); + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "e", int.class) + .set(packetPlayOutNamedEntitySpawn, (int) Math.floor(location.getZ() * 32.0D)); + 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.a(10, (byte) 127); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "i", DataWatcher.class) + .set(packetPlayOutNamedEntitySpawn, dataWatcher); + + return packetPlayOutNamedEntitySpawn; + } +} diff --git a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..3c411df --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R3.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_8_R3.IChatBaseComponent; +import net.minecraft.server.v1_8_R3.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_8_R3.WorldSettings; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutPlayerInfoWrapper { + + 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); + + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = packetPlayOutPlayerInfo.new PlayerInfoData(gameProfile, 1, + WorldSettings.EnumGamemode.NOT_SET, IChatBaseComponent.ChatSerializer.a(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_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..3b6b53c --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_8_R3.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_8_R3.PacketPlayOutScoreboardTeam; +import org.bukkit.ChatColor; + +import java.util.Collection; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutScoreboardTeamWrapper { + + public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { + PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); + + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "h", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "e", String.class) + .set(packetPlayOutScoreboardTeam, "never"); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "i", int.class) + .set(packetPlayOutScoreboardTeam, 1); + // Could not get this working in the PacketPlayOutPlayerInfoWrapper class. + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "c", String.class) + .set(packetPlayOutScoreboardTeam, ChatColor.BLUE + "[NPC] "); + Reflection.FieldAccessor collectionFieldAccessor = Reflection.getField( + packetPlayOutScoreboardTeam.getClass(), "g", 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(), "h", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_9_R1/pom.xml b/nms/v1_9_R1/pom.xml new file mode 100644 index 0000000..0ae9204 --- /dev/null +++ b/nms/v1_9_R1/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_9_R1 + + + + org.spigotmc + spigot + 1.9-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java new file mode 100644 index 0000000..36f1721 --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R1; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_9_R1.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_9_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class NPC_v1_9_R1 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_9_R1(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().subtract(0, 0.5, 0), lines); + hologram.generatePackets(false); + + 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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..72b2a04 --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_9_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_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..d0a2504 --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_9_R1.DataWatcher; +import net.minecraft.server.v1_9_R1.DataWatcherObject; +import net.minecraft.server.v1_9_R1.DataWatcherRegistry; +import net.minecraft.server.v1_9_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<>(12, DataWatcherRegistry.a), (byte) 127); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "h", DataWatcher.class) + .set(packetPlayOutNamedEntitySpawn, dataWatcher); + + return packetPlayOutNamedEntitySpawn; + } +} diff --git a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..43695c7 --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_9_R1.IChatBaseComponent; +import net.minecraft.server.v1_9_R1.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_9_R1.WorldSettings; +import org.bukkit.ChatColor; + +import java.util.List; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutPlayerInfoWrapper { + + 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); + + PacketPlayOutPlayerInfo.PlayerInfoData playerInfoData = new PacketPlayOutPlayerInfo().new PlayerInfoData(gameProfile, 1, + WorldSettings.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_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..ea81eee --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_9_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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/nms/v1_9_R2/pom.xml b/nms/v1_9_R2/pom.xml new file mode 100644 index 0000000..8fcd700 --- /dev/null +++ b/nms/v1_9_R2/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + net.jitse + npclib-nms + 1.0.4 + + + npclib-nms-v1_9_R2 + + + + org.spigotmc + spigot + 1.9.4-R0.1-SNAPSHOT + provided + + + diff --git a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java new file mode 100644 index 0000000..21a40de --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R2; + +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.nms.holograms.Hologram; +import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutEntityHeadRotationWrapper; +import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutNamedEntitySpawnWrapper; +import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutPlayerInfoWrapper; +import net.jitse.npclib.nms.v1_9_R2.packets.PacketPlayOutScoreboardTeamWrapper; +import net.jitse.npclib.skin.Skin; +import net.minecraft.server.v1_9_R2.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_9_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_9_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_9_R2(JavaPlugin plugin, Skin skin, double autoHideDistance, List lines) { + super(plugin, skin, autoHideDistance, lines); + } + + @Override + public void create(Location location) { + this.location = location; + + this.hologram = new Hologram(location.clone().subtract(0, 0.5, 0), lines); + hologram.generatePackets(false); + + 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), 5); + } + + @Override + public void sendHidePackets(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + playerConnection.sendPacket(packetPlayOutEntityDestroy); + playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); + + hologram.destroy(player); + + // 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); + } +} diff --git a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java new file mode 100644 index 0000000..6b2d008 --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityHeadRotationWrapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_9_R2.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_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java new file mode 100644 index 0000000..39f5a3c --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutNamedEntitySpawnWrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_9_R2.DataWatcher; +import net.minecraft.server.v1_9_R2.DataWatcherObject; +import net.minecraft.server.v1_9_R2.DataWatcherRegistry; +import net.minecraft.server.v1_9_R2.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<>(12, DataWatcherRegistry.a), (byte) 127); + + Reflection.getField(packetPlayOutNamedEntitySpawn.getClass(), "h", DataWatcher.class) + .set(packetPlayOutNamedEntitySpawn, dataWatcher); + + return packetPlayOutNamedEntitySpawn; + } +} diff --git a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java new file mode 100644 index 0000000..67afd64 --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutPlayerInfoWrapper.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_9_R2.IChatBaseComponent; +import net.minecraft.server.v1_9_R2.PacketPlayOutPlayerInfo; +import net.minecraft.server.v1_9_R2.WorldSettings; +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, WorldSettings.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, WorldSettings.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_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java new file mode 100644 index 0000000..38e4b3e --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutScoreboardTeamWrapper.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.nms.v1_9_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.minecraft.server.v1_9_R2.PacketPlayOutScoreboardTeam; + +import java.util.Collection; + +/** + * @author Jitse Boonstra + */ +public class PacketPlayOutScoreboardTeamWrapper { + + public PacketPlayOutScoreboardTeam createRegisterTeam(String name) { + PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeam = new PacketPlayOutScoreboardTeam(); + + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 0); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "b", String.class) + .set(packetPlayOutScoreboardTeam, name); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, 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(), "i", 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(), "g", int.class) + .set(packetPlayOutScoreboardTeam, 1); + Reflection.getField(packetPlayOutScoreboardTeam.getClass(), "a", String.class) + .set(packetPlayOutScoreboardTeam, name); + + return packetPlayOutScoreboardTeam; + } +} diff --git a/plugin/pom.xml b/plugin/pom.xml new file mode 100644 index 0000000..481ae46 --- /dev/null +++ b/plugin/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + + net.jitse + npclib + 1.0.4 + + + npclib-plugin + + + NPCLib + + + src/main/resources + true + + + + + + + ${project.parent.groupId} + npclib-api + ${project.parent.version} + compile + + + diff --git a/plugin/src/main/java/net/jitse/npclib/plugin/NPCLibPlugin.java b/plugin/src/main/java/net/jitse/npclib/plugin/NPCLibPlugin.java new file mode 100644 index 0000000..2cd427d --- /dev/null +++ b/plugin/src/main/java/net/jitse/npclib/plugin/NPCLibPlugin.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.plugin; + +import net.jitse.npclib.NPCLib; +import net.jitse.npclib.api.NPC; +import net.jitse.npclib.plugin.listeners.NPCListener; +import net.jitse.npclib.skin.MineSkinFetcher; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Arrays; + +/** + * @author Jitse Boonstra + */ +public class NPCLibPlugin extends JavaPlugin implements Listener { + + private NPCLib npcLib; + + @Override + public void onEnable() { + this.npcLib = new NPCLib(this); + getServer().getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + ChatColor.WHITE + "plugin enabled."); + getServer().getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + + ChatColor.GRAY + "This is a test plugin usually used for development reasons. " + + "You can spawn NPCs by pressing [shift] in game."); + + + getServer().getPluginManager().registerEvents(this, this); + getServer().getPluginManager().registerEvents(new NPCListener(), this); + } + + @Override + public void onDisable() { + getServer().getConsoleSender().sendMessage(ChatColor.BLUE + "[NPCLib] " + ChatColor.WHITE + "plugin disabled."); + } + + @EventHandler + public void onPlayerShift(PlayerToggleSneakEvent event) { + if (event.isSneaking()) { + return; + } + + MineSkinFetcher.fetchSkinFromIdAsync(168841, skin -> { + NPC npc = npcLib.createNPC(skin, Arrays.asList( + ChatColor.BOLD + "NPC Library", "", + "Create your own", "non-player characters", + "with the simplistic", "API of NPCLib!" + )); + npc.create(event.getPlayer().getLocation()); + + for (Player player : getServer().getOnlinePlayers()) { + npc.show(player); + } + }); + } +} diff --git a/plugin/src/main/java/net/jitse/npclib/plugin/listeners/NPCListener.java b/plugin/src/main/java/net/jitse/npclib/plugin/listeners/NPCListener.java new file mode 100644 index 0000000..14d3ef3 --- /dev/null +++ b/plugin/src/main/java/net/jitse/npclib/plugin/listeners/NPCListener.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Jitse Boonstra + */ + +package net.jitse.npclib.plugin.listeners; + +import net.jitse.npclib.events.NPCDestroyEvent; +import net.jitse.npclib.events.NPCInteractEvent; +import net.jitse.npclib.events.NPCSpawnEvent; +import org.bukkit.ChatColor; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +/** + * @author Jitse Boonstra + */ +public class NPCListener implements Listener { + + @EventHandler + public void onNPCSpawn(NPCSpawnEvent event) { + event.getPlayer().sendMessage(ChatColor.GREEN + "Spawned NPC " + event.getNPC().getEntityId()); + } + + @EventHandler + public void onNPCDestroy(NPCDestroyEvent event) { + event.getPlayer().sendMessage(ChatColor.RED + "Destroyed NPC " + event.getNPC().getEntityId()); + } + + @EventHandler + public void onNPCInteract(NPCInteractEvent event) { + event.getWhoClicked().sendMessage(ChatColor.BLUE + "Interacted with NPC " + + event.getNPC().getEntityId() + " type " + event.getClickType()); + } +} diff --git a/plugin/src/main/resources/plugin.yml b/plugin/src/main/resources/plugin.yml new file mode 100644 index 0000000..2f76287 --- /dev/null +++ b/plugin/src/main/resources/plugin.yml @@ -0,0 +1,5 @@ +name: NPCLib +version: 1.0.4 +author: JitseB +main: net.jitse.npclib.plugin.NPCLibPlugin +description: An NPC library. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..9a914dd --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + + + 4.0.0 + pom + + net.jitse + npclib + 1.0.4 + + NPCLib + https://github.com/JitseB/npclib + + + UTF-8 + + + + + MIT + https://opensource.org/licenses/MIT + repo + + + + + clean install + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + + package + + shade + + + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.12.2-R0.1-SNAPSHOT + provided + + + + + commons + nms + api + plugin + + \ No newline at end of file From 19c6ca645b70145676028dcd82571d8a2f1290bc Mon Sep 17 00:00:00 2001 From: JitseB Date: Sat, 5 May 2018 19:14:23 +0200 Subject: [PATCH 3/3] Few small changes in the pom files. --- commons/pom.xml | 8 ++++++++ plugin/pom.xml | 3 ++- pom.xml | 7 ------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/commons/pom.xml b/commons/pom.xml index 6016a07..d480999 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -12,4 +12,12 @@ npclib-commons + + + org.spigotmc + spigot + 1.12.2-R0.1-SNAPSHOT + provided + + diff --git a/plugin/pom.xml b/plugin/pom.xml index 481ae46..7818ea2 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -13,7 +13,8 @@ npclib-plugin - NPCLib + ../target + NPCLib-v${project.parent.version} src/main/resources diff --git a/pom.xml b/pom.xml index 9a914dd..11e2e5b 100644 --- a/pom.xml +++ b/pom.xml @@ -68,13 +68,6 @@ 1.12.2-R0.1-SNAPSHOT provided - - - org.spigotmc - spigot - 1.12.2-R0.1-SNAPSHOT - provided -