diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f2f5947..b062f23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,6 +65,7 @@ jobs: dependencies: runs-on: ubuntu-latest + if: ${{github.ref == 'refs/heads/version/1.20.1' && github.event_name != 'pull_request'}} steps: - name: checkout repository uses: actions/checkout@v4 @@ -76,7 +77,6 @@ jobs: distribution: 'temurin' - name: Build with Gradle and generate dependency Graph - if: ${{github.ref == 'refs/heads/version/1.20.1' && github.event_name != 'pull_request'}} uses: gradle/gradle-build-action@v2 with: arguments: dependencies diff --git a/Changelog.md b/Changelog.md index 3fef427..4f3e0e8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,10 @@ +# Indev +- Message Embeds to better represent Minecraft messages on Discord +- Fix `/link` Minecraft command not being registered on Forge +- Implement Markdown parsing for Discord to Minecraft message sync +- Implement automatically converting URLs to clickable links in Minecraft chat +- Replace blocked URLs before sending Minecraft chat to Discord + # 1.2.1 Allow providing token via config diff --git a/build.gradle.kts b/build.gradle.kts index 529f941..c5a74c8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -67,6 +67,7 @@ subprojects { val jdaVersion: String by project val exposedVersion: String by project val sqliteJDBCVersion: String by project + val commonmarkVersion: String by project // This array gets used at multiple places, so it's easier to // just specify all dependencies at once and re-use them. This @@ -85,7 +86,10 @@ subprojects { // Database driver that allows Exposed to communicate with // the SQLite database. This will not be in the JAR and needs to be provided // otherwise (e.g. https://www.curseforge.com/minecraft/mc-mods/sqlite-jdbc) - "org.xerial:sqlite-jdbc:$sqliteJDBCVersion" + "org.xerial:sqlite-jdbc:$sqliteJDBCVersion", + + // Markdown parser used for formatting Discord messages in Minecraft + "org.commonmark:commonmark:$commonmarkVersion", ) dependencies { diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt index 6b58514..d6921aa 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt @@ -81,6 +81,18 @@ object AstralBotConfig { */ val ENABLED_COMMANDS: ForgeConfigSpec.ConfigValue> + /** + * Enables parsing Discord messages into Minecraft's Chat Components. + * This includes making links clickable, etc. + */ + val ENABLE_MARKDOWN_PARSING: ForgeConfigSpec.BooleanValue + + /** + * Enables converting detected URLs into clickable links, requires + * [ENABLE_MARKDOWN_PARSING] to be enabled to do anything + */ + val ENABLE_AUTO_LINKS: ForgeConfigSpec.BooleanValue + init { val builder = ForgeConfigSpec.Builder() @@ -117,7 +129,9 @@ object AstralBotConfig { "https://pornhub.com", "https://xhamster.com", "https://xvideos.com", - "https://rule34.xyz" + "https://rule34.xyz", + "https://rule34.xxx", + "https://discord.gg" ) ) ) { @@ -149,6 +163,11 @@ object AstralBotConfig { return@defineList true } + ENABLE_MARKDOWN_PARSING = builder.comment("Parse Discord messages into Minecraft's Chat Components") + .define(listOf("markdown", "enabled"), true) + ENABLE_AUTO_LINKS = builder.comment("Automatically convert detected URLs into clickable links") + .define(listOf("markdown", "autoLinks"), true) + SPEC = builder.build() } @@ -163,7 +182,7 @@ object AstralBotConfig { try { val parsedURL = URL(url) for (blockedURL in URL_BLOCKLIST.get()) { - if (parsedURL.host.equals(URL(blockedURL).host)) return false + if (parsedURL.host == URL(blockedURL).host) return false } } catch (e: Exception) { LOGGER.warn("URL $url", e) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt index 6f46b95..b41b8b5 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -7,6 +7,7 @@ object AstralBotTextConfig { val GENERIC_ERROR: ForgeConfigSpec.ConfigValue val GENERIC_SUCCESS: ForgeConfigSpec.ConfigValue + val GENERIC_BLOCKED: ForgeConfigSpec.ConfigValue val FAQ_ERROR: ForgeConfigSpec.ConfigValue val FAQ_NO_REGISTERED: ForgeConfigSpec.ConfigValue @@ -17,6 +18,7 @@ object AstralBotTextConfig { val DISCORD_MESSAGE: ForgeConfigSpec.ConfigValue val DISCORD_REPLY: ForgeConfigSpec.ConfigValue + val DISCORD_EMBEDS: ForgeConfigSpec.ConfigValue val RELOAD_ERROR: ForgeConfigSpec.ConfigValue val RELOAD_SUCCESS: ForgeConfigSpec.ConfigValue @@ -41,6 +43,8 @@ object AstralBotTextConfig { .define("genericError", "Something went wrong!") GENERIC_SUCCESS = builder.comment("Generic success message sent to Discord") .define("genericSuccess", "Success!") + GENERIC_BLOCKED = builder.comment("Generic string that replaces blocked URLs/Links") + .define("genericBlocked", "[BLOCKED]") FAQ_ERROR = builder.comment("Message sent to Discord if an error ocurrs during FAQ loading") .define(mutableListOf("faq", "error"), "Bot Error (Contact Bot Operator)") @@ -76,6 +80,9 @@ object AstralBotTextConfig { The user the message is in reply to is referenced by {{replied}} """.replace(whitespaceRegex, "\n")) .define(mutableListOf("messages", "discord", "reply"), " replying to {{replied}}") + DISCORD_EMBEDS = + builder.comment("Template for the label of embeds of a message.") + .define(mutableListOf("messages", "discord", "embeds"), "Embeds:") RELOAD_ERROR = builder.comment("""Template for the error message sent to Discord when reloading fails. diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt index fdf3ab2..a317547 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -4,8 +4,10 @@ import com.mojang.authlib.GameProfile import dev.erdragh.astralbot.* import dev.erdragh.astralbot.config.AstralBotConfig import dev.erdragh.astralbot.config.AstralBotTextConfig +import dev.erdragh.astralbot.util.* import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Message +import net.dv8tion.jda.api.entities.MessageEmbed import net.dv8tion.jda.api.events.message.MessageReceivedEvent import net.dv8tion.jda.api.hooks.ListenerAdapter import net.minecraft.ChatFormatting @@ -15,6 +17,7 @@ import net.minecraft.network.chat.HoverEvent import net.minecraft.network.chat.MutableComponent import net.minecraft.server.MinecraftServer import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.item.ItemStack import java.text.DecimalFormat import java.util.* import kotlin.jvm.optionals.getOrNull @@ -27,7 +30,9 @@ import kotlin.math.min * @author Erdragh */ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() { - private val playerNames = HashSet(server.maxPlayers) + private val playerNames = HashSet(server.maxPlayers); + private val notchPlayer = byName("Notch")?.let { ServerPlayer(this.server, this.server.allLevels.elementAt(0), it) } + companion object { private val numberFormat = DecimalFormat("###.##") @@ -121,19 +126,40 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() * @param player the Player who sent the message * @param message the String contents of the message */ - fun sendChatToDiscord(player: ServerPlayer?, message: String) { + fun sendChatToDiscord(player: ServerPlayer?, message: Component) { if (shuttingDown.get()) return + + val attachments = message.toFlatList().mapNotNull { + it.style.hoverEvent + } + + val formattedEmbeds: MutableList = mutableListOf() + val items: MutableList = mutableListOf() + + for (attachment in attachments) { + attachment.getValue(HoverEvent.Action.SHOW_TEXT)?.let { + formattedEmbeds.add(formatHoverText(it)) + } + attachment.getValue(HoverEvent.Action.SHOW_ITEM)?.itemStack?.let { + formatHoverItems(it, items, notchPlayer)?.let(formattedEmbeds::add) + } + attachment.getValue(HoverEvent.Action.SHOW_ENTITY)?.let { + formatHoverEntity(it)?.let(formattedEmbeds::add) + } + } + val escape = { it: String -> it.replace("_", "\\_") } textChannel?.sendMessage( if (player != null) AstralBotTextConfig.PLAYER_MESSAGE.get() - .replace("{{message}}", escape(message)) + .replace("{{message}}", formatComponentToMarkdown(message)) .replace("{{fullName}}", escape(player.displayName.string)) .replace("{{name}}", escape(player.name.string)) - else escape(message) + else escape(message.string) ) + ?.addEmbeds(formattedEmbeds) ?.setSuppressedNotifications(true) - ?.setSuppressEmbeds(true)?.queue() + ?.queue() } /** @@ -189,7 +215,7 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() val messageContents = Component.empty() // This is the actual message content - val actualMessage = Component.literal(message.contentDisplay) + val actualMessage = formatMarkdownToComponent(message.contentDisplay) // If it's enabled in the config you can click on a message and get linked to said message // in the actual Discord client if (AstralBotConfig.CLICKABLE_MESSAGES.get()) { @@ -307,7 +333,9 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() private fun formatEmbeds(message: Message): MutableComponent { val comp = Component.empty() // Adds a newline with space if there are embeds and the message isn't empty - if (message.embeds.size + message.attachments.size + message.stickers.size > 0 && message.contentDisplay.isNotBlank()) comp.append("\n ") + if (message.embeds.size + message.attachments.size + message.stickers.size > 0 && message.contentDisplay.isNotBlank()) comp.append( + "\n ${AstralBotTextConfig.DISCORD_EMBEDS.get()} " + ) var i = 0 message.embeds.forEach { if (i++ != 0) comp.append(", ") @@ -352,14 +380,19 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() if (AstralBotConfig.CLICKABLE_EMBEDS.get()) { embedComponent.withStyle { style -> if (url != null && AstralBotConfig.CLICKABLE_EMBEDS.get()) { - style.withColor(ChatFormatting.BLUE).withUnderlined(true) + style.withColor(ChatFormatting.BLUE) + .withUnderlined(true) .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url)) + .withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.nullToEmpty(url))) } else style } } comp.append(embedComponent) } else { - comp.append(Component.literal("BLOCKED").withStyle(ChatFormatting.RED)) + comp.append( + Component.literal(AstralBotTextConfig.GENERIC_BLOCKED.get()) + .withStyle(ChatFormatting.RED, ChatFormatting.UNDERLINE) + ) } return comp } diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/util/ComponentRenderer.kt b/common/src/main/kotlin/dev/erdragh/astralbot/util/ComponentRenderer.kt new file mode 100644 index 0000000..a447712 --- /dev/null +++ b/common/src/main/kotlin/dev/erdragh/astralbot/util/ComponentRenderer.kt @@ -0,0 +1,265 @@ +package dev.erdragh.astralbot.util + +import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.ClickEvent +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.HoverEvent +import net.minecraft.network.chat.MutableComponent +import org.commonmark.node.* +import org.commonmark.renderer.NodeRenderer +import java.util.Stack + +class ComponentRenderer : AbstractVisitor(), NodeRenderer { + companion object { + private abstract class ListHolder(val parent: ListHolder?) + + private class BulletListHolder(parent: ListHolder?, list: BulletList) : ListHolder(parent) { + val marker: String = list.marker + } + + private class OrderedListHolder(parent: ListHolder?, list: OrderedList) : ListHolder(parent) { + val delimiter: String = list.markerDelimiter + var number: Int = list.markerStartNumber + } + } + + private var currentComponent: MutableComponent = Component.empty() + private val prefixes: Stack = Stack() + private var listHolder: ListHolder? = null + private var shouldAddBlock: Boolean = false + + override fun getNodeTypes(): MutableSet> { + return mutableSetOf( + Document::class.java, + Heading::class.java, + Emphasis::class.java, + Link::class.java, + Paragraph::class.java, + StrongEmphasis::class.java, + Text::class.java, + BlockQuote::class.java, + Code::class.java, + FencedCodeBlock::class.java, + IndentedCodeBlock::class.java, + BulletList::class.java, + OrderedList::class.java, + ListItem::class.java, + SoftLineBreak::class.java, + HardLineBreak::class.java, + ThematicBreak::class.java + ) + } + + private fun childIntoCurrent(component: MutableComponent, action: () -> Unit) { + val temp = currentComponent + currentComponent = component + action() + temp.append(currentComponent) + currentComponent = temp + } + + fun renderToComponent(node: Node?): MutableComponent { + this.render(node) + return currentComponent + } + + override fun render(node: Node?) { + node?.accept(this) + } + + override fun visit(document: Document?) { + visitChildren(document) + } + + override fun visit(heading: Heading?) { + if (heading == null) return + + block() + childIntoCurrent(Component.empty().withStyle(ChatFormatting.BOLD)) { + visitChildren(heading) + } + block() + } + + override fun visit(emphasis: Emphasis?) { + childIntoCurrent(Component.empty().withStyle(ChatFormatting.ITALIC)) { + super.visit(emphasis) + } + } + + override fun visit(link: Link?) { + if (link == null) return + this.formatLink(link, link.title, link.destination) + } + + override fun visit(paragraph: Paragraph?) { + visitChildren(paragraph) + block() + } + + override fun visit(strongEmphasis: StrongEmphasis?) { + childIntoCurrent(Component.empty().withStyle(ChatFormatting.BOLD)) { + super.visit(strongEmphasis) + } + } + + override fun visit(text: Text?) { + if (text == null) return + + val literal = text.literal + + if (!AstralBotConfig.ENABLE_AUTO_LINKS.get()) { + append(literal) + return + } + + val matcher = urlPattern.matcher(text.literal) + var lastEnd = 0 + for (result in matcher.results()) { + append(literal.substring(lastEnd.. ").withStyle(ChatFormatting.DARK_GRAY).withStyle { it.withItalic(false) }) + block() + childIntoCurrent(Component.empty().withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC)) { + visitChildren(blockQuote) + } + prefixes.pop() + block() + } + + override fun visit(code: Code?) { + if (code == null) return + append( + Component.literal("`${code.literal}`") + .withStyle(ChatFormatting.YELLOW) + ) + } + + override fun visit(fencedCodeBlock: FencedCodeBlock?) { + if (fencedCodeBlock == null) return + append(Component.literal(fencedCodeBlock.literal).withStyle(ChatFormatting.YELLOW)) + } + + override fun visit(indentedCodeBlock: IndentedCodeBlock?) { + if (indentedCodeBlock == null) return + append(Component.literal(indentedCodeBlock.literal).withStyle(ChatFormatting.YELLOW)) + } + + override fun visit(bulletList: BulletList?) { + if (bulletList == null) return + listHolder = BulletListHolder(listHolder, bulletList) + visitChildren(bulletList) + listHolder = listHolder!!.parent + block() + } + + override fun visit(orderedList: OrderedList?) { + if (orderedList == null) return + listHolder = OrderedListHolder(listHolder, orderedList) + visitChildren(orderedList) + listHolder = listHolder!!.parent + block() + } + + override fun visit(listItem: ListItem?) { + if (listItem == null) return + val markerIndent = listItem.markerIndent + val marker: String + + when (listHolder) { + is BulletListHolder -> { + marker = " ".repeat(markerIndent) + (listHolder!! as BulletListHolder).marker + } + is OrderedListHolder -> { + val holder = listHolder!! as OrderedListHolder + marker = " ".repeat(markerIndent) + holder.number + holder.delimiter + holder.number++ + } + else -> { + error("Unknown list holder type: $listHolder") + } + } + + block() + + val contentIndent = listItem.contentIndent + append(marker) + append(" ".repeat(contentIndent - marker.length)) + prefixes.push(Component.literal(" ".repeat(contentIndent))) + + if (listItem.firstChild != null) { + // not an empty list + visitChildren(listItem) + } + prefixes.pop() + } + + override fun visit(softLineBreak: SoftLineBreak?) { + newline() + } + + override fun visit(hardLineBreak: HardLineBreak?) { + currentComponent.append(" ") + newline() + } + + override fun visit(thematicBreak: ThematicBreak?) { + if (thematicBreak == null) return + block() + append(thematicBreak.literal) + block() + } + + private fun newline() { + currentComponent.append("\n") + for (prefix in prefixes.asIterable()) { + currentComponent.append(prefix) + } + } + + private fun formatLink(node: Node?, title: String?, destination: String) { + childIntoCurrent(Component.empty() + .withStyle(ChatFormatting.BLUE, ChatFormatting.UNDERLINE) + .withStyle { + if (AstralBotConfig.urlAllowed(destination)) { + it + .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, destination)) + .withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(destination))) + } else { + it + .withColor(ChatFormatting.RED) + .withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(AstralBotTextConfig.GENERIC_BLOCKED.get()))) + } + } + ) { + node?.let(::visitChildren) + if (title != null) { + append(title) + } + } + } + + private fun block() { + this.shouldAddBlock = true + } + + private fun append(component: Component) { + if (this.shouldAddBlock) { + this.shouldAddBlock = false + newline() + } + this.currentComponent.append(component) + } + + private fun append(literal: String) { + append(Component.literal(literal)) + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/util/MessageFormatting.kt b/common/src/main/kotlin/dev/erdragh/astralbot/util/MessageFormatting.kt new file mode 100644 index 0000000..e528f92 --- /dev/null +++ b/common/src/main/kotlin/dev/erdragh/astralbot/util/MessageFormatting.kt @@ -0,0 +1,112 @@ +package dev.erdragh.astralbot.util + +import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig +import net.dv8tion.jda.api.EmbedBuilder +import net.dv8tion.jda.api.entities.MessageEmbed +import net.minecraft.network.chat.ClickEvent +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.HoverEvent +import net.minecraft.network.chat.MutableComponent +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.TooltipFlag +import org.commonmark.parser.Parser +import java.awt.Color +import java.util.regex.Pattern + +// Pattern for recognizing a URL, based off RFC 3986 +// Source: https://stackoverflow.com/questions/5713558/detect-and-extract-url-from-a-string +val urlPattern: Pattern = Pattern.compile( + "(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)" + + "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*" + + "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)", + Pattern.CASE_INSENSITIVE or Pattern.MULTILINE or Pattern.DOTALL +) + +fun formatMarkdownToComponent(md: String): MutableComponent { + if (!AstralBotConfig.ENABLE_MARKDOWN_PARSING.get()) return Component.literal(md) + + val parser = Parser.builder().build() + val parsed = parser.parse(md) + val renderer = ComponentRenderer() + + return renderer.renderToComponent(parsed) +} + +fun formatComponentToMarkdown(comp: Component): String { + return comp.toFlatList() + .map { + var formatted = it.string + + if (it.style.isBold) { + formatted = "**$formatted**" + } + if (it.style.isItalic) { + formatted = "_${formatted}_" + } + it.style.clickEvent?.let { clickEvent -> + if (clickEvent.action == ClickEvent.Action.OPEN_URL) { + formatted = "[$formatted](${clickEvent.value})" + } + } + + val matcher = urlPattern.matcher(formatted) + val replaced = matcher.replaceAll { match -> + val group = match.group() + return@replaceAll if (AstralBotConfig.urlAllowed(group)) { + group + } else { + AstralBotTextConfig.GENERIC_BLOCKED.get() + } + } + formatted = replaced + + return@map formatted + } + .joinToString("") +} + +fun formatHoverText(text: Component): MessageEmbed { + return EmbedBuilder() + .setDescription(text.string) + .let { builder: EmbedBuilder -> + text.style.color?.value?.let { color -> builder.setColor(color) } + builder + } + .build() +} + +fun formatHoverItems(stack: ItemStack, knownItems: MutableList, player: Player?): MessageEmbed? { + if (knownItems.contains(stack)) return null + knownItems.add(stack) + val tooltip = stack.getTooltipLines(player, TooltipFlag.NORMAL).map(::formatComponentToMarkdown) + return EmbedBuilder() + .setTitle("${tooltip[0]} ${if (stack.count > 1) "(${stack.count})" else ""}") + .setDescription(tooltip.drop(1).let { + if (stack.hasCustomHoverName()) { + listOf(stack.item.description.string).plus(it) + } else it + }.joinToString("\n")) + .let { builder: EmbedBuilder -> + stack.rarity.color.color?.let { color -> builder.setColor(color) } + builder + } + .build() +} + +fun formatHoverEntity(entity: HoverEvent.EntityTooltipInfo): MessageEmbed? { + if (entity.type == EntityType.PLAYER) return null + return EmbedBuilder() + .setTitle(entity.name?.string) + .setDescription(entity.type.description.string) + .let { builder: EmbedBuilder -> + val mobCategory = entity.type.category + if (mobCategory.isFriendly) { + builder.setColor(Color.GREEN) + } + builder + } + .build() +} \ No newline at end of file diff --git a/common/src/main/kotlin/module-info.java b/common/src/main/kotlin/module-info.java index d9bf252..cc50849 100644 --- a/common/src/main/kotlin/module-info.java +++ b/common/src/main/kotlin/module-info.java @@ -14,6 +14,8 @@ // For Discord Interaction requires net.dv8tion.jda; + // For message parsing + requires org.commonmark; // For Minecraft itself requires authlib; diff --git a/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt b/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt index 203ae0e..59d97b9 100644 --- a/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt +++ b/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt @@ -29,11 +29,11 @@ object BotMod : ModInitializer { } ServerMessageEvents.CHAT_MESSAGE.register { message, player, _ -> - minecraftHandler?.sendChatToDiscord(player, message.signedContent()) + minecraftHandler?.sendChatToDiscord(player, message.decoratedContent()) } ServerMessageEvents.GAME_MESSAGE.register { _, message, _ -> if (message !is DiscordMessageComponent) { - minecraftHandler?.sendChatToDiscord(null as ServerPlayer?, message.string) + minecraftHandler?.sendChatToDiscord(null as ServerPlayer?, message) } } diff --git a/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt b/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt index 40d145a..955f367 100644 --- a/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt +++ b/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt @@ -29,6 +29,7 @@ object BotMod { FORGE_BUS.addListener(::onServerStop) FORGE_BUS.addListener(::onChatMessage) FORGE_BUS.addListener(::onSystemMessage) + FORGE_BUS.addListener(::onCommandRegistration) FORGE_BUS.addListener(::onPlayerJoin) FORGE_BUS.addListener(::onPlayerLeave) @@ -44,12 +45,12 @@ object BotMod { } private fun onChatMessage(event: ServerChatEvent) { - minecraftHandler?.sendChatToDiscord(event.player, event.message.string) + minecraftHandler?.sendChatToDiscord(event.player, event.message) } private fun onSystemMessage(event: SystemMessageEvent) { if (event.message !is DiscordMessageComponent) { - minecraftHandler?.sendChatToDiscord(null as ServerPlayer?, event.message.string) + minecraftHandler?.sendChatToDiscord(null as ServerPlayer?, event.message) } } diff --git a/gradle.properties b/gradle.properties index fdc1733..88c92ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,8 +15,11 @@ parchmentVersion=2023.09.03 forgeConfigAPIVersion=8.0.0 # Discord Interactions -jdaVersion=5.0.0-beta.22 +jdaVersion=5.0.0-beta.23 # Database Interactions exposedVersion=0.49.0 -sqliteJDBCVersion=3.44.1.0 \ No newline at end of file +sqliteJDBCVersion=3.44.1.0 + +# Message parsing +commonmarkVersion=0.22.0 \ No newline at end of file