Skip to content

Commit

Permalink
Merge branch 'refs/heads/version/1.20.1' into version/1.18.2
Browse files Browse the repository at this point in the history
# Conflicts:
#	common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt
#	fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt
#	forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt
  • Loading branch information
Erdragh committed Apr 27, 2024
2 parents 097b46b + b28e37f commit 437d576
Show file tree
Hide file tree
Showing 12 changed files with 484 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 1.3.0
- 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

Expand Down
18 changes: 15 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import java.nio.charset.StandardCharsets
plugins {
// This is an Architectury repository, as such the relevant plugins are needed
id("architectury-plugin") version "3.4-SNAPSHOT"
id("dev.architectury.loom") version "1.4-SNAPSHOT" apply false
id("dev.architectury.loom") version "1.5-SNAPSHOT" apply false
// The shadow plugin is used in both Architectury and when including JDA and Exposed
id("com.github.johnrengelman.shadow") version "8.1.1" apply false
// Since this mod/bot is written in Kotlin and expected to run on Minecraft and as such
// the JVM, the Kotlin plugin is needed
kotlin("jvm") version "1.9.22"
kotlin("jvm") version "1.9.23"
// For generating documentation based on comments in the code
id("org.jetbrains.dokka") version "1.9.10"
java
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -229,4 +233,12 @@ tasks.register<Task>("prepareChangelog") {
var changelog = file.readText(StandardCharsets.UTF_8)
changelog = changelog.replace(Regex("[^^](#(#|\\n|.)+)|(^#.+)"), "")
println(changelog.trim())
}

// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
idea {
module {
isDownloadSources = true
isDownloadJavadoc = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ object AstralBotConfig {
*/
val ENABLED_COMMANDS: ForgeConfigSpec.ConfigValue<List<String>>

/**
* 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()

Expand Down Expand Up @@ -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"
)
)
) {
Expand Down Expand Up @@ -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()
}

Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ object AstralBotTextConfig {

val GENERIC_ERROR: ForgeConfigSpec.ConfigValue<String>
val GENERIC_SUCCESS: ForgeConfigSpec.ConfigValue<String>
val GENERIC_BLOCKED: ForgeConfigSpec.ConfigValue<String>

val FAQ_ERROR: ForgeConfigSpec.ConfigValue<String>
val FAQ_NO_REGISTERED: ForgeConfigSpec.ConfigValue<String>
Expand All @@ -17,6 +18,7 @@ object AstralBotTextConfig {

val DISCORD_MESSAGE: ForgeConfigSpec.ConfigValue<String>
val DISCORD_REPLY: ForgeConfigSpec.ConfigValue<String>
val DISCORD_EMBEDS: ForgeConfigSpec.ConfigValue<String>

val RELOAD_ERROR: ForgeConfigSpec.ConfigValue<String>
val RELOAD_SUCCESS: ForgeConfigSpec.ConfigValue<String>
Expand All @@ -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)")
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ 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
import net.minecraft.Util
import net.minecraft.network.chat.*
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
Expand All @@ -25,7 +28,9 @@ import kotlin.math.min
* @author Erdragh
*/
class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() {
private val playerNames = HashSet<String>(server.maxPlayers)
private val playerNames = HashSet<String>(server.maxPlayers);
private val notchPlayer = byName("Notch")?.let { ServerPlayer(this.server, this.server.allLevels.elementAt(0), it) }


companion object {
private val numberFormat = DecimalFormat("###.##")
Expand Down Expand Up @@ -119,19 +124,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<MessageEmbed> = mutableListOf()
val items: MutableList<ItemStack> = 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()
}

/**
Expand Down Expand Up @@ -187,7 +213,7 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter()

val messageContents = TextComponent("")
// This is the actual message content
val actualMessage = TextComponent(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()) {
Expand Down Expand Up @@ -305,7 +331,9 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter()
private fun formatEmbeds(message: Message): MutableComponent {
val comp = TextComponent("")
// 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(", ")
Expand Down Expand Up @@ -350,14 +378,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(TextComponent("BLOCKED").withStyle(ChatFormatting.RED))
comp.append(
TextComponent(AstralBotTextConfig.GENERIC_BLOCKED.get())
.withStyle(ChatFormatting.RED, ChatFormatting.UNDERLINE)
)
}
return comp
}
Expand Down
Loading

0 comments on commit 437d576

Please sign in to comment.