From c010555081f3993d4805bbdc2a0c2a4a52dc45eb Mon Sep 17 00:00:00 2001 From: jonathan <7577851+axieum@users.noreply.github.com> Date: Thu, 11 Aug 2022 23:42:02 +1000 Subject: [PATCH 1/3] feat(api): add `String` formatting to string templates e.g. `${long_message:%.30s}` to truncate a string to 30 chars --- .../axieum/mcmod/minecord/api/util/StringTemplate.java | 5 ++++- .../mcmod/minecord/api/util/StringTemplateTests.java | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/minecord-api/src/main/java/me/axieum/mcmod/minecord/api/util/StringTemplate.java b/minecord-api/src/main/java/me/axieum/mcmod/minecord/api/util/StringTemplate.java index 11e4322..f87ced5 100644 --- a/minecord-api/src/main/java/me/axieum/mcmod/minecord/api/util/StringTemplate.java +++ b/minecord-api/src/main/java/me/axieum/mcmod/minecord/api/util/StringTemplate.java @@ -243,8 +243,11 @@ public String format(final @Nullable String template) try { // If a format was specified, use it against its class type if (format != null && !format.isBlank()) { + // String + if (value instanceof String) { + matcher.appendReplacement(builder, String.format(format, value)); // Number - if (value instanceof Number) { + } else if (value instanceof Number) { matcher.appendReplacement(builder, new DecimalFormat(format).format(value)); // Date & Time } else if (value instanceof Temporal) { diff --git a/minecord-api/src/test/java/me/axieum/mcmod/minecord/api/util/StringTemplateTests.java b/minecord-api/src/test/java/me/axieum/mcmod/minecord/api/util/StringTemplateTests.java index 52a569e..db950a6 100644 --- a/minecord-api/src/test/java/me/axieum/mcmod/minecord/api/util/StringTemplateTests.java +++ b/minecord-api/src/test/java/me/axieum/mcmod/minecord/api/util/StringTemplateTests.java @@ -59,6 +59,15 @@ public void erroneousLazyVariables() }, "Exceptions raised when evaluating lazy variables should be caught"); } + @Test + @DisplayName("Format strings") + public void formatStrings() + { + st.add("lorem", "Lorem ipsum dolor sit amet, consectetur."); + assertEquals("Lorem ipsum dolor sit amet...", st.format("${lorem:%.26s}...")); + assertEquals("Lorem ipsum dolor sit amet, consectetur.", st.format("${lorem:%.255s}")); + } + @Test @DisplayName("Format decimals") public void formatDecimals() From 1db5afe5ac5469e6406d44c9bb8262727991bfe9 Mon Sep 17 00:00:00 2001 From: jonathan <7577851+axieum@users.noreply.github.com> Date: Thu, 11 Aug 2022 23:44:04 +1000 Subject: [PATCH 2/3] feat(chat): add Discord reply messages (closes #50) --- .../api/chat/event/ChatPlaceholderEvents.java | 22 +++++++++++ .../discord/MessageReceivedListener.java | 37 ++++++++++++++++--- .../minecord/impl/chat/config/ChatConfig.java | 5 +++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/api/chat/event/ChatPlaceholderEvents.java b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/api/chat/event/ChatPlaceholderEvents.java index 47c0293..22ab990 100644 --- a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/api/chat/event/ChatPlaceholderEvents.java +++ b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/api/chat/event/ChatPlaceholderEvents.java @@ -50,6 +50,16 @@ public static final class Discord } }); + /** + * Called when a user sent a message in reply to another. + */ + public static final Event REPLY_RECEIVED = + EventFactory.createArrayBacked(ReplyReceived.class, callbacks -> (st, event) -> { + for (ReplyReceived callback : callbacks) { + callback.onReplyReceivedPlaceholder(st, event); + } + }); + /** * Called when a user edited their recently sent message. */ @@ -92,6 +102,18 @@ public interface MessageReceived void onMessageReceivedPlaceholder(StringTemplate template, MessageReceivedEvent event); } + @FunctionalInterface + public interface ReplyReceived + { + /** + * Called when a user sent a message in reply to another. + * + * @param template mutable string template + * @param event JDA message received event instance + */ + void onReplyReceivedPlaceholder(StringTemplate template, MessageReceivedEvent event); + } + @FunctionalInterface public interface MessageUpdated { diff --git a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReceivedListener.java b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReceivedListener.java index 7afeadc..fcc2017 100644 --- a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReceivedListener.java +++ b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReceivedListener.java @@ -3,6 +3,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.Nullable; import me.axieum.mcmod.minecord.api.chat.event.ChatPlaceholderEvents; import me.axieum.mcmod.minecord.api.util.StringTemplate; @@ -32,6 +33,7 @@ public void onMessageReceived(MessageReceivedEvent event) public void onText(MessageReceivedEvent event) { final long channelId = event.getChannel().getIdLong(); + final @Nullable Message replyMessage = event.getMessage().getReferencedMessage(); /* * Prepare a message template. @@ -53,16 +55,41 @@ public void onText(MessageReceivedEvent event) // The raw message contents st.add("raw", event.getMessage().getContentRaw()); - ChatPlaceholderEvents.Discord.MESSAGE_RECEIVED.invoker().onMessageReceivedPlaceholder(st, event); + // The message is in reply to another + if (replyMessage != null) { + // The replied message author's tag (i.e. username#discriminator), e.g. Axieum#1001 + st.add("reply_tag", replyMessage.getAuthor().getAsTag()); + // The replied message author's username, e.g. Axieum + st.add("reply_username", replyMessage.getAuthor().getName()); + // The replied message author's username discriminator, e.g. 1001 + st.add("reply_discriminator", replyMessage.getAuthor().getDiscriminator()); + // The replied message author's nickname or username + st.add("reply_author", replyMessage.getMember() != null ? replyMessage.getMember().getEffectiveName() + : replyMessage.getAuthor().getName()); + // The replied message formatted message contents + st.add("reply_message", StringUtils.discordToMinecraft(replyMessage.getContentDisplay())); + // The replied message raw message contents + st.add("reply_raw", replyMessage.getContentRaw()); + } /* * Dispatch the message. */ - MinecraftDispatcher.json(entry -> st.format(entry.minecraft.chat), - entry -> entry.minecraft.chat != null && entry.id == channelId); - - LOGGER.info(st.format("@${tag} > ${raw}")); + // The message is a standalone message + if (replyMessage == null) { + ChatPlaceholderEvents.Discord.MESSAGE_RECEIVED.invoker().onMessageReceivedPlaceholder(st, event); + MinecraftDispatcher.json(entry -> st.format(entry.minecraft.chat), + entry -> entry.minecraft.chat != null && entry.id == channelId); + LOGGER.info(st.format("@${tag} > ${raw}")); + + // The message is in reply to another + } else { + ChatPlaceholderEvents.Discord.REPLY_RECEIVED.invoker().onReplyReceivedPlaceholder(st, event); + MinecraftDispatcher.json(entry -> st.format(entry.minecraft.reply), + entry -> entry.minecraft.reply != null && entry.id == channelId); + LOGGER.info(st.format("@${tag} (in reply to @${reply_tag}) > ${raw}")); + } } public void onAttachment(MessageReceivedEvent event, Message.Attachment attachment) diff --git a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java index 0a24558..9b27d5d 100644 --- a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java +++ b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java @@ -137,6 +137,11 @@ public static class MinecraftSchema Usages: ${author}, ${tag}, ${username}, ${discriminator} and ${message}""") public String chat = "[\"\",{\"text\":\"${author}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"\",{\"text\":\"Sent from Discord\",\"italic\":true}]}},{\"text\":\" > \",\"color\":\"dark_gray\"},{\"text\":\"${message}\"}]"; + @Comment(""" + A user sent a message in reply to another + Usages: ${author}, ${tag}, ${username}, ${discriminator}, ${message}, ${reply_author}, ${reply_tag}, ${reply_username}, ${reply_discriminator} and ${reply_message}""") + public String reply = "[\"\",{\"text\":\"${author}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[{\"text\":\"Sent from Discord\",\"italic\":true}]}},\" \",{\"text\":\"(in reply to ${reply_author})\",\"color\":\"#99dcff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${reply_tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"${reply_message:%.50s}...\"]}},{\"text\":\" > \",\"color\":\"dark_gray\"},\"${message}\"]"; + @Comment(""" A user edited their recently sent message Usages: ${author}, ${tag}, ${username}, ${discriminator}, ${diff}, ${original} and ${message}""") From e8bcaeb6af8daa1b0937e3e857edb9b1038628a1 Mon Sep 17 00:00:00 2001 From: jonathan <7577851+axieum@users.noreply.github.com> Date: Thu, 11 Aug 2022 23:44:44 +1000 Subject: [PATCH 3/3] fix(chat): correct Discord message placeholders in config --- .../chat/callback/discord/MessageReactionListener.java | 10 +++++----- .../mcmod/minecord/impl/chat/config/ChatConfig.java | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReactionListener.java b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReactionListener.java index 54056fb..5c2b479 100644 --- a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReactionListener.java +++ b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/callback/discord/MessageReactionListener.java @@ -36,17 +36,14 @@ public void onGenericMessageReaction(GenericMessageReactionEvent event) final StringTemplate st = new StringTemplate(); - // The issuer's nickname or username - st.add("issuer", event.getMember() != null ? event.getMember().getEffectiveName() - : event.getUser().getName()); // The issuer's tag (i.e. username#discriminator), e.g. Axieum#1001 st.add("issuer_tag", event.getUser().getAsTag()); // The issuer's username, e.g. Axieum st.add("issuer_username", event.getUser().getName()); // The issuer's username discriminator, e.g. 1001 st.add("issuer_discriminator", event.getUser().getDiscriminator()); - // The author's nickname or username - st.add("author", event.getMember() != null ? event.getMember().getEffectiveName() + // The issuer's nickname or username + st.add("issuer", event.getMember() != null ? event.getMember().getEffectiveName() : event.getUser().getName()); // The author's tag (i.e. username#discriminator), e.g. Axieum#1001 st.add("author_tag", event.getUser().getAsTag()); @@ -54,6 +51,9 @@ public void onGenericMessageReaction(GenericMessageReactionEvent event) st.add("author_username", event.getUser().getName()); // The author's username discriminator, e.g. 1001 st.add("author_discriminator", event.getUser().getDiscriminator()); + // The author's nickname or username + st.add("author", event.getMember() != null ? event.getMember().getEffectiveName() + : event.getUser().getName()); // The emote used to react st.add("emote", emote); diff --git a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java index 9b27d5d..6be1117 100644 --- a/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java +++ b/minecord-chat/src/main/java/me/axieum/mcmod/minecord/impl/chat/config/ChatConfig.java @@ -134,7 +134,7 @@ public static class MinecraftSchema { @Comment(""" A user sent a message - Usages: ${author}, ${tag}, ${username}, ${discriminator} and ${message}""") + Usages: ${author}, ${tag}, ${username}, ${discriminator}, ${message} and ${raw}""") public String chat = "[\"\",{\"text\":\"${author}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"\",{\"text\":\"Sent from Discord\",\"italic\":true}]}},{\"text\":\" > \",\"color\":\"dark_gray\"},{\"text\":\"${message}\"}]"; @Comment(""" @@ -144,17 +144,17 @@ public static class MinecraftSchema @Comment(""" A user edited their recently sent message - Usages: ${author}, ${tag}, ${username}, ${discriminator}, ${diff}, ${original} and ${message}""") + Usages: ${author}, ${tag}, ${username}, ${discriminator}, ${diff}, ${message}, ${raw}, ${original} and ${original_raw}""") public String edit = "[\"\",{\"text\":\"${author}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"\",{\"text\":\"Sent from Discord\",\"italic\":true}]}},{\"text\":\" > \",\"color\":\"dark_gray\"},{\"text\":\"${diff}\"}]"; @Comment(""" A user reacted to a recent message - Usages: ${reactor}, ${reactor_tag}, ${reactor_username}, ${reactor_discriminator}, ${author}, ${author_tag}, ${author_username}, ${author_discriminator} and ${emote}""") + Usages: ${issuer}, ${issuer_tag}, ${issuer_username}, ${issuer_discriminator}, ${author}, ${author_tag}, ${author_username}, ${author_discriminator} and ${emote}""") public String react = "[\"\",{\"text\":\"${issuer}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${issuer_tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"\",{\"text\":\"Sent from Discord\",\"italic\":true}]}},{\"text\":\" reacted with \"},{\"text\":\"${emote}\",\"color\":\"green\"},{\"text\": \" to \"},{\"text\":\"${author}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${author_tag} \"}},{\"text\":\"'s message\"}]"; @Comment(""" A user removed their reaction from a recent message - Usages: ${reactor}, ${reactor_tag}, ${reactor_username}, ${reactor_discriminator}, ${author}, ${author_tag}, ${author_username}, ${author_discriminator} and ${emote}""") + Usages: ${issuer}, ${issuer_tag}, ${issuer_username}, ${issuer_discriminator}, ${author}, ${author_tag}, ${author_username}, ${author_discriminator} and ${emote}""") public String unreact = "[\"\",{\"text\":\"${issuer}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${issuer_tag} \"},\"hoverEvent\":{\"action\":\"show_text\",\"contents\":[\"\",{\"text\":\"Sent from Discord\",\"italic\":true}]}},{\"text\":\" removed their reaction of \"},{\"text\":\"${emote}\",\"color\":\"red\"},{\"text\": \" from \"},{\"text\":\"${author}\",\"color\":\"#00aaff\",\"clickEvent\":{\"action\":\"suggest_command\",\"value\":\"@${author_tag} \"}},{\"text\":\"'s message\"}]"; @Comment("""