diff --git a/src/de/steamwar/lobby/display/NPC.java b/src/de/steamwar/lobby/display/NPC.java index 8e0e6e5..9907f16 100644 --- a/src/de/steamwar/lobby/display/NPC.java +++ b/src/de/steamwar/lobby/display/NPC.java @@ -22,11 +22,12 @@ package de.steamwar.lobby.display; import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; import com.mojang.authlib.GameProfile; -import de.steamwar.lobby.LobbySystem; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -74,6 +75,41 @@ public class NPC { private static final Reflection.FieldAccessor movePacketPitch = Reflection.getField(movePacket, byte.class, 1); private static final Reflection.FieldAccessor movePacketOnGround = Reflection.getField(movePacket, boolean.class, 0); + private static final Class dataWatcherObject = Reflection.getClass("{nms.network.syncher}.DataWatcherObject"); + private static final Class dataWatcherRegistry = Reflection.getClass("{nms.network.syncher}.DataWatcherRegistry"); + private static final Class dataWatcherSerializer = Reflection.getClass("{nms.network.syncher}.DataWatcherSerializer"); + private static final Reflection.ConstructorInvoker dataWatcherObjectConstructor = Reflection.getConstructor(dataWatcherObject, int.class, dataWatcherSerializer); + private static Object getDataWatcherObject(int index, Class type) { + for(Field field : dataWatcherRegistry.getFields()) { + if(dataWatcherSerializer.isAssignableFrom(field.getType()) && type.equals(((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0])) { + try { + return dataWatcherObjectConstructor.invoke(index, field.get(null)); + } catch (IllegalAccessException e) { + throw new SecurityException("Could not get field", e); + } + } + } + throw new SecurityException("Could not find Serializer for " + type.getName()); + } + + private static final Class item = Reflection.getClass("{nms.network.syncher}.DataWatcher$Item"); + private static final Reflection.ConstructorInvoker itemConstructor = Reflection.getConstructor(item, dataWatcherObject, Object.class); + private static Object getDataWatcherItem(Object dwo, Object value) { + return itemConstructor.invoke(dwo, value); + } + + private static final Class metadataPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityMetadata"); + private static final Reflection.FieldAccessor metadataEntity = Reflection.getField(metadataPacket, int.class, 0); + private static final Reflection.FieldAccessor metadataMetadata = Reflection.getField(metadataPacket, List.class, 0); + private Object getDataWatcherPacket(Object dataWatcherObject, Object value) { + Object packet = Reflection.newInstance(metadataPacket); + metadataEntity.set(packet, entityId); + metadataMetadata.set(packet, Collections.singletonList(getDataWatcherItem(dataWatcherObject, value))); + return packet; + } + + private static Object skinPartsDataWatcherObject = getDataWatcherObject(17, Byte.class); + private final Displayable display; private final int entityId; @@ -83,6 +119,7 @@ public class NPC { private final Object addPlayerInfo; private final Object namedSpawn; + private final Object skinParts; private final Object headRotation; private final Object removePlayerInfo; private final Object destroy; @@ -100,6 +137,8 @@ public class NPC { removePlayerInfo = playerInfoPacket(removePlayer, profile); destroy = Hologram.destroyPacket(entityId); + skinParts = getDataWatcherPacket(skinPartsDataWatcherObject, (byte) 0xFF); + namedSpawn = namedSpawnConstructor.invoke(); namedSpawnEntity.set(namedSpawn, entityId); namedSpawnUUID.set(namedSpawn, uuid); @@ -142,6 +181,7 @@ public class NPC { TinyProtocol.instance.sendPacket(player, addPlayerInfo); TinyProtocol.instance.sendPacket(player, namedSpawn); TinyProtocol.instance.sendPacket(player, headRotation); + TinyProtocol.instance.sendPacket(player, skinParts); } private void hide(Player player) {