diff --git a/build-number.txt b/build-number.txt index b1882ce3..a9958891 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -1720 \ No newline at end of file +1741 \ No newline at end of file diff --git a/src/main/java/me/chayapak1/chomens_bot/Bot.java b/src/main/java/me/chayapak1/chomens_bot/Bot.java index 227e4082..01cdc89c 100644 --- a/src/main/java/me/chayapak1/chomens_bot/Bot.java +++ b/src/main/java/me/chayapak1/chomens_bot/Bot.java @@ -79,6 +79,7 @@ public class Bot extends SessionAdapter { public ServerPluginsManagerPlugin serverPluginsManager; public SelfCarePlugin selfCare; public QueryPlugin query; + public ExtrasMessengerPlugin extrasMessenger; public CorePlugin core; public TeamPlugin team; public PlayersPlugin players; @@ -130,6 +131,7 @@ public class Bot extends SessionAdapter { this.serverPluginsManager = new ServerPluginsManagerPlugin(this); this.selfCare = new SelfCarePlugin(this); this.query = new QueryPlugin(this); + this.extrasMessenger = new ExtrasMessengerPlugin(this); this.core = new CorePlugin(this); this.team = new TeamPlugin(this); this.players = new PlayersPlugin(this); diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java new file mode 100644 index 00000000..85fd82da --- /dev/null +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java @@ -0,0 +1,145 @@ +package me.chayapak1.chomens_bot.plugins; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import me.chayapak1.chomens_bot.Bot; +import net.kyori.adventure.key.Key; +import org.geysermc.mcprotocollib.network.Session; +import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundCustomPayloadPacket; +import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ExtrasMessengerPlugin extends Bot.Listener { + private static final Key EXTRAS_REGISTER_KEY = Key.key("extras", "register"); + private static final Key EXTRAS_UNREGISTER_KEY = Key.key("extras", "unregister"); + private static final Key EXTRAS_MESSAGE_KEY = Key.key("extras", "message"); + + private final List listeners = new ArrayList<>(); + + private final Bot bot; + + private final String chomens_namespace; + + public ExtrasMessengerPlugin (Bot bot) { + this.bot = bot; + this.chomens_namespace = bot.config.namespace + "_"; // Ex. chomens_bot_ (then it will be appended by channel) + + bot.addListener(this); + } + + @Override + public void connected (ConnectedEvent event) { + // TODO: don't register these things on connected but on the + // custom payload packet instead so it only registers + // for servers that support this + final List channels = new ArrayList<>(); + + channels.add(EXTRAS_REGISTER_KEY.asString()); + channels.add(EXTRAS_UNREGISTER_KEY.asString()); + channels.add(EXTRAS_MESSAGE_KEY.asString()); + + bot.session.send( + new ServerboundCustomPayloadPacket( + Key.key("minecraft", "register"), + String.join("\u0000", channels).getBytes(StandardCharsets.UTF_8) + ) + ); + } + + @Override + public void packetReceived (Session session, Packet packet) { + if (packet instanceof ClientboundCustomPayloadPacket t_packet) packetReceived(t_packet); + } + + public void packetReceived (ClientboundCustomPayloadPacket packet) { + final Key packetChannel = packet.getChannel(); + + if (!packetChannel.equals(EXTRAS_MESSAGE_KEY)) return; + + final ByteBuf buf = Unpooled.wrappedBuffer(packet.getData()); + + final String channelName = readString(buf); + + if (!channelName.startsWith(chomens_namespace)) return; + + final UUID uuid = readUUID(buf); + + final byte[] data = readByteArrayToEnd(buf); + + for (Listener listener : listeners) listener.onMessage(uuid, data); + } + + public void sendPayload (String name, byte[] data) { + final ByteBuf buf = Unpooled.buffer(); + + writeString(buf, chomens_namespace + name); + buf.writeBytes(data); + + final byte[] byteArray = readByteArrayToEnd(buf); + + bot.session.send( + new ServerboundCustomPayloadPacket( + EXTRAS_MESSAGE_KEY, + byteArray + ) + ); + } + + // TODO: automatically register the already registered channels on reconnect + public void registerChannel (String channel) { + final ByteBuf buf = Unpooled.buffer(); + + writeString(buf, chomens_namespace + channel); + + bot.session.send( + new ServerboundCustomPayloadPacket( + EXTRAS_REGISTER_KEY, + readByteArrayToEnd(buf) + ) + ); + } + + private void writeString (ByteBuf input, String string) { + final byte[] bytesString = string.getBytes(StandardCharsets.US_ASCII); + + input.writeByte(bytesString.length); + input.writeBytes(bytesString); + } + + private String readString (ByteBuf input) { + final int length = input.readUnsignedByte(); + + final byte[] buf = new byte[length]; + + input.readBytes(buf); + + return new String(buf, StandardCharsets.US_ASCII); + } + + private UUID readUUID (ByteBuf input) { + final long mostSignificant = input.readLong(); + final long leastSignificant = input.readLong(); + + return new UUID(mostSignificant, leastSignificant); + } + + private byte[] readByteArrayToEnd (ByteBuf input) { + final byte[] bytes = new byte[input.readableBytes()]; + + input.readBytes(bytes); + + return bytes; + } + + public void addListener (Listener listener) { listeners.add(listener); } + + public static class Listener { + public void onMessage (UUID sender, byte[] message) {} + } +}