diff --git a/api/src/main/java/net/jitse/npclib/api/NPC.java b/api/src/main/java/net/jitse/npclib/api/NPC.java index 16b9fe0..3836644 100644 --- a/api/src/main/java/net/jitse/npclib/api/NPC.java +++ b/api/src/main/java/net/jitse/npclib/api/NPC.java @@ -5,6 +5,7 @@ package net.jitse.npclib.api; import net.jitse.npclib.api.skin.Skin; +import net.jitse.npclib.api.state.NPCAnimation; import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.api.state.NPCState; import org.bukkit.Location; @@ -103,6 +104,13 @@ public interface NPC { */ NPC toggleState(NPCState state); + /** + * Plays an animation as the the NPC. + * + * @param animation The animation to play. + */ + void playAnimation(NPCAnimation animation); + /** * Get state of NPC. * diff --git a/api/src/main/java/net/jitse/npclib/api/state/NPCAnimation.java b/api/src/main/java/net/jitse/npclib/api/state/NPCAnimation.java new file mode 100644 index 0000000..119f250 --- /dev/null +++ b/api/src/main/java/net/jitse/npclib/api/state/NPCAnimation.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.api.state; + +public enum NPCAnimation { + + SWING_MAINHAND(0), + TAKE_DAMAGE(1), + SWING_OFFHAND(3), + CRITICAL_DAMAGE(4), + MAGICAL_DAMAGE(5); + + private int id; + + NPCAnimation(int id) { + this.id = id; + } + + public int getId() { + return id; + } +} diff --git a/api/src/main/java/net/jitse/npclib/internal/NPCBase.java b/api/src/main/java/net/jitse/npclib/internal/NPCBase.java index 3bd2152..05b0856 100644 --- a/api/src/main/java/net/jitse/npclib/internal/NPCBase.java +++ b/api/src/main/java/net/jitse/npclib/internal/NPCBase.java @@ -11,6 +11,7 @@ import net.jitse.npclib.api.NPC; import net.jitse.npclib.api.events.NPCHideEvent; import net.jitse.npclib.api.events.NPCShowEvent; import net.jitse.npclib.api.skin.Skin; +import net.jitse.npclib.api.state.NPCAnimation; import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.api.state.NPCState; import net.jitse.npclib.hologram.Hologram; @@ -268,6 +269,16 @@ public abstract class NPCBase implements NPC, NPCPacketHandler { return this; } + @Override + public void playAnimation(NPCAnimation animation) { + for (UUID shownUuid : shown) { + Player player = Bukkit.getPlayer(shownUuid); + if (player != null && isShown(player)) { + sendAnimationPacket(player, animation); + } + } + } + @Override public ItemStack getItem(NPCSlot slot) { Objects.requireNonNull(slot, "Slot cannot be null"); diff --git a/api/src/main/java/net/jitse/npclib/internal/NPCPacketHandler.java b/api/src/main/java/net/jitse/npclib/internal/NPCPacketHandler.java index de51ea7..ab64479 100644 --- a/api/src/main/java/net/jitse/npclib/internal/NPCPacketHandler.java +++ b/api/src/main/java/net/jitse/npclib/internal/NPCPacketHandler.java @@ -4,6 +4,7 @@ package net.jitse.npclib.internal; +import net.jitse.npclib.api.state.NPCAnimation; import net.jitse.npclib.api.state.NPCSlot; import org.bukkit.entity.Player; @@ -22,6 +23,8 @@ interface NPCPacketHandler { void sendEquipmentPacket(Player player, NPCSlot slot, boolean auto); + void sendAnimationPacket(Player player, NPCAnimation animation); + default void sendEquipmentPackets(Player player) { for (NPCSlot slot : NPCSlot.values()) sendEquipmentPacket(player, slot, true); diff --git a/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..90f9241 --- /dev/null +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_10_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_10_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..092a96c --- /dev/null +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_11_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_11_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..d36d9d9 --- /dev/null +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_12_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_12_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..14b09dc --- /dev/null +++ b/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_13_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_13_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..63e1bd0 --- /dev/null +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_13_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_13_R2.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..14e708f --- /dev/null +++ b/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_14_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_14_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_15_R1/src/main/java/net/jitse/npclib/nms/v1_15_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_15_R1/src/main/java/net/jitse/npclib/nms/v1_15_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..3771340 --- /dev/null +++ b/nms/v1_15_R1/src/main/java/net/jitse/npclib/nms/v1_15_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_15_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_15_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/NPC_v1_16_R1.java b/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/NPC_v1_16_R1.java index c7ee60c..667ac9a 100644 --- a/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/NPC_v1_16_R1.java +++ b/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/NPC_v1_16_R1.java @@ -5,6 +5,7 @@ import com.mojang.authlib.properties.Property; import com.mojang.datafixers.util.Pair; import net.jitse.npclib.NPCLib; import net.jitse.npclib.api.skin.Skin; +import net.jitse.npclib.api.state.NPCAnimation; import net.jitse.npclib.api.state.NPCSlot; import net.jitse.npclib.hologram.Hologram; import net.jitse.npclib.internal.MinecraftVersion; @@ -30,6 +31,7 @@ public class NPC_v1_16_R1 extends NPCBase { private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private PacketPlayOutAnimation packetPlayOutAnimation; public NPC_v1_16_R1(NPCLib instance, List lines) { super(instance, lines); @@ -109,6 +111,14 @@ public class NPC_v1_16_R1 extends NPCBase { playerConnection.sendPacket(packet); } + @Override + public void sendAnimationPacket(Player player, NPCAnimation animation) { + PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; + + PacketPlayOutAnimation packet = new PacketPlayOutAnimationWrapper().create(animation, entityId); + playerConnection.sendPacket(packet); + } + @Override public void updateSkin(Skin skin) { GameProfile newProfile = new GameProfile(uuid, name); diff --git a/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..b2c8a37 --- /dev/null +++ b/nms/v1_16_R1/src/main/java/net/jitse/npclib/nms/v1_16_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_16_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_16_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..884ce57 --- /dev/null +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,23 @@ +package net.jitse.npclib.nms.v1_8_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_8_R2.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + int id = npcAnimation.getId(); + if(id == 3) throw new IllegalArgumentException("Offhand Swing Animations are only available on 1.9 and up."); + + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, id); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..6fd6551 --- /dev/null +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,23 @@ +package net.jitse.npclib.nms.v1_8_R3.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_8_R3.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + int id = npcAnimation.getId(); + if(id == 3) throw new IllegalArgumentException("Offhand Swing Animations are only available on 1.9 and up."); + + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, id); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..aa1fa07 --- /dev/null +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_9_R1.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_9_R1.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +} diff --git a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutAnimationWrapper.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutAnimationWrapper.java new file mode 100644 index 0000000..553a20b --- /dev/null +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/packets/PacketPlayOutAnimationWrapper.java @@ -0,0 +1,20 @@ +package net.jitse.npclib.nms.v1_9_R2.packets; + +import com.comphenix.tinyprotocol.Reflection; +import net.jitse.npclib.api.state.NPCAnimation; +import net.minecraft.server.v1_9_R2.PacketPlayOutAnimation; + +public class PacketPlayOutAnimationWrapper { + + public PacketPlayOutAnimation create(NPCAnimation npcAnimation, int entityId) { + PacketPlayOutAnimation packetPlayOutAnimation = new PacketPlayOutAnimation(); + + Reflection.getField(packetPlayOutAnimation.getClass(), "a", int.class) + .set(packetPlayOutAnimation, entityId); + Reflection.getField(packetPlayOutAnimation.getClass(), "b", int.class) + .set(packetPlayOutAnimation, npcAnimation.getId()); + + return packetPlayOutAnimation; + } + +}