diff --git a/api/pom.xml b/api/pom.xml
index 45cec94..6f746de 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -8,7 +8,7 @@
npclib
net.jitse
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-api
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 4caae2b..c3db5ac 100644
--- a/api/src/main/java/net/jitse/npclib/api/NPC.java
+++ b/api/src/main/java/net/jitse/npclib/api/NPC.java
@@ -101,7 +101,7 @@ public interface NPC {
* @return Object instance.
*/
NPC toggleState(NPCState state);
-
+
/**
* Get state of NPC.
*
@@ -120,14 +120,14 @@ public interface NPC {
NPC setItem(NPCSlot slot, ItemStack item);
NPC setText(List text);
-
+
/**
* Get the text of an NPC
*
* @return List text
*/
List getText();
-
+
/**
* Get a NPC's item.
*
@@ -135,4 +135,14 @@ public interface NPC {
* @return ItemStack item.
*/
ItemStack getItem(NPCSlot slot);
+
+ /**
+ * LABYMOD ONLY
+ * Let the NPC play an emote.
+ * (https://docs.labymod.net/pages/server/emote_api/)
+ *
+ * @param receiver The player who should see the emote.
+ * @param emoteId The emote id (see link).
+ */
+ void forceLabyModEmote(Player receiver, int emoteId);
}
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 48347e7..58c50b1 100644
--- a/api/src/main/java/net/jitse/npclib/internal/NPCBase.java
+++ b/api/src/main/java/net/jitse/npclib/internal/NPCBase.java
@@ -4,6 +4,8 @@
package net.jitse.npclib.internal;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.jitse.npclib.NPCLib;
@@ -14,6 +16,7 @@ import net.jitse.npclib.api.skin.Skin;
import net.jitse.npclib.api.state.NPCSlot;
import net.jitse.npclib.api.state.NPCState;
import net.jitse.npclib.hologram.Hologram;
+import net.labymod.utilities.LMCUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
@@ -25,10 +28,7 @@ import java.util.*;
public abstract class NPCBase implements NPC, NPCPacketHandler {
- protected final UUID uuid = UUID.randomUUID();
protected final int entityId = Integer.MAX_VALUE - NPCManager.getAllNPCs().size();
- protected final String name = uuid.toString().replace("-", "").substring(0, 10);
- protected final GameProfile gameProfile = new GameProfile(uuid, name);
protected final Set hasTeamRegistered = new HashSet<>();
protected final Set activeStates = EnumSet.noneOf(NPCState.class);
@@ -36,6 +36,11 @@ public abstract class NPCBase implements NPC, NPCPacketHandler {
private final Set autoHidden = new HashSet<>();
protected double cosFOV = Math.cos(Math.toRadians(60));
+ // 12/4/20, JMB: Changed the UUID in order to enable LabyMod Emotes:
+ // This gives a format similar to: 528086a2-4f5f-2ec2-0000-000000000000
+ protected UUID uuid = new UUID(new Random().nextLong(), 0);
+ protected String name = uuid.toString().replace("-", "").substring(0, 10);
+ protected GameProfile gameProfile = new GameProfile(uuid, name);
protected NPCLib instance;
protected List text;
@@ -86,6 +91,16 @@ public abstract class NPCBase implements NPC, NPCPacketHandler {
}
}
+ @Override
+ public void forceLabyModEmote(Player receiver, int emoteId) {
+ JsonArray array = new JsonArray();
+ JsonObject forcedEmote = new JsonObject();
+ forcedEmote.addProperty("uuid", uuid.toString());
+ forcedEmote.addProperty("emote_id", emoteId);
+ array.add(forcedEmote);
+ LMCUtils.sendLMCMessage(receiver, "emote_api", array.getAsJsonObject());
+ }
+
public void disableFOV() {
this.cosFOV = 0; // Or equals Math.cos(1/2 * Math.PI).
}
diff --git a/api/src/main/java/net/labymod/utilities/LMCUtils.java b/api/src/main/java/net/labymod/utilities/LMCUtils.java
new file mode 100644
index 0000000..9320905
--- /dev/null
+++ b/api/src/main/java/net/labymod/utilities/LMCUtils.java
@@ -0,0 +1,152 @@
+package net.labymod.utilities;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.google.gson.JsonObject;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.handler.codec.DecoderException;
+import io.netty.handler.codec.EncoderException;
+import org.bukkit.entity.Player;
+
+import java.nio.charset.Charset;
+
+public class LMCUtils {
+
+ private static final Class> CRAFT_PLAYER_CLASS = Reflection.getCraftBukkitClass("CraftPlayer");
+ private static final Reflection.MethodInvoker GET_HANDLE_METHOD = Reflection.getMethod(CRAFT_PLAYER_CLASS, "getHandle");
+ private static final Class> PLAYER_CONNECTION_CLASS = Reflection.getMinecraftClass("PlayerConnection");
+ private static final Reflection.FieldAccessor PLAYER_CONNECTION_FIELD = Reflection.getField(Reflection.getMinecraftClass("EntityPlayer"),
+ "playerConnection", PLAYER_CONNECTION_CLASS);
+ private static final Reflection.MethodInvoker SEND_PACKET_METHOD = Reflection.getMethod(PLAYER_CONNECTION_CLASS,
+ "sendPacket", Reflection.getMinecraftClass("Packet"));
+ private static final Class> PACKET_DATA_SERIALIZER_CLASS = Reflection.getMinecraftClass("PacketDataSerializer");
+ private static final Reflection.ConstructorInvoker PACKET_DATA_SERIALIZER_CONSTRUCTOR = Reflection.getConstructor(
+ PACKET_DATA_SERIALIZER_CLASS, ByteBuf.class);
+ private static final Reflection.ConstructorInvoker PACKET_PLAY_OUT_CUSTOM_PAYLOAD_CONSTRUCTOR = Reflection.getConstructor(
+ Reflection.getMinecraftClass("PacketPlayOutCustomPayload"), String.class, PACKET_DATA_SERIALIZER_CLASS);
+
+ /**
+ * Send a LMC message to the minecraft client
+ *
+ * @param player Minecraft Client
+ * @param key LMC message key
+ * @param messageContent json object content
+ */
+ public static void sendLMCMessage(Player player, String key, JsonObject messageContent) {
+ byte[] bytes = LMCUtils.getBytesToSend(key, messageContent.toString());
+
+ // 12/4/20, JMB: Converted into reflections for multi-version support:
+// PacketDataSerializer pds = new PacketDataSerializer(Unpooled.wrappedBuffer(bytes));
+// PacketPlayOutCustomPayload payloadPacket = new PacketPlayOutCustomPayload("LMC", pds);
+// ((CraftPlayer) player).getHandle().playerConnection.sendPacket(payloadPacket);
+ Object pds = PACKET_DATA_SERIALIZER_CONSTRUCTOR.invoke(Unpooled.wrappedBuffer(bytes));
+ Object payloadPacket = PACKET_PLAY_OUT_CUSTOM_PAYLOAD_CONSTRUCTOR.invoke("LMC", pds);
+ SEND_PACKET_METHOD.invoke(PLAYER_CONNECTION_FIELD.get(GET_HANDLE_METHOD.invoke(CRAFT_PLAYER_CLASS.cast(player))), payloadPacket);
+ }
+
+ /**
+ * Gets the bytes that are required to send the given message
+ *
+ * @param messageKey the message's key
+ * @param messageContents the message's contents
+ * @return the byte array that should be the payload
+ */
+ public static byte[] getBytesToSend(String messageKey, String messageContents) {
+ // Getting an empty buffer
+ ByteBuf byteBuf = Unpooled.buffer();
+
+ // Writing the message-key to the buffer
+ writeString(byteBuf, messageKey);
+
+ // Writing the contents to the buffer
+ writeString(byteBuf, messageContents);
+
+ // Copying the buffer's bytes to the byte array
+ byte[] bytes = new byte[byteBuf.readableBytes()];
+ byteBuf.readBytes(bytes);
+
+ // Returning the byte array
+ return bytes;
+ }
+
+ /**
+ * Writes a varint to the given byte buffer
+ *
+ * @param buf the byte buffer the int should be written to
+ * @param input the int that should be written to the buffer
+ */
+ private static void writeVarIntToBuffer(ByteBuf buf, int input) {
+ while ((input & -128) != 0) {
+ buf.writeByte(input & 127 | 128);
+ input >>>= 7;
+ }
+
+ buf.writeByte(input);
+ }
+
+ /**
+ * Writes a string to the given byte buffer
+ *
+ * @param buf the byte buffer the string should be written to
+ * @param string the string that should be written to the buffer
+ */
+ private static void writeString(ByteBuf buf, String string) {
+ byte[] abyte = string.getBytes(Charset.forName("UTF-8"));
+
+ if (abyte.length > Short.MAX_VALUE) {
+ throw new EncoderException("String too big (was " + string.length() + " bytes encoded, max " + Short.MAX_VALUE + ")");
+ } else {
+ writeVarIntToBuffer(buf, abyte.length);
+ buf.writeBytes(abyte);
+ }
+ }
+
+ /**
+ * Reads a varint from the given byte buffer
+ *
+ * @param buf the byte buffer the varint should be read from
+ * @return the int read
+ */
+ public static int readVarIntFromBuffer(ByteBuf buf) {
+ int i = 0;
+ int j = 0;
+
+ byte b0;
+ do {
+ b0 = buf.readByte();
+ i |= (b0 & 127) << j++ * 7;
+ if (j > 5) {
+ throw new RuntimeException("VarInt too big");
+ }
+ } while ((b0 & 128) == 128);
+
+ return i;
+ }
+
+ /**
+ * Reads a string from the given byte buffer
+ *
+ * @param buf the byte buffer the string should be read from
+ * @param maxLength the string's max-length
+ * @return the string read
+ */
+ public static String readString(ByteBuf buf, int maxLength) {
+ int i = readVarIntFromBuffer(buf);
+
+ if (i > maxLength * 4) {
+ throw new DecoderException("The received encoded string buffer length is longer than maximum allowed (" + i + " > " + maxLength * 4 + ")");
+ } else if (i < 0) {
+ throw new DecoderException("The received encoded string buffer length is less than zero! Weird string!");
+ } else {
+ byte[] bytes = new byte[i];
+ buf.readBytes(bytes);
+
+ String s = new String(bytes, Charset.forName("UTF-8"));
+ if (s.length() > maxLength) {
+ throw new DecoderException("The received string length is longer than maximum allowed (" + i + " > " + maxLength + ")");
+ } else {
+ return s;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/nms/pom.xml b/nms/pom.xml
index 6009070..159bd4c 100644
--- a/nms/pom.xml
+++ b/nms/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms
diff --git a/nms/v1_10_R1/pom.xml b/nms/v1_10_R1/pom.xml
index 72f34db..9f81f64 100755
--- a/nms/v1_10_R1/pom.xml
+++ b/nms/v1_10_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_10_R1
diff --git a/nms/v1_11_R1/pom.xml b/nms/v1_11_R1/pom.xml
index 35f571d..cbdf03b 100755
--- a/nms/v1_11_R1/pom.xml
+++ b/nms/v1_11_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_11_R1
diff --git a/nms/v1_12_R1/pom.xml b/nms/v1_12_R1/pom.xml
index 4c17ae7..d0e6915 100755
--- a/nms/v1_12_R1/pom.xml
+++ b/nms/v1_12_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_12_R1
diff --git a/nms/v1_13_R1/pom.xml b/nms/v1_13_R1/pom.xml
index 5d3e4ca..9a7f215 100755
--- a/nms/v1_13_R1/pom.xml
+++ b/nms/v1_13_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_13_R1
diff --git a/nms/v1_13_R2/pom.xml b/nms/v1_13_R2/pom.xml
index 61f707d..e1f863f 100755
--- a/nms/v1_13_R2/pom.xml
+++ b/nms/v1_13_R2/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_13_R2
diff --git a/nms/v1_14_R1/pom.xml b/nms/v1_14_R1/pom.xml
index 9c2dc1f..6f4188d 100755
--- a/nms/v1_14_R1/pom.xml
+++ b/nms/v1_14_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_14_R1
diff --git a/nms/v1_15_R1/pom.xml b/nms/v1_15_R1/pom.xml
index 6fe5267..d0a1b99 100644
--- a/nms/v1_15_R1/pom.xml
+++ b/nms/v1_15_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_15_R1
diff --git a/nms/v1_8_R2/pom.xml b/nms/v1_8_R2/pom.xml
index 36f0496..2b04bbd 100755
--- a/nms/v1_8_R2/pom.xml
+++ b/nms/v1_8_R2/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_8_R2
diff --git a/nms/v1_8_R3/pom.xml b/nms/v1_8_R3/pom.xml
index d04e6a7..8ea9690 100755
--- a/nms/v1_8_R3/pom.xml
+++ b/nms/v1_8_R3/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_8_R3
diff --git a/nms/v1_9_R1/pom.xml b/nms/v1_9_R1/pom.xml
index c99a7b6..b452b25 100755
--- a/nms/v1_9_R1/pom.xml
+++ b/nms/v1_9_R1/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_9_R1
diff --git a/nms/v1_9_R2/pom.xml b/nms/v1_9_R2/pom.xml
index 590a908..6e7bdcb 100755
--- a/nms/v1_9_R2/pom.xml
+++ b/nms/v1_9_R2/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib-nms
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-nms-v1_9_R2
diff --git a/plugin/pom.xml b/plugin/pom.xml
index 5eb3040..5947c44 100644
--- a/plugin/pom.xml
+++ b/plugin/pom.xml
@@ -8,7 +8,7 @@
net.jitse
npclib
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
npclib-plugin
diff --git a/pom.xml b/pom.xml
index dbf7d46..e62072a 100755
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
net.jitse
npclib
- 2.4.2-SNAPSHOT
+ 2.5-SNAPSHOT
UTF-8