diff --git a/api/src/main/java/net/jitse/npclib/api/state/NPCSlot.java b/api/src/main/java/net/jitse/npclib/api/state/NPCSlot.java index e868eeb..3fa1341 100644 --- a/api/src/main/java/net/jitse/npclib/api/state/NPCSlot.java +++ b/api/src/main/java/net/jitse/npclib/api/state/NPCSlot.java @@ -6,7 +6,8 @@ public enum NPCSlot { CHESTPLATE(3), LEGGINGS(2), BOOTS(1), - IN_HAND(0); + MAINHAND(0), + OFFHAND(5); int slot; diff --git a/api/src/main/java/net/jitse/npclib/hologram/Hologram.java b/api/src/main/java/net/jitse/npclib/hologram/Hologram.java index bf91b78..6777211 100644 --- a/api/src/main/java/net/jitse/npclib/hologram/Hologram.java +++ b/api/src/main/java/net/jitse/npclib/hologram/Hologram.java @@ -83,6 +83,7 @@ public class Hologram { } public void generatePackets(MinecraftVersion version) { + // TODO: Check when this method was changed (1.9 R2 is giving an exception... Reflection.MethodInvoker gravityMethod = (version.isAboveOrEqual(MinecraftVersion.V1_9_R2) ? Reflection.getMethod(ENTITY_CLAZZ, "setNoGravity", boolean.class) : Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, "setGravity", boolean.class)); diff --git a/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java b/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java index 9ea6cc9..f3ce9d3 100755 --- a/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java +++ b/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java @@ -20,10 +20,10 @@ interface PacketHandler { void sendMetadataPacket(Player player); - void sendEquipmentPacket(Player player, NPCSlot slot); + void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto); default void sendEquipmentPackets(Player player) { for (NPCSlot slot : NPCSlot.values()) - sendEquipmentPacket(player, slot); + sendEquipmentPacket(player, slot, true); } } diff --git a/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java b/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java index f021cf0..db30d79 100644 --- a/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java +++ b/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java @@ -41,7 +41,8 @@ public abstract class SimpleNPC implements NPC, PacketHandler { protected Location location; protected Skin skin; - protected ItemStack helmet, chestplate, leggings, boots, inHand; + // offHand support in 1.9 R1 and later. + protected ItemStack helmet, chestplate, leggings, boots, inHand, offHand; public SimpleNPC(NPCLib instance, List lines) { this.instance = instance; @@ -280,7 +281,7 @@ public abstract class SimpleNPC implements NPC, PacketHandler { case BOOTS: this.boots = item; break; - case IN_HAND: + case MAINHAND: this.inHand = item; break; default: @@ -290,7 +291,7 @@ public abstract class SimpleNPC implements NPC, PacketHandler { for (UUID shownUuid : shown) { Player player = Bukkit.getPlayer(shownUuid); if (player != null && isShown(player)) { - sendEquipmentPacket(player, slot); + sendEquipmentPacket(player, slot, false); } } return this; diff --git a/nms/pom.xml b/nms/pom.xml index 1c4868b..1ba2367 100644 --- a/nms/pom.xml +++ b/nms/pom.xml @@ -15,16 +15,16 @@ v1_8_R1 - - - - - - - - - - + v1_8_R2 + v1_8_R3 + v1_9_R1 + v1_9_R2 + + + + + + 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 index b96f09e..5354679 100755 --- 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 @@ -107,7 +107,7 @@ public class NPC_v1_8_R1 extends SimpleNPC { } @Override - public void sendEquipmentPacket(Player player, NPCSlot slot) { + public void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; ItemStack item; @@ -124,11 +124,14 @@ public class NPC_v1_8_R1 extends SimpleNPC { case BOOTS: item = boots; break; - case IN_HAND: + case MAINHAND: item = inHand; break; default: - throw new IllegalArgumentException("Slot is not recognized"); + if (!auto) { + throw new IllegalArgumentException(slot.toString() + " is not a supported slot for the version of your server"); + } + return; } PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(entityId, slot.getSlot(), CraftItemStack.asNMSCopy(item)); 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 index 8357855..e32c2fc 100755 --- 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 @@ -5,17 +5,17 @@ package net.jitse.npclib.nms.v1_8_R2; import net.jitse.npclib.NPCLib; +import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.hologram.Hologram; import net.jitse.npclib.internal.MinecraftVersion; import net.jitse.npclib.internal.SimpleNPC; -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.nms.v1_8_R2.packets.*; import net.minecraft.server.v1_8_R2.*; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_8_R2.inventory.CraftItemStack; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.HashSet; import java.util.List; @@ -96,4 +96,44 @@ public class NPC_v1_8_R2 extends SimpleNPC { playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); hologram.destroy(player); } + + @Override + public void sendMetadataPacket(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadataWrapper().create(activeStates, entityId); + + playerConnection.sendPacket(packet); + } + + @Override + public void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + ItemStack item; + switch (slot) { + case HELMET: + item = helmet; + break; + case CHESTPLATE: + item = chestplate; + break; + case LEGGINGS: + item = leggings; + break; + case BOOTS: + item = boots; + break; + case MAINHAND: + item = inHand; + break; + default: + if (!auto) { + throw new IllegalArgumentException(slot.toString() + " is not a supported slot for the version of your server"); + } + return; + } + + PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(entityId, slot.getSlot(), CraftItemStack.asNMSCopy(item)); + playerConnection.sendPacket(packet); + } } diff --git a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityMetadataWrapper.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityMetadataWrapper.java new file mode 100644 index 0000000..625fc80 --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutEntityMetadataWrapper.java @@ -0,0 +1,16 @@ +package net.jitse.npclib.nms.v1_8_R2.packets; + +import net.jitse.npclib.api.state.NPCState; +import net.minecraft.server.v1_8_R2.DataWatcher; +import net.minecraft.server.v1_8_R2.PacketPlayOutEntityMetadata; + +public class PacketPlayOutEntityMetadataWrapper { + + public PacketPlayOutEntityMetadata create(NPCState[] activateStates, int entityId) { + DataWatcher dataWatcher = new DataWatcher(null); + byte masked = NPCState.getMasked(activateStates); + dataWatcher.a(0, masked); + + return new PacketPlayOutEntityMetadata(entityId, dataWatcher, true); + } +} 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 index b7742b6..fe1a50d 100755 --- 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 @@ -5,17 +5,17 @@ package net.jitse.npclib.nms.v1_8_R3; import net.jitse.npclib.NPCLib; +import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.hologram.Hologram; import net.jitse.npclib.internal.MinecraftVersion; import net.jitse.npclib.internal.SimpleNPC; -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.nms.v1_8_R3.packets.*; import net.minecraft.server.v1_8_R3.*; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.HashSet; import java.util.List; @@ -97,4 +97,44 @@ public class NPC_v1_8_R3 extends SimpleNPC { playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); hologram.destroy(player); } + + @Override + public void sendMetadataPacket(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadataWrapper().create(activeStates, entityId); + + playerConnection.sendPacket(packet); + } + + @Override + public void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + ItemStack item; + switch (slot) { + case HELMET: + item = helmet; + break; + case CHESTPLATE: + item = chestplate; + break; + case LEGGINGS: + item = leggings; + break; + case BOOTS: + item = boots; + break; + case MAINHAND: + item = inHand; + break; + default: + if (!auto) { + throw new IllegalArgumentException(slot.toString() + " is not a supported slot for the version of your server"); + } + return; + } + + PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(entityId, slot.getSlot(), CraftItemStack.asNMSCopy(item)); + playerConnection.sendPacket(packet); + } } diff --git a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityMetadataWrapper.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityMetadataWrapper.java new file mode 100644 index 0000000..398a4a4 --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutEntityMetadataWrapper.java @@ -0,0 +1,16 @@ +package net.jitse.npclib.nms.v1_8_R3.packets; + +import net.jitse.npclib.api.state.NPCState; +import net.minecraft.server.v1_8_R3.DataWatcher; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityMetadata; + +public class PacketPlayOutEntityMetadataWrapper { + + public PacketPlayOutEntityMetadata create(NPCState[] activateStates, int entityId) { + DataWatcher dataWatcher = new DataWatcher(null); + byte masked = NPCState.getMasked(activateStates); + dataWatcher.a(0, masked); + + return new PacketPlayOutEntityMetadata(entityId, dataWatcher, true); + } +} 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 index 42ea977..7fff571 100755 --- 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 @@ -5,17 +5,17 @@ package net.jitse.npclib.nms.v1_9_R1; import net.jitse.npclib.NPCLib; +import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.hologram.Hologram; import net.jitse.npclib.internal.MinecraftVersion; import net.jitse.npclib.internal.SimpleNPC; -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.nms.v1_9_R1.packets.*; import net.minecraft.server.v1_9_R1.*; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_9_R1.inventory.CraftItemStack; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.HashSet; import java.util.List; @@ -96,4 +96,54 @@ public class NPC_v1_9_R1 extends SimpleNPC { playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); hologram.destroy(player); } + + @Override + public void sendMetadataPacket(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadataWrapper().create(activeStates, entityId); + + playerConnection.sendPacket(packet); + } + + @Override + public void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + EnumItemSlot nmsSlot; + ItemStack item; + switch (slot) { + case HELMET: + item = helmet; + nmsSlot = EnumItemSlot.HEAD; + break; + case CHESTPLATE: + item = chestplate; + nmsSlot = EnumItemSlot.CHEST; + break; + case LEGGINGS: + item = leggings; + nmsSlot = EnumItemSlot.LEGS; + break; + case BOOTS: + item = boots; + nmsSlot = EnumItemSlot.FEET; + break; + case MAINHAND: + item = inHand; + nmsSlot = EnumItemSlot.MAINHAND; + break; + case OFFHAND: + item = offHand; + nmsSlot = EnumItemSlot.OFFHAND; + break; + default: + if (!auto) { + throw new IllegalArgumentException(slot.toString() + " is not a supported slot for the version of your server"); + } + return; + } + + PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(entityId, nmsSlot, CraftItemStack.asNMSCopy(item)); + playerConnection.sendPacket(packet); + } } diff --git a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityMetadataWrapper.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityMetadataWrapper.java new file mode 100644 index 0000000..91476bd --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutEntityMetadataWrapper.java @@ -0,0 +1,18 @@ +package net.jitse.npclib.nms.v1_9_R1.packets; + +import net.jitse.npclib.api.state.NPCState; +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.PacketPlayOutEntityMetadata; + +public class PacketPlayOutEntityMetadataWrapper { + + public PacketPlayOutEntityMetadata create(NPCState[] activateStates, int entityId) { + DataWatcher dataWatcher = new DataWatcher(null); + byte masked = NPCState.getMasked(activateStates); + dataWatcher.register(new DataWatcherObject<>(0, DataWatcherRegistry.a), masked); + + return new PacketPlayOutEntityMetadata(entityId, dataWatcher, true); + } +} 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 index e5bd316..bdd70f5 100755 --- 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 @@ -5,17 +5,17 @@ package net.jitse.npclib.nms.v1_9_R2; import net.jitse.npclib.NPCLib; +import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.hologram.Hologram; import net.jitse.npclib.internal.MinecraftVersion; import net.jitse.npclib.internal.SimpleNPC; -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.nms.v1_9_R2.packets.*; import net.minecraft.server.v1_9_R2.*; import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_9_R2.inventory.CraftItemStack; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.HashSet; import java.util.List; @@ -97,4 +97,54 @@ public class NPC_v1_9_R2 extends SimpleNPC { playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); hologram.destroy(player); } + + @Override + public void sendMetadataPacket(Player player) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + PacketPlayOutEntityMetadata packet = new PacketPlayOutEntityMetadataWrapper().create(activeStates, entityId); + + playerConnection.sendPacket(packet); + } + + @Override + public void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + EnumItemSlot nmsSlot; + ItemStack item; + switch (slot) { + case HELMET: + item = helmet; + nmsSlot = EnumItemSlot.HEAD; + break; + case CHESTPLATE: + item = chestplate; + nmsSlot = EnumItemSlot.CHEST; + break; + case LEGGINGS: + item = leggings; + nmsSlot = EnumItemSlot.LEGS; + break; + case BOOTS: + item = boots; + nmsSlot = EnumItemSlot.FEET; + break; + case MAINHAND: + item = inHand; + nmsSlot = EnumItemSlot.MAINHAND; + break; + case OFFHAND: + item = offHand; + nmsSlot = EnumItemSlot.OFFHAND; + break; + default: + if (!auto) { + throw new IllegalArgumentException(slot.toString() + " is not a supported slot for the version of your server"); + } + return; + } + + PacketPlayOutEntityEquipment packet = new PacketPlayOutEntityEquipment(entityId, nmsSlot, CraftItemStack.asNMSCopy(item)); + playerConnection.sendPacket(packet); + } } diff --git a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityMetadataWrapper.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityMetadataWrapper.java new file mode 100644 index 0000000..778100a --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutEntityMetadataWrapper.java @@ -0,0 +1,18 @@ +package net.jitse.npclib.nms.v1_9_R2.packets; + +import net.jitse.npclib.api.state.NPCState; +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.PacketPlayOutEntityMetadata; + +public class PacketPlayOutEntityMetadataWrapper { + + public PacketPlayOutEntityMetadata create(NPCState[] activateStates, int entityId) { + DataWatcher dataWatcher = new DataWatcher(null); + byte masked = NPCState.getMasked(activateStates); + dataWatcher.register(new DataWatcherObject<>(0, DataWatcherRegistry.a), masked); + + return new PacketPlayOutEntityMetadata(entityId, dataWatcher, true); + } +}