Skip to content

Commit

Permalink
Make webhook chat sync more configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
Erdragh committed May 28, 2024
1 parent c32dc21 commit cb13c69
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ object AstralBotConfig {
*/
val WEBHOOK_ENABLED: ModConfigSpec.BooleanValue

/**
* URL template for getting avatars from Minecraft users
*/
val WEBHOOK_MC_AVATAR_URL: ModConfigSpec.ConfigValue<String>

/**
* Whether the chat messages sent via the webhook should
* imitate the sender's Discord account or their Minecraft
Expand Down Expand Up @@ -126,6 +131,8 @@ object AstralBotConfig {
.define(listOf("webhook", "enabled"), true)
WEBHOOK_USE_LINKED = builder.comment("Whether to imitate user's linked Discord accounts when sending messages from MC to DC")
.define(listOf("webhook", "useLinked"), false)
WEBHOOK_MC_AVATAR_URL = builder.comment("API that returns images based on Minecraft users. {{uuid}} and {{name}} can be used")
.define(listOf("webhook", "mcAvatarUrl"), "https://mc-heads.net/head/{{uuid}}")

REQUIRE_LINK_FOR_WHITELIST = builder.comment("Whether to require being linked to be whitelisted")
.define("requireLinkForWhitelist", false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ object AstralBotTextConfig {

val PLAYER_MESSAGE: ModConfigSpec.ConfigValue<String>

val WEBHOOK_NAME_TEMPLATE: ModConfigSpec.ConfigValue<String>

val DISCORD_MESSAGE: ModConfigSpec.ConfigValue<String>
val DISCORD_REPLY: ModConfigSpec.ConfigValue<String>
val DISCORD_EMBEDS: ModConfigSpec.ConfigValue<String>
Expand Down Expand Up @@ -63,12 +65,19 @@ object AstralBotTextConfig {
.define("tickReport", "Average Tick Time: {{mspt}} MSPT (TPS: {{tps}})")

PLAYER_MESSAGE =
builder.comment("""Template for how Minecraft chat messages are sent to Discord.
builder.comment("""Template for how Minecraft chat messages are sent to Discord if webhooks aren't used
The player's name can be accessed via {{name}} and its name with pre- and suffix
via {{fullName}}. The message itself is accessed via {{message}}.
""".replace(whitespaceRegex, "\n"))
.define(mutableListOf("messages", "minecraft"), "<{{fullName}}> {{message}}")

WEBHOOK_NAME_TEMPLATE =
builder.comment("""Template for how chat synchronization using Webhooks formats
the message author's name.
The player's primary name can be accessed via {{primary}} and the secondary name via {{secondary}}.
""".replace(whitespaceRegex, "\n"))
.define(mutableListOf("webhook", "name"), "{{primary}} ({{secondary}})")

DISCORD_MESSAGE =
builder.comment("""Template for how Discord messages are synchronized to Minecraft.
The sender is referenced by {{user}}. The optional response is accessed by {{reply}}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter()
.build()
})
.setContent(content)
.setUsername(messageSenderInfo.name)
.setUsername(
AstralBotTextConfig.WEBHOOK_NAME_TEMPLATE.get()
.replace("{{primary}}", messageSenderInfo.primaryName)
.replace("{{secondary}}", messageSenderInfo.secondaryName ?: "Unlinked")
)
.setAvatarUrl(messageSenderInfo.avatar)
.build()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package dev.erdragh.astralbot.util

import dev.erdragh.astralbot.LOGGER
import dev.erdragh.astralbot.config.AstralBotConfig
import dev.erdragh.astralbot.handlers.WhitelistHandler
import dev.erdragh.astralbot.jda
import net.dv8tion.jda.api.entities.User
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player

Expand All @@ -13,33 +15,50 @@ object MessageSenderLookup {
fun getMessageSenderInfo(player: ServerPlayer?, discord: Boolean = false): ResolvedSenderInfo? {
if (player == null) return null

if (discord) {
val cached = discordAvatars[player]
if (cached != null) return cached

val discordId = WhitelistHandler.checkWhitelist(player.gameProfile.id)
?: return ResolvedSenderInfo("Unlinked Account (${(player.displayName ?: player.name).string})", null)
val discordUser = jda?.getUserById(discordId)
val discordId = WhitelistHandler.checkWhitelist(player.gameProfile.id)
var discordUser: User? = null
if (discordId != null) {
discordUser = jda?.getUserById(discordId)
if (discordUser == null) {
// Lazily load the user info if it's not cached
jda?.retrieveUserById(discordId)?.submit()?.whenComplete { user, error ->
if (error == null) {
discordAvatars[player] = ResolvedSenderInfo(user.effectiveName, user.avatarUrl)
discordAvatars[player] = ResolvedSenderInfo(user.effectiveName, (player.displayName ?: player.name).string, user.avatarUrl)
minecraftSkins[player] = ResolvedSenderInfo(
(player.displayName ?: player.name).string,
user.effectiveName,
AstralBotConfig.WEBHOOK_MC_AVATAR_URL.get()
.replace("{{uuid}}", player.gameProfile.id.toString())
.replace("{{name}}", player.gameProfile.name)
)
} else {
LOGGER.error("Failed to retrieve user: $discordId for chat synchronization", error)
}
}
return ResolvedSenderInfo("Uncached User (${(player.displayName ?: player.name).string})", null)
}
}

if (discord) {
val cached = discordAvatars[player]
if (cached != null) return cached
if (discordUser == null) {
return ResolvedSenderInfo("Uncached", (player.displayName ?: player.name).string, null)
}

return discordAvatars.computeIfAbsent(player) {
ResolvedSenderInfo(discordUser.effectiveName, discordUser.avatarUrl)
ResolvedSenderInfo(discordUser.effectiveName, (player.displayName ?: player.name).string, discordUser.avatarUrl)
}
}
return minecraftSkins.computeIfAbsent(player) {
ResolvedSenderInfo((player.displayName ?: player.name).string, "https://mc-heads.net/head/${player.gameProfile.id}")
ResolvedSenderInfo(
(player.displayName ?: player.name).string,
if (discordId == null) null else (discordUser?.effectiveName ?: "Uncached"),
AstralBotConfig.WEBHOOK_MC_AVATAR_URL.get()
.replace("{{uuid}}", player.gameProfile.id.toString())
.replace("{{name}}", player.gameProfile.name)
)
}
}

data class ResolvedSenderInfo(val name: String, val avatar: String?)
data class ResolvedSenderInfo(val primaryName: String, val secondaryName: String?, val avatar: String?)
}

0 comments on commit cb13c69

Please sign in to comment.