diff --git a/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/BufferUtil.java b/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/BufferUtil.java index 23c4128..fe856d4 100644 --- a/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/BufferUtil.java +++ b/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/BufferUtil.java @@ -25,8 +25,8 @@ package com.github.juliarn.npclib.ext.labymod; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.UUID; import org.jetbrains.annotations.NotNull; final class BufferUtil { @@ -62,23 +62,13 @@ private BufferUtil() { } } - public static @NotNull ByteBuffer putString(@NotNull ByteBuffer buffer, @NotNull String string) { - // get the bytes of the buffer to write - byte[] bytes = string.getBytes(StandardCharsets.UTF_8); - - // write the content - ByteBuffer writeBuffer = putVarInt(buffer, bytes.length); - writeBuffer = putBytes(writeBuffer, bytes); - + public static @NotNull ByteBuffer putUUID(@NotNull ByteBuffer buffer, @NotNull UUID uuid) { + ByteBuffer writeBuffer = ensureWriteable(buffer, Long.BYTES * 2); + writeBuffer.putLong(uuid.getMostSignificantBits()); + writeBuffer.putLong(uuid.getLeastSignificantBits()); return writeBuffer; } - public static @NotNull ByteBuffer putBytes(@NotNull ByteBuffer buffer, byte[] bytes) { - // ensure that the target buffer has enough space to fit the bytes and write them - ByteBuffer writeBuffer = ensureWriteable(buffer, bytes.length); - return writeBuffer.put(bytes); - } - public static @NotNull ByteBuffer putVarInt(@NotNull ByteBuffer buffer, int value) { // ensure that the target buffer has enough space to fit the var int int varIntBytes = VAR_INT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(value)]; diff --git a/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/LabyModExtension.java b/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/LabyModExtension.java index 2cb588b..143e9e9 100644 --- a/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/LabyModExtension.java +++ b/ext/labymod/src/main/java/com/github/juliarn/npclib/ext/labymod/LabyModExtension.java @@ -26,77 +26,65 @@ import com.github.juliarn.npclib.api.protocol.OutboundPacket; import com.github.juliarn.npclib.api.protocol.PlatformPacketAdapter; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import java.nio.ByteBuffer; -import java.util.UUID; +import java.util.function.UnaryOperator; import org.jetbrains.annotations.NotNull; public final class LabyModExtension { - private static final String EMOTE_ID_PROPERTY = "emote_id"; - private static final String STICKER_ID_PROPERTY = "sticker_id"; + // full list of packet ids can be found here: + // https://github.com/LabyMod/labymod4-server-api/blob/master/core/src/main/java/net/labymod/serverapi/core/LabyModProtocol.java + private static final int EMOTE_PACKET_ID = 16; + private static final int SPRAY_PACKET_ID = 17; + private static final String LM_PLUGIN_CHANNEL = "labymod:neo"; - private static final String EMOTE_API_MESSAGE_KEY = "emote_api"; - private static final String STICKER_API_MESSAGE_KEY = "sticker_api"; - - private static final String LM_PLUGIN_CHANNEL = "labymod3:main"; - - private static final int DEFAULT_BUFFER_ALLOCATION_BYTES = 128; + // a sensitive default for users that only send out a single sticker or emote via one packet + private static final int DEFAULT_BUFFER_ALLOCATION_BYTES = 32; private LabyModExtension() { throw new UnsupportedOperationException(); } + // list of emote ids can be found here: + // https://dev.labymod.net/pages/server/labymod/features/emotes public static @NotNull OutboundPacket createEmotePacket( @NotNull PlatformPacketAdapter packetAdapter, int... emoteIds ) { return (player, npc) -> { - // construct the data we need to write - JsonArray data = createIdJsonData(EMOTE_ID_PROPERTY, npc.profile().uniqueId(), emoteIds); - byte[] payloadData = constructPayloadData(EMOTE_API_MESSAGE_KEY, data.toString()); + byte[] payloadData = constructPayloadData(EMOTE_PACKET_ID, buffer -> { + // put the amount of emotes to send into the buffer & write each emote into the buffer + // an emote is also prefixed with the npc uuid which is always the target npc id in our case + ByteBuffer target = BufferUtil.putVarInt(buffer, emoteIds.length); + for (int emoteId : emoteIds) { + target = BufferUtil.putUUID(target, npc.profile().uniqueId()); + target = BufferUtil.putVarInt(target, emoteId); + } + return target; + }); // create a new plugin message outbound packet and schedule the payload data packetAdapter.createCustomPayloadPacket(LM_PLUGIN_CHANNEL, payloadData).schedule(player, npc); }; } + // currently not supported by the LM api public static @NotNull OutboundPacket createStickerPacket( @NotNull PlatformPacketAdapter packetAdapter, int... stickerIds ) { return (player, npc) -> { - // construct the data we need to write - JsonArray data = createIdJsonData(STICKER_ID_PROPERTY, npc.profile().uniqueId(), stickerIds); - byte[] payloadData = constructPayloadData(STICKER_API_MESSAGE_KEY, data.toString()); - - // create a new plugin message outbound packet and schedule the payload data - packetAdapter.createCustomPayloadPacket(LM_PLUGIN_CHANNEL, payloadData).schedule(player, npc); }; } - private static byte[] constructPayloadData(@NotNull String apiMessageKey, @NotNull String data) { + private static byte[] constructPayloadData(int packetId, @NotNull UnaryOperator packetWriter) { ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_BUFFER_ALLOCATION_BYTES); // put the message key, then the data - buffer = BufferUtil.putString(buffer, apiMessageKey); - buffer = BufferUtil.putString(buffer, data); + buffer = BufferUtil.putVarInt(buffer, packetId); + buffer = packetWriter.apply(buffer); // get the buffer content return BufferUtil.extractData(buffer); } - - private static @NotNull JsonArray createIdJsonData(@NotNull String idProperty, @NotNull UUID npcId, int... ids) { - // put the id api data - JsonArray array = new JsonArray(); - for (int id : ids) { - JsonObject object = new JsonObject(); - object.addProperty(idProperty, id); - object.addProperty("uuid", npcId.toString()); - array.add(object); - } - - return array; - } }