From 4e362e7976bf51dc49f0126e2a0a01d2d363b00f Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 17 Jan 2024 22:23:30 +0100 Subject: [PATCH 01/35] More graceful shutdown --- .../src/main/kotlin/dev/erdragh/astralbot/Bot.kt | 14 ++++++++++++-- .../erdragh/astralbot/handlers/MinecraftHandler.kt | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt index 235a673..bf2a5d4 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt @@ -15,7 +15,9 @@ import net.minecraft.server.MinecraftServer import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.File +import java.time.Duration import java.time.LocalDateTime +import java.util.concurrent.atomic.AtomicBoolean import kotlin.properties.Delegates const val MODID = "astralbot" @@ -32,6 +34,7 @@ var applicationId by Delegates.notNull() var baseDirectory: File? = null private lateinit var setupJob: Job +var shuttingDown = AtomicBoolean(false) /** * @return the time at which the AstralBot was started @@ -139,8 +142,15 @@ fun startAstralbot(server: MinecraftServer) { fun stopAstralbot() { LOGGER.info("Shutting down AstralBot") + shuttingDown.set(true) if (baseDirectory != null) FAQHandler.stop() - jda?.shutdownNow() - jda?.awaitShutdown() + if (jda != null) { + jda!!.shutdown() + // Allow at most 10 seconds for remaining requests to finish + if (!jda!!.awaitShutdown(Duration.ofSeconds(10))) { + jda!!.shutdownNow() // Cancel all remaining requests + jda!!.awaitShutdown() // Wait until shutdown is complete (indefinitely) + } + } LOGGER.info("Shut down AstralBot") } \ No newline at end of file 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 1a76f28..e7bab51 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -109,6 +109,7 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() * @param message the String contents of the message */ fun sendChatToDiscord(player: ServerPlayer?, message: String) { + if (shuttingDown.get()) return textChannel?.sendMessage(if (player != null) "<${player.displayName.string.replace("_", "\\_")}> $message" else message) ?.setSuppressedNotifications(true) ?.setSuppressEmbeds(true)?.queue() From 667898ca934db7a921651c1da5d7358fe1e7e525 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 10:25:50 +0100 Subject: [PATCH 02/35] Updated dependencies --- fabric/gradle.properties | 4 ++-- gradle.properties | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fabric/gradle.properties b/fabric/gradle.properties index 7a43909..6fbd2cd 100644 --- a/fabric/gradle.properties +++ b/fabric/gradle.properties @@ -1,2 +1,2 @@ -fabricApiVersion=0.88.1 -fabricKotlinVersion=1.10.8+kotlin.1.9.0 \ No newline at end of file +fabricApiVersion=0.91.0 +fabricKotlinVersion=1.10.17+kotlin.1.9.22 \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index fa39321..ceed9f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx3G # Minecraft things enabledPlatforms=fabric,forge # Specified here because it's used in both the fabric and common subproject -fabricLoaderVersion=0.14.22 +fabricLoaderVersion=0.15.6 version=1.1.0 group=dev.erdragh.astralbot @@ -15,8 +15,8 @@ parchmentVersion=2023.09.03 forgeConfigAPIVersion=8.0.0 # Discord Interactions -jdaVersion=5.0.0-beta.19 +jdaVersion=5.0.0-beta.20 # Database Interactions -exposedVersion=0.45.0 +exposedVersion=0.46.0 sqliteJDBCVersion=3.44.1.0 \ No newline at end of file From c7daeda8597cb75414a3df610188688317be78ef Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 10:29:13 +0100 Subject: [PATCH 03/35] Format TPS with two decimal places (#8) --- .../dev/erdragh/astralbot/handlers/MinecraftHandler.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 e7bab51..1275863 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -14,6 +14,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 java.text.DecimalFormat import java.util.* import kotlin.jvm.optionals.getOrNull import kotlin.math.min @@ -27,6 +28,9 @@ import kotlin.math.round */ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() { private val playerNames = HashSet(server.maxPlayers) + companion object { + private val numberFormat = DecimalFormat("###.##") + } /** * Gets all currently online players' names @@ -73,7 +77,11 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() */ fun tickReport(): String { // Idea from the TPSCommand in Forge - return "Average Tick Time: ${round(server.averageTickTime * 100) / 100} (TPS: ${min(20.0, 1000.0/server.averageTickTime)})" + return "Average Tick Time: ${numberFormat.format(server.averageTickTime)}mspt (TPS: ${numberFormat.format( + min( + 20.0, + 1000.0 / server.averageTickTime + ))})" } /** From e4ea62c1e53707ab87562a0da580cfe380780a25 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 10:31:46 +0100 Subject: [PATCH 04/35] Add server starting and stopping discord messages --- common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt index bf2a5d4..f02ac01 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt @@ -96,6 +96,8 @@ private fun setupFromJDA(api: JDA) { } textChannel = ch guild = g + + ch.sendMessage("Server Started!").queue() } @OptIn(DelicateCoroutinesApi::class) @@ -141,6 +143,7 @@ fun startAstralbot(server: MinecraftServer) { } fun stopAstralbot() { + if (!shuttingDown.get()) textChannel?.sendMessage("Server shutting down!")?.queue() LOGGER.info("Shutting down AstralBot") shuttingDown.set(true) if (baseDirectory != null) FAQHandler.stop() From b2c4da019238bf63521dc46a15804f38fa4b8b60 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 11:10:08 +0100 Subject: [PATCH 05/35] Add Minecraft /link command --- .../main/kotlin/dev/erdragh/astralbot/Bot.kt | 2 +- .../{ => discord}/CommandHandlingListener.kt | 2 +- .../DiscordCommands.kt} | 2 +- .../commands/{ => discord}/FAQCommand.kt | 2 +- .../commands/{ => discord}/LinkingCommands.kt | 2 +- .../{ => discord}/ManagementCommands.kt | 2 +- .../{ => discord}/ManagementHelper.kt | 2 +- .../{ => discord}/MinecraftCommands.kt | 2 +- .../commands/{ => discord}/SetupCommands.kt | 2 +- .../commands/minecraft/MinecraftCommands.kt | 25 ++++++++++++++++ .../astralbot/config/AstralBotConfig.kt | 2 +- .../astralbot/handlers/WhitelistHandler.kt | 30 ++++++++++++------- common/src/main/kotlin/module-info.java | 1 + .../dev/erdragh/astralbot/fabric/BotMod.kt | 9 ++++-- .../dev/erdragh/astralbot/forge/BotMod.kt | 6 ++++ 15 files changed, 67 insertions(+), 24 deletions(-) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/CommandHandlingListener.kt (98%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{Commands.kt => discord/DiscordCommands.kt} (98%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/FAQCommand.kt (96%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/LinkingCommands.kt (99%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/ManagementCommands.kt (99%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/ManagementHelper.kt (92%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/MinecraftCommands.kt (95%) rename common/src/main/kotlin/dev/erdragh/astralbot/commands/{ => discord}/SetupCommands.kt (99%) create mode 100644 common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt index f02ac01..c756ef5 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt @@ -1,6 +1,6 @@ package dev.erdragh.astralbot -import dev.erdragh.astralbot.commands.CommandHandlingListener +import dev.erdragh.astralbot.commands.discord.CommandHandlingListener import dev.erdragh.astralbot.config.AstralBotConfig import dev.erdragh.astralbot.handlers.FAQHandler import dev.erdragh.astralbot.handlers.MinecraftHandler diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/CommandHandlingListener.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt similarity index 98% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/CommandHandlingListener.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt index c9f967c..4484be6 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/CommandHandlingListener.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.applicationId diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/Commands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt similarity index 98% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/Commands.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt index 905fc3c..a9d5a75 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/Commands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt @@ -1,6 +1,6 @@ // This file contains multiple commands which don't warrant separate files -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.config.AstralBotConfig import dev.erdragh.astralbot.minecraftHandler diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/FAQCommand.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FAQCommand.kt similarity index 96% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/FAQCommand.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FAQCommand.kt index 246fab8..caa1d98 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/FAQCommand.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FAQCommand.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.handlers.FAQHandler import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/LinkingCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt similarity index 99% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/LinkingCommands.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt index 6f82c4c..97c345e 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/LinkingCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.config.AstralBotConfig diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/ManagementCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/ManagementCommands.kt similarity index 99% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/ManagementCommands.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/ManagementCommands.kt index 0adfd3b..920f4c2 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/ManagementCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/ManagementCommands.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.getStartTimestamp diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/ManagementHelper.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/ManagementHelper.kt similarity index 92% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/ManagementHelper.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/ManagementHelper.kt index caf5706..aa77498 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/ManagementHelper.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/ManagementHelper.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import com.sun.management.OperatingSystemMXBean import java.lang.management.ManagementFactory diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/MinecraftCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/MinecraftCommands.kt similarity index 95% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/MinecraftCommands.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/MinecraftCommands.kt index 9c1a7fa..312b73d 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/MinecraftCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/MinecraftCommands.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.minecraftHandler import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/SetupCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt similarity index 99% rename from common/src/main/kotlin/dev/erdragh/astralbot/commands/SetupCommands.kt rename to common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt index 9c6e88b..ab95f4c 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/SetupCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.commands +package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.config.AstralBotConfig diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt new file mode 100644 index 0000000..2cb8acc --- /dev/null +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt @@ -0,0 +1,25 @@ +package dev.erdragh.astralbot.commands.minecraft + +import com.mojang.brigadier.Command +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder.literal +import com.mojang.brigadier.context.CommandContext +import dev.erdragh.astralbot.handlers.WhitelistHandler +import net.minecraft.commands.CommandSourceStack +import net.minecraft.network.chat.Component + +fun registerMinecraftCommands(dispatcher: CommandDispatcher) { + dispatcher.register(literal("link").executes(LinkCommand)) +} + +object LinkCommand : Command { + override fun run(context: CommandContext?): Int { + val caller = context?.source?.playerOrException!! + val whitelistCode = WhitelistHandler.getOrGenerateWhitelistCode(caller.uuid) + context.source.sendSuccess({ + Component.literal("Use this code to /link yourself on Discord:") + .append(Component.literal("$whitelistCode").withStyle { it.withItalic(true) }) + }, false) + return 0 + } +} \ No newline at end of file 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 dd9f51f..63baa6f 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt @@ -1,7 +1,7 @@ package dev.erdragh.astralbot.config import dev.erdragh.astralbot.LOGGER -import dev.erdragh.astralbot.commands.allCommands +import dev.erdragh.astralbot.commands.discord.allCommands import net.minecraftforge.common.ForgeConfigSpec import java.net.URL diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt index 0f4edba..18fea9a 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt @@ -174,6 +174,23 @@ object WhitelistHandler { return result } + fun getOrGenerateWhitelistCode(minecraftID: UUID): Int { + val foundCode = loginCodes.entries.find { it.value == minecraftID }?.key + if (foundCode != null) return foundCode + + val loginCodeRange = 10000..99999 + val whitelistCode = loginRandom.nextInt(loginCodeRange) + // The following line could be vulnerable to a DOS attack + // I accept the possibility of a login code possibly getting overwritten + // so this DOS won't cause an infinite loop. Such a DOS may still cause + // Players to not be able to whitelist. + // while (loginCodes.containsKey(whitelistCode)) whitelistCode = loginRandom.nextInt(loginCodeRange) + synchronized(loginCodes) { + loginCodes[whitelistCode] = minecraftID + } + return whitelistCode + } + /** * Checks whether a User is actually whitelisted and is allowed to join the server. * This method gets used in the PlayerList mixins to expand the isWhiteListed check. @@ -190,17 +207,8 @@ object WhitelistHandler { val hasToBeWhitelistedByLink = (!isWhitelisted && AstralBotConfig.REQUIRE_LINK_FOR_WHITELIST.get()) || (!isWhitelisted && !defaultWhitelisted) // Generates a link code only if the user doesn't have one and has to go through linking to get one - if (!loginCodes.containsValue(minecraftID) && hasToBeWhitelistedByLink) { - val loginCodeRange = 10000..99999 - val whitelistCode = loginRandom.nextInt(loginCodeRange) - // The following line could be vulnerable to a DOS attack - // I accept the possibility of a login code possibly getting overwritten - // so this DOS won't cause an infinite loop. Such a DOS may still cause - // Players to not be able to whitelist. - // while (loginCodes.containsKey(whitelistCode)) whitelistCode = loginRandom.nextInt(loginCodeRange) - synchronized(loginCodes) { - loginCodes[whitelistCode] = minecraftID - } + if (hasToBeWhitelistedByLink) { + getOrGenerateWhitelistCode(minecraftID) } // The config option is false by default, which means other methods of whitelisting diff --git a/common/src/main/kotlin/module-info.java b/common/src/main/kotlin/module-info.java index 8b62ebd..f20fe66 100644 --- a/common/src/main/kotlin/module-info.java +++ b/common/src/main/kotlin/module-info.java @@ -19,6 +19,7 @@ requires authlib; requires minecraft.merged; requires transitive org.slf4j; + requires brigadier; // For accessing the config requires forgeconfigapiport.common; 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 de487f5..52120e9 100644 --- a/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt +++ b/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt @@ -1,14 +1,13 @@ package dev.erdragh.astralbot.fabric import dev.erdragh.astralbot.* +import dev.erdragh.astralbot.commands.minecraft.registerMinecraftCommands import dev.erdragh.astralbot.config.AstralBotConfig import dev.erdragh.astralbot.handlers.DiscordMessageComponent import fuzs.forgeconfigapiport.api.config.v2.ForgeConfigRegistry import net.fabricmc.api.ModInitializer -import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents import net.fabricmc.fabric.api.message.v1.ServerMessageEvents import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents import net.minecraft.server.level.ServerPlayer @@ -43,5 +42,9 @@ object BotMod : ModInitializer { ServerPlayConnectionEvents.DISCONNECT.register { packet, _ -> minecraftHandler?.onPlayerLeave(packet.player.name.string) } + + CommandRegistrationCallback.EVENT.register { dispatcher, _, _ -> + registerMinecraftCommands(dispatcher) + } } } \ No newline at end of file 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 795c129..a29c5d1 100644 --- a/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt +++ b/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt @@ -1,6 +1,7 @@ package dev.erdragh.astralbot.forge import dev.erdragh.astralbot.LOGGER +import dev.erdragh.astralbot.commands.minecraft.registerMinecraftCommands import dev.erdragh.astralbot.config.AstralBotConfig import dev.erdragh.astralbot.forge.event.SystemMessageEvent import dev.erdragh.astralbot.handlers.DiscordMessageComponent @@ -8,6 +9,7 @@ import dev.erdragh.astralbot.minecraftHandler import dev.erdragh.astralbot.startAstralbot import dev.erdragh.astralbot.stopAstralbot import net.minecraft.server.level.ServerPlayer +import net.minecraftforge.event.RegisterCommandsEvent import net.minecraftforge.event.ServerChatEvent import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.event.server.ServerStartedEvent @@ -56,4 +58,8 @@ object BotMod { private fun onPlayerLeave(event: PlayerEvent.PlayerLoggedOutEvent) { minecraftHandler?.onPlayerLeave(event.entity.name.string) } + + private fun onCommandRegistration(event: RegisterCommandsEvent) { + registerMinecraftCommands(event.dispatcher) + } } \ No newline at end of file From 686dee1223cd87a1095dc2aa13d2bd56aadcba88 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 11:26:51 +0100 Subject: [PATCH 06/35] Add AstralBotTextConfig and use it for FAQs --- .../astralbot/config/AstralBotTextConfig.kt | 25 +++++++++++++++++++ .../erdragh/astralbot/handlers/FAQHandler.kt | 5 ++-- .../dev/erdragh/astralbot/fabric/BotMod.kt | 2 ++ .../dev/erdragh/astralbot/forge/BotMod.kt | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt new file mode 100644 index 0000000..714359f --- /dev/null +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -0,0 +1,25 @@ +package dev.erdragh.astralbot.config + +import net.minecraftforge.common.ForgeConfigSpec + +object AstralBotTextConfig { + val SPEC: ForgeConfigSpec + + val FAQ_ERROR: ForgeConfigSpec.ConfigValue + val FAQ_NO_REGISTERED: ForgeConfigSpec.ConfigValue + + init { + val builder = ForgeConfigSpec.Builder() + + FAQ_ERROR = builder.comment("Message sent to Discord if an error ocurrs during FAQ loading") + .define("faqError", "Bot Error (Contact Bot Operator)") + FAQ_NO_REGISTERED = + builder.comment( + """Message sent to Discord when there is no FAQ for the given id. + The placeholder {{id}} may be used to include the requested id""".trimMargin() + ) + .define("faqNoRegistered", "No FAQ registered for id: `{{id}}`") + + SPEC = builder.build() + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/FAQHandler.kt b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/FAQHandler.kt index 3ff2d0e..68b6d4b 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/FAQHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/FAQHandler.kt @@ -2,6 +2,7 @@ package dev.erdragh.astralbot.handlers import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.baseDirectory +import dev.erdragh.astralbot.config.AstralBotTextConfig import java.io.File import java.nio.file.StandardWatchEventKinds import kotlin.io.path.extension @@ -67,11 +68,11 @@ object FAQHandler { fun getFAQForId(id: String): String { if (!faqDirectory.exists() || !faqDirectory.isDirectory) { LOGGER.error("FAQ directory not specified as directory: ${faqDirectory.absolutePath}") - return "Bot Error (Contact Bot Operator)" + return AstralBotTextConfig.FAQ_ERROR.get() } val faqFiles = faqDirectory.listFiles { file -> file.name == "$id.md" } val faqFile = if (faqFiles?.isNotEmpty() == true) faqFiles[0] else null - return faqFile?.readText(Charsets.UTF_8) ?: "No FAQ registered for id: `$id`" + return faqFile?.readText(Charsets.UTF_8) ?: AstralBotTextConfig.FAQ_NO_REGISTERED.get().replace("{{id}}", id) } /** 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 52120e9..448bbaf 100644 --- a/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt +++ b/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt @@ -3,6 +3,7 @@ package dev.erdragh.astralbot.fabric import dev.erdragh.astralbot.* import dev.erdragh.astralbot.commands.minecraft.registerMinecraftCommands import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig import dev.erdragh.astralbot.handlers.DiscordMessageComponent import fuzs.forgeconfigapiport.api.config.v2.ForgeConfigRegistry import net.fabricmc.api.ModInitializer @@ -16,6 +17,7 @@ import net.minecraftforge.fml.config.ModConfig object BotMod : ModInitializer { override fun onInitialize() { ForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotConfig.SPEC) + ForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text") ServerLifecycleEvents.SERVER_STARTED.register { LOGGER.info("Starting AstralBot on Fabric") 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 a29c5d1..fecc8ee 100644 --- a/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt +++ b/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt @@ -3,6 +3,7 @@ package dev.erdragh.astralbot.forge import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.commands.minecraft.registerMinecraftCommands import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig import dev.erdragh.astralbot.forge.event.SystemMessageEvent import dev.erdragh.astralbot.handlers.DiscordMessageComponent import dev.erdragh.astralbot.minecraftHandler @@ -23,6 +24,7 @@ import thedarkcolour.kotlinforforge.forge.FORGE_BUS object BotMod { init { ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotConfig.SPEC) + ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text") FORGE_BUS.addListener(::onServerStart) FORGE_BUS.addListener(::onServerStop) FORGE_BUS.addListener(::onChatMessage) From f5dd1a3465542b45e41c04ee569509ca267a1a9d Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 11:38:50 +0100 Subject: [PATCH 07/35] tickReport and playerMessage templating --- .../astralbot/config/AstralBotTextConfig.kt | 20 +++++++++++++- .../astralbot/handlers/MinecraftHandler.kt | 26 ++++++++++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) 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 714359f..ead5638 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -8,6 +8,10 @@ object AstralBotTextConfig { val FAQ_ERROR: ForgeConfigSpec.ConfigValue val FAQ_NO_REGISTERED: ForgeConfigSpec.ConfigValue + val TICK_REPORT: ForgeConfigSpec.ConfigValue + + val PLAYER_MESSAGE: ForgeConfigSpec.ConfigValue + init { val builder = ForgeConfigSpec.Builder() @@ -16,10 +20,24 @@ object AstralBotTextConfig { FAQ_NO_REGISTERED = builder.comment( """Message sent to Discord when there is no FAQ for the given id. - The placeholder {{id}} may be used to include the requested id""".trimMargin() + The placeholder {{id}} may be used to include the requested id""".trimIndent() ) .define("faqNoRegistered", "No FAQ registered for id: `{{id}}`") + TICK_REPORT = + builder.comment("""Template for the tick report sent to users on the /tps command. + the average time per tick in MSPT can be used via {{mspt}} and the TPS calculated + from it via {{tps}} + """.trimIndent()) + .define("tickReport", "Average Tick Time: {{mspt}} MSPT (TPS: {{tps}})") + + PLAYER_MESSAGE = + builder.comment("""Template for how Minecraft chat messages are sent to Discord. + 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}}. + """.trimIndent()) + .define("playerMessage", "<{{fullName}}> {{message}}") + SPEC = builder.build() } } \ No newline at end of file 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 1275863..bf59d73 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -3,6 +3,7 @@ package dev.erdragh.astralbot.handlers import com.mojang.authlib.GameProfile import dev.erdragh.astralbot.* import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig import net.dv8tion.jda.api.entities.Member import net.dv8tion.jda.api.entities.Message import net.dv8tion.jda.api.events.message.MessageReceivedEvent @@ -28,6 +29,7 @@ import kotlin.math.round */ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() { private val playerNames = HashSet(server.maxPlayers) + companion object { private val numberFormat = DecimalFormat("###.##") } @@ -77,11 +79,15 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() */ fun tickReport(): String { // Idea from the TPSCommand in Forge - return "Average Tick Time: ${numberFormat.format(server.averageTickTime)}mspt (TPS: ${numberFormat.format( - min( - 20.0, - 1000.0 / server.averageTickTime - ))})" + return AstralBotTextConfig.TICK_REPORT.get().replace("{{mspt}}", numberFormat.format(server.averageTickTime)) + .replace( + "{{tps}}", numberFormat.format( + min( + 20.0, + 1000.0 / server.averageTickTime + ) + ) + ) } /** @@ -118,7 +124,15 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() */ fun sendChatToDiscord(player: ServerPlayer?, message: String) { if (shuttingDown.get()) return - textChannel?.sendMessage(if (player != null) "<${player.displayName.string.replace("_", "\\_")}> $message" else message) + val escape = { it: String -> it.replace("_", "\\_") } + textChannel?.sendMessage( + if (player != null) + AstralBotTextConfig.PLAYER_MESSAGE.get() + .replace("{{message}}", escape(message)) + .replace("{{fullName}}", escape(player.displayName.string)) + .replace("{{name}}", escape(player.name.string)) + else escape(message) + ) ?.setSuppressedNotifications(true) ?.setSuppressEmbeds(true)?.queue() } From 11a931fda2364e5fab7e04127785fb87930f6b23 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 12:51:13 +0100 Subject: [PATCH 08/35] Discord message sync templating --- .../astralbot/config/AstralBotTextConfig.kt | 14 ++++ .../astralbot/handlers/MinecraftHandler.kt | 66 +++++++++++++++---- 2 files changed, 66 insertions(+), 14 deletions(-) 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 ead5638..740f851 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -12,6 +12,9 @@ object AstralBotTextConfig { val PLAYER_MESSAGE: ForgeConfigSpec.ConfigValue + val DISCORD_MESSAGE: ForgeConfigSpec.ConfigValue + val DISCORD_REPLY: ForgeConfigSpec.ConfigValue + init { val builder = ForgeConfigSpec.Builder() @@ -38,6 +41,17 @@ object AstralBotTextConfig { """.trimIndent()) .define("playerMessage", "<{{fullName}}> {{message}}") + 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}} + """.trimIndent()) + .define("discordMessage", "{{user}}{{reply}}:") + DISCORD_REPLY = + builder.comment("""Template for the {{reply}} part of the discordMessage. + The user the message is in reply to is referenced by {{replied}} + """.trimIndent()) + .define("discordReply", " replying to {{replied}}:") + SPEC = builder.build() } } \ No newline at end of file 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 bf59d73..410f8a9 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -19,7 +19,6 @@ import java.text.DecimalFormat import java.util.* import kotlin.jvm.optionals.getOrNull import kotlin.math.min -import kotlin.math.round /** * Wrapper class around the [MinecraftServer] to provide convenience @@ -187,10 +186,6 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() */ private fun sendFormattedMessage(message: Message, send: (component: MutableComponent) -> Unit) { val comp = Component.empty() - // The actual sender of the message - message.member?.let { - comp.append(formattedUser(it)) - } // Lambda that constructs the rest of the message. I'm doing it this way // because this may be used in a callback lambda below, where I can't return @@ -198,9 +193,7 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() val formatRestOfMessage: () -> MutableComponent = { -> val restOfMessage = Component.empty() // This is the actual message content - val actualMessage = Component.empty() - .append(Component.literal(": ").withStyle { it.withColor(ChatFormatting.GRAY) }) - .append(message.contentDisplay) + val actualMessage = Component.literal(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()) { @@ -222,27 +215,72 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() if (referencedAuthor != null) { // This fetches the Member from the ID in a blocking manner - guild?.retrieveMemberById(referencedAuthor)?.submit()?.whenComplete { member, error -> + guild?.retrieveMemberById(referencedAuthor)?.submit()?.whenComplete { repliedMember, error -> if (error != null) { LOGGER.error("Failed to get member with id: $referencedAuthor", error) return@whenComplete - } else if (member == null) { + } else if (repliedMember == null) { LOGGER.error("Failed to get member with id: $referencedAuthor") return@whenComplete } - comp.append( - Component.literal(" replying to ") - .withStyle { style -> style.withColor(ChatFormatting.GRAY).withItalic(true) }) - comp.append(formattedUser(member)) + message.member?.let { + comp.append(formattedUsers(it, repliedMember)) + } comp.append(formatRestOfMessage()) send(comp) } } else { + message.member?.let { + comp.append(formattedUsers(it, null)) + } comp.append(formatRestOfMessage()) send(comp) } } + private fun formattedUsers(author: Member, replied: Member?): MutableComponent { + val users = Component.empty() + + val templateSplitByUser = AstralBotTextConfig.DISCORD_MESSAGE.get().split("{{user}}") + + val withReply = { templatePart: String -> + val accumulator = Component.empty() + + val reply = Component.empty() + replied?.let { + val replyTemplateSplit = AstralBotTextConfig.DISCORD_REPLY.get().split("{{replied}}") + for ((index, value) in replyTemplateSplit.withIndex()) { + reply.append(Component.literal(value).withStyle { style -> style.withColor(ChatFormatting.GRAY) }) + + if (index + 1 < replyTemplateSplit.size) { + reply.append(formattedUser(it)) + } + } + } + + val templateSplitByReply = templatePart.split("{{reply}}") + + for ((index, value) in templateSplitByReply.withIndex()) { + accumulator.append(Component.literal(value).withStyle { it.withColor(ChatFormatting.GRAY) }) + + if (index + 1 < templateSplitByReply.size) { + accumulator.append(reply.copy()) + } + } + accumulator + } + + for ((index, value) in templateSplitByUser.withIndex()) { + users.append(withReply(value)) + + if (index + 1 < templateSplitByUser.size) { + users.append(formattedUser(author)) + } + } + + return users + } + /** * Formats the attachments and embeds on a Discord [Message] into * a comma separated list. From f03e85ee18a5bdab3edc4ea355fdf66e4601907e Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 12:52:04 +0100 Subject: [PATCH 09/35] Config files should be .toml --- fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt | 2 +- forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 448bbaf..203ae0e 100644 --- a/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt +++ b/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt @@ -17,7 +17,7 @@ import net.minecraftforge.fml.config.ModConfig object BotMod : ModInitializer { override fun onInitialize() { ForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotConfig.SPEC) - ForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text") + ForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text.toml") ServerLifecycleEvents.SERVER_STARTED.register { LOGGER.info("Starting AstralBot on Fabric") 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 fecc8ee..40d145a 100644 --- a/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt +++ b/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt @@ -24,7 +24,7 @@ import thedarkcolour.kotlinforforge.forge.FORGE_BUS object BotMod { init { ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotConfig.SPEC) - ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text") + ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text.toml") FORGE_BUS.addListener(::onServerStart) FORGE_BUS.addListener(::onServerStop) FORGE_BUS.addListener(::onChatMessage) From 441d07d6a349c8a7f217d08c9b4a7f9270dff9b2 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 13:00:54 +0100 Subject: [PATCH 10/35] Reload text templates --- .../discord/CommandHandlingListener.kt | 7 +++--- .../astralbot/config/AstralBotTextConfig.kt | 22 ++++++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt index 4484be6..3f8cafc 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt @@ -2,6 +2,7 @@ package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.applicationId +import dev.erdragh.astralbot.config.AstralBotTextConfig import dev.erdragh.astralbot.guild import dev.erdragh.astralbot.waitForSetup import net.dv8tion.jda.api.entities.Guild @@ -61,14 +62,14 @@ object CommandHandlingListener : ListenerAdapter() { fun updateCommands(guild: Guild, sendMessage: (msg: String) -> Unit) { guild.retrieveCommands().submit().whenComplete { fetchedCommands, error -> if (error != null) { - sendMessage("Something went wrong: ${error.localizedMessage}") + sendMessage(AstralBotTextConfig.RELOAD_ERROR.get().replace("{{error}}", error.localizedMessage)) return@whenComplete } waitForSetup() val deletedCommands = fetchedCommands.filter { it.applicationIdLong == applicationId }.map { guild.deleteCommandById(it.id).submit() } deletedCommands.forEach { it.get() } guild.updateCommands().addCommands(getEnabledCommands().map { it.command }).queue { - sendMessage("Reloaded commands for guild") + sendMessage(AstralBotTextConfig.RELOAD_SUCCESS.get()) } } } @@ -84,7 +85,7 @@ object CommandHandlingListener : ListenerAdapter() { if (usedCommand != null) { usedCommand.handle(event) } else { - event.reply("Something went wrong").queue() + event.reply(AstralBotTextConfig.GENERIC_ERROR.get()).queue() } } 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 740f851..783fd20 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -5,6 +5,8 @@ import net.minecraftforge.common.ForgeConfigSpec object AstralBotTextConfig { val SPEC: ForgeConfigSpec + val GENERIC_ERROR: ForgeConfigSpec.ConfigValue + val FAQ_ERROR: ForgeConfigSpec.ConfigValue val FAQ_NO_REGISTERED: ForgeConfigSpec.ConfigValue @@ -15,9 +17,15 @@ object AstralBotTextConfig { val DISCORD_MESSAGE: ForgeConfigSpec.ConfigValue val DISCORD_REPLY: ForgeConfigSpec.ConfigValue + val RELOAD_ERROR: ForgeConfigSpec.ConfigValue + val RELOAD_SUCCESS: ForgeConfigSpec.ConfigValue + init { val builder = ForgeConfigSpec.Builder() + GENERIC_ERROR = builder.comment("Generic error message sent to Discord") + .define("genericError", "Something went wrong!") + FAQ_ERROR = builder.comment("Message sent to Discord if an error ocurrs during FAQ loading") .define("faqError", "Bot Error (Contact Bot Operator)") FAQ_NO_REGISTERED = @@ -39,18 +47,26 @@ object AstralBotTextConfig { 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}}. """.trimIndent()) - .define("playerMessage", "<{{fullName}}> {{message}}") + .define(mutableListOf("messages", "minecraft"), "<{{fullName}}> {{message}}") 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}} """.trimIndent()) - .define("discordMessage", "{{user}}{{reply}}:") + .define(mutableListOf("messages", "discord", "message"), "{{user}}{{reply}}:") DISCORD_REPLY = builder.comment("""Template for the {{reply}} part of the discordMessage. The user the message is in reply to is referenced by {{replied}} """.trimIndent()) - .define("discordReply", " replying to {{replied}}:") + .define(mutableListOf("messages", "discord", "reply"), " replying to {{replied}}:") + + RELOAD_ERROR = + builder.comment("""Template for the error message sent to Discord when reloading fails. + The error message itself is accessible with {{error}} + """.trimIndent()) + .define(mutableListOf("reload", "error"), "Something went wrong: {{error}}") + RELOAD_SUCCESS = builder.comment("Message sent to Discord after a successful reload") + .define(mutableListOf("reload", "success"), "Reloaded commands for guild") SPEC = builder.build() } From 5ea739602c0e68bc749862be080555d21bf211e9 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 13:33:44 +0100 Subject: [PATCH 11/35] Fix config comment formatting --- .../astralbot/config/AstralBotTextConfig.kt | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) 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 783fd20..e33eaf6 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -22,48 +22,50 @@ object AstralBotTextConfig { init { val builder = ForgeConfigSpec.Builder() + val whitespaceRegex = Regex("\n[ \t]+"); GENERIC_ERROR = builder.comment("Generic error message sent to Discord") .define("genericError", "Something went wrong!") FAQ_ERROR = builder.comment("Message sent to Discord if an error ocurrs during FAQ loading") - .define("faqError", "Bot Error (Contact Bot Operator)") + .define(mutableListOf("faq", "error"), "Bot Error (Contact Bot Operator)") FAQ_NO_REGISTERED = builder.comment( """Message sent to Discord when there is no FAQ for the given id. - The placeholder {{id}} may be used to include the requested id""".trimIndent() + The placeholder {{id}} may be used to include the requested id""".replace(whitespaceRegex, "\n") ) - .define("faqNoRegistered", "No FAQ registered for id: `{{id}}`") + .define(mutableListOf("faq", "notRegistered"), "No FAQ registered for id: `{{id}}`") TICK_REPORT = builder.comment("""Template for the tick report sent to users on the /tps command. the average time per tick in MSPT can be used via {{mspt}} and the TPS calculated from it via {{tps}} - """.trimIndent()) + """.replace(whitespaceRegex, "\n")) .define("tickReport", "Average Tick Time: {{mspt}} MSPT (TPS: {{tps}})") PLAYER_MESSAGE = builder.comment("""Template for how Minecraft chat messages are sent to Discord. 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}}. - """.trimIndent()) + """.replace(whitespaceRegex, "\n")) .define(mutableListOf("messages", "minecraft"), "<{{fullName}}> {{message}}") 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}} - """.trimIndent()) - .define(mutableListOf("messages", "discord", "message"), "{{user}}{{reply}}:") + The sender is referenced by {{user}}. The optional response is accessed by {{reply}}. + The message itself is accessed with {{message}} + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("messages", "discord", "message"), "{{user}}{{reply}}: {{message}}") DISCORD_REPLY = builder.comment("""Template for the {{reply}} part of the discordMessage. The user the message is in reply to is referenced by {{replied}} - """.trimIndent()) - .define(mutableListOf("messages", "discord", "reply"), " replying to {{replied}}:") + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("messages", "discord", "reply"), " replying to {{replied}}") RELOAD_ERROR = builder.comment("""Template for the error message sent to Discord when reloading fails. The error message itself is accessible with {{error}} - """.trimIndent()) + """.replace(whitespaceRegex, "\n")) .define(mutableListOf("reload", "error"), "Something went wrong: {{error}}") RELOAD_SUCCESS = builder.comment("Message sent to Discord after a successful reload") .define(mutableListOf("reload", "success"), "Reloaded commands for guild") From 2afb2c639f400c18f842329859c4d75779f379c9 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 13:34:11 +0100 Subject: [PATCH 12/35] refactor Discord -> Minecraft message formatting --- .../astralbot/handlers/MinecraftHandler.kt | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) 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 410f8a9..5f41689 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -187,26 +187,19 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() private fun sendFormattedMessage(message: Message, send: (component: MutableComponent) -> Unit) { val comp = Component.empty() - // Lambda that constructs the rest of the message. I'm doing it this way - // because this may be used in a callback lambda below, where I can't return - // out of sendFormattedMessage anymore - val formatRestOfMessage: () -> MutableComponent = { -> - val restOfMessage = Component.empty() - // This is the actual message content - val actualMessage = Component.literal(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()) { - actualMessage.withStyle { it.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, message.jumpUrl)) } - } - restOfMessage.append(actualMessage) - - // Only adds embeds if it's enabled in the config - if (AstralBotConfig.HANDLE_EMBEDS.get()) { - restOfMessage.append(formatEmbeds(message)) - } + val messageContents = Component.empty() + // This is the actual message content + val actualMessage = Component.literal(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()) { + actualMessage.withStyle { it.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, message.jumpUrl)) } + } + messageContents.append(actualMessage) - restOfMessage + // Only adds embeds if it's enabled in the config + if (AstralBotConfig.HANDLE_EMBEDS.get()) { + messageContents.append(formatEmbeds(message)) } val referencedAuthor = message.referencedMessage?.author?.id @@ -224,25 +217,41 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() return@whenComplete } message.member?.let { - comp.append(formattedUsers(it, repliedMember)) + comp.append(formatMessageWithUsers(messageContents, it, repliedMember)) + send(comp) } - comp.append(formatRestOfMessage()) - send(comp) } } else { message.member?.let { - comp.append(formattedUsers(it, null)) + comp.append(formatMessageWithUsers(messageContents, it, null)) + send(comp) } - comp.append(formatRestOfMessage()) - send(comp) } } - private fun formattedUsers(author: Member, replied: Member?): MutableComponent { - val users = Component.empty() + private fun formatMessageWithUsers(message: MutableComponent, author: Member, replied: Member?): MutableComponent { + val formatted = Component.empty() val templateSplitByUser = AstralBotTextConfig.DISCORD_MESSAGE.get().split("{{user}}") + val formattedLiteral = { contents: String -> Component.literal(contents).withStyle(ChatFormatting.GRAY) } + + val withMessage = { templatePart: String -> + val accumulator = Component.empty() + + val templateSplitMessage = templatePart.split("{{message}}") + + for ((index, value) in templateSplitMessage.withIndex()) { + accumulator.append(formattedLiteral(value)) + + if (index + 1 < templateSplitMessage.size) { + accumulator.append(message) + } + } + + accumulator + } + val withReply = { templatePart: String -> val accumulator = Component.empty() @@ -250,7 +259,7 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() replied?.let { val replyTemplateSplit = AstralBotTextConfig.DISCORD_REPLY.get().split("{{replied}}") for ((index, value) in replyTemplateSplit.withIndex()) { - reply.append(Component.literal(value).withStyle { style -> style.withColor(ChatFormatting.GRAY) }) + reply.append(formattedLiteral(value)) if (index + 1 < replyTemplateSplit.size) { reply.append(formattedUser(it)) @@ -261,7 +270,7 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() val templateSplitByReply = templatePart.split("{{reply}}") for ((index, value) in templateSplitByReply.withIndex()) { - accumulator.append(Component.literal(value).withStyle { it.withColor(ChatFormatting.GRAY) }) + accumulator.append(withMessage(value)) if (index + 1 < templateSplitByReply.size) { accumulator.append(reply.copy()) @@ -271,14 +280,14 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() } for ((index, value) in templateSplitByUser.withIndex()) { - users.append(withReply(value)) + formatted.append(withReply(value)) if (index + 1 < templateSplitByUser.size) { - users.append(formattedUser(author)) + formatted.append(formattedUser(author)) } } - return users + return formatted } /** From f10867db9be58635e71808372a8e909de6f3c545 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Wed, 24 Jan 2024 17:47:59 +0100 Subject: [PATCH 13/35] Link command text templates --- .../commands/discord/LinkingCommands.kt | 24 +++++++-- .../commands/minecraft/MinecraftCommands.kt | 7 ++- .../astralbot/config/AstralBotTextConfig.kt | 54 ++++++++++++++++++- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt index 97c345e..bac3b50 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt @@ -2,6 +2,7 @@ package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig import dev.erdragh.astralbot.guild import dev.erdragh.astralbot.handlers.WhitelistHandler import dev.erdragh.astralbot.minecraftHandler @@ -41,7 +42,7 @@ object LinkCommand : HandledSlashCommand { // Notify the user that the given link code couldn't be associated with a Minecraft account if (minecraftID == null) { - event.hook.setEphemeral(true).sendMessage("Couldn't find Minecraft account to link").queue() + event.hook.setEphemeral(true).sendMessage(AstralBotTextConfig.LINK_NO_MINECRAFT.get()).queue() return } @@ -52,10 +53,16 @@ object LinkCommand : HandledSlashCommand { // Depending on the whitelisting status of the given data send the relevant response if (WhitelistHandler.checkWhitelist(minecraftID) != null) { event.hook.setEphemeral(true) - .sendMessageFormat("Minecraft username %s already linked", minecraftUser?.name) + .sendMessageFormat( + AstralBotTextConfig.LINK_MINECRAFT_TAKEN.get() + .replace("{{name}}", minecraftUser?.name ?: "Unnamed Account") + ) .queue() } else if (WhitelistHandler.checkWhitelist(event.user.idLong) != null) { - event.hook.setEphemeral(true).sendMessageFormat("%s already linked", event.member).queue() + event.hook.setEphemeral(true).sendMessageFormat( + AstralBotTextConfig.LINK_DISCORD_TAKEN.get() + .replace("{{name}}", event.member?.toString() ?: "Unnamed Account") + ).queue() } else { WhitelistHandler.whitelist(event.user, minecraftID) waitForSetup() @@ -67,11 +74,17 @@ object LinkCommand : HandledSlashCommand { } } event.hook.setEphemeral(true) - .sendMessageFormat("Linked %s to Minecraft username %s", event.member, minecraftUser?.name).queue() + .sendMessageFormat( + AstralBotTextConfig.LINK_SUCCESSFUL.get() + .replace("{{dc}}", event.member?.toString() ?: "Unnamed Account") + .replace("{{mc}}", minecraftUser?.name ?: "Unnamed Account") + ).queue() } } catch (e: Exception) { // Just in case a DB interaction failed the user still needs to get a response. - event.hook.setEphemeral(true).sendMessageFormat("Failed to link: %s", e.localizedMessage).queue() + event.hook.setEphemeral(true) + .sendMessageFormat(AstralBotTextConfig.LINK_ERROR.get().replace("{{error}}", e.localizedMessage)) + .queue() LOGGER.error("Failed to link", e) } @@ -101,6 +114,7 @@ object UnlinkCommand : HandledSlashCommand { // Specifying option names as constants to prevent typos private const val OPTION_MC = "mc" private const val OPTION_DC = "dc" + /** * This command can check the link status of Discord Users and Minecraft accounts * diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt index 2cb8acc..71777d4 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/minecraft/MinecraftCommands.kt @@ -4,6 +4,7 @@ import com.mojang.brigadier.Command import com.mojang.brigadier.CommandDispatcher import com.mojang.brigadier.builder.LiteralArgumentBuilder.literal import com.mojang.brigadier.context.CommandContext +import dev.erdragh.astralbot.config.AstralBotTextConfig import dev.erdragh.astralbot.handlers.WhitelistHandler import net.minecraft.commands.CommandSourceStack import net.minecraft.network.chat.Component @@ -15,10 +16,12 @@ fun registerMinecraftCommands(dispatcher: CommandDispatcher) object LinkCommand : Command { override fun run(context: CommandContext?): Int { val caller = context?.source?.playerOrException!! + if (WhitelistHandler.checkWhitelist(caller.uuid) != null) { + context.source.sendFailure(Component.literal(AstralBotTextConfig.LINK_COMMAND_ALREADY_LINKED.get())) + } val whitelistCode = WhitelistHandler.getOrGenerateWhitelistCode(caller.uuid) context.source.sendSuccess({ - Component.literal("Use this code to /link yourself on Discord:") - .append(Component.literal("$whitelistCode").withStyle { it.withItalic(true) }) + Component.literal(AstralBotTextConfig.LINK_COMMAND_MESSAGE.get().replace("{{code}}", "$whitelistCode")) }, false) return 0 } 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 e33eaf6..4078e0d 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -20,9 +20,18 @@ object AstralBotTextConfig { val RELOAD_ERROR: ForgeConfigSpec.ConfigValue val RELOAD_SUCCESS: ForgeConfigSpec.ConfigValue + val LINK_NO_MINECRAFT: ForgeConfigSpec.ConfigValue + val LINK_MINECRAFT_TAKEN: ForgeConfigSpec.ConfigValue + val LINK_DISCORD_TAKEN: ForgeConfigSpec.ConfigValue + val LINK_SUCCESSFUL: ForgeConfigSpec.ConfigValue + val LINK_ERROR: ForgeConfigSpec.ConfigValue + + val LINK_COMMAND_MESSAGE: ForgeConfigSpec.ConfigValue + val LINK_COMMAND_ALREADY_LINKED: ForgeConfigSpec.ConfigValue + init { val builder = ForgeConfigSpec.Builder() - val whitespaceRegex = Regex("\n[ \t]+"); + val whitespaceRegex = Regex("\n[ \t]+") GENERIC_ERROR = builder.comment("Generic error message sent to Discord") .define("genericError", "Something went wrong!") @@ -70,6 +79,49 @@ object AstralBotTextConfig { RELOAD_SUCCESS = builder.comment("Message sent to Discord after a successful reload") .define(mutableListOf("reload", "success"), "Reloaded commands for guild") + LINK_NO_MINECRAFT = + builder.comment(""" + Message for when there's no Minecraft account associated with the given Link code. + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "noMinecraft"), "Couldn't find Minecraft account to link.") + LINK_MINECRAFT_TAKEN = + builder.comment(""" + Message for when the Minecraft account is already linked. This should never happen under + normal circumstances. + The Minecraft username is referenced by {{name}} + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "minecaftTaken"), "Minecraft username {{name}} already linked.") + LINK_DISCORD_TAKEN = + builder.comment(""" + Message for when a Discord account is already linked. + The Discord user is referenced by {{name}} + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "discordTaken"), "{{name}} already linked.") + LINK_SUCCESSFUL = + builder.comment(""" + Message for when linking was successful. + The Minecraft usernames can be accessed via {{mc}}. The Discord user via {{dc}} + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "successful"), "Linked {{dc}} to Minecraft username {{mc}}.") + LINK_ERROR = + builder.comment(""" + Message for when linking failed for some reason. + The error message can be accessed via {{error}} + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "error"), "Failed to link: {{error}}") + + LINK_COMMAND_MESSAGE = + builder.comment(""" + The message sent to a Minecraft user that requested a link code. + The code is referenced via {{code}} + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "command", "message"), "Use this code to /link yourself on Discord: {{code}}") + LINK_COMMAND_ALREADY_LINKED = + builder.comment(""" + The message sent to a Minecraft user requesting a link code when they're already linked. + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("link", "command", "alreadyLinked"), "You're already linked!") + SPEC = builder.build() } } \ No newline at end of file From ea660f6cba9b97d6becefd90b92b522bdb9b9c3e Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Tue, 30 Jan 2024 13:23:32 +0100 Subject: [PATCH 14/35] Use generic text templates in Setup Commands --- .../erdragh/astralbot/commands/discord/SetupCommands.kt | 9 +++++---- .../dev/erdragh/astralbot/config/AstralBotTextConfig.kt | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt index ab95f4c..60518cc 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/SetupCommands.kt @@ -2,6 +2,7 @@ package dev.erdragh.astralbot.commands.discord import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.config.AstralBotTextConfig import dev.erdragh.astralbot.guild import dev.erdragh.astralbot.handlers.WhitelistHandler import dev.erdragh.astralbot.textChannel @@ -30,7 +31,7 @@ object ReloadCommand : HandledSlashCommand { event.deferReply(true).queue() val guild = event.guild if (guild == null) { - event.hook.setEphemeral(true).sendMessage("Failed to fetch Guild to refresh").queue() + event.hook.setEphemeral(true).sendMessage(AstralBotTextConfig.GENERIC_ERROR.get()).queue() return } CommandHandlingListener.updateCommands(guild) { msg -> @@ -86,7 +87,7 @@ object ChatSyncCommand : HandledSlashCommand { success = true } event.hook.setEphemeral(true) - .sendMessage(if (success) "Successfully set up chat synchronization" else "Something went wrong while setting up chat sync") + .sendMessage(if (success) AstralBotTextConfig.GENERIC_SUCCESS.get() else AstralBotTextConfig.GENERIC_ERROR.get()) .queue() } } @@ -112,7 +113,7 @@ object LinkRoleCommand : HandledSlashCommand { event.deferReply(true).queue() val role = event.getOptionsByType(OptionType.ROLE).findLast { it.name == OPTION_ROLE }?.asRole if (role !is Role) { - event.hook.setEphemeral(true).sendMessage("Failed to resolve role from command option").queue() + event.hook.setEphemeral(true).sendMessage(AstralBotTextConfig.GENERIC_ERROR.get()).queue() LOGGER.error("Failed to resolve role from command option") return } @@ -139,6 +140,6 @@ object LinkRoleCommand : HandledSlashCommand { } } - event.hook.setEphemeral(true).sendMessage("Set up role ${role.name} for linked members").queue() + event.hook.setEphemeral(true).sendMessage(AstralBotTextConfig.GENERIC_SUCCESS.get()).queue() } } \ No newline at end of file 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 4078e0d..893bc20 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -6,6 +6,7 @@ object AstralBotTextConfig { val SPEC: ForgeConfigSpec val GENERIC_ERROR: ForgeConfigSpec.ConfigValue + val GENERIC_SUCCESS: ForgeConfigSpec.ConfigValue val FAQ_ERROR: ForgeConfigSpec.ConfigValue val FAQ_NO_REGISTERED: ForgeConfigSpec.ConfigValue @@ -35,6 +36,8 @@ object AstralBotTextConfig { GENERIC_ERROR = builder.comment("Generic error message sent to Discord") .define("genericError", "Something went wrong!") + GENERIC_SUCCESS = builder.comment("Generic success message sent to Discord") + .define("genericSuccess", "Success!") FAQ_ERROR = builder.comment("Message sent to Discord if an error ocurrs during FAQ loading") .define(mutableListOf("faq", "error"), "Bot Error (Contact Bot Operator)") From 78e4b2e05c852fb6182e8236f5293029371f59b2 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Tue, 30 Jan 2024 13:28:47 +0100 Subject: [PATCH 15/35] Fix github workflow --- .github/workflows/build.yml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ea7d24..b90ca8d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,23 +30,18 @@ jobs: java-version: ${{ matrix.java }} distribution: 'temurin' - - name: echo ref - run: echo ${{github.ref}} - - - name: setup gradle with dependency graph + - name: Build with Gradle and generate dependency Graph if: ${{github.ref == 'refs/heads/main' && github.event_name != 'pull_request'}} uses: gradle/gradle-build-action@v2 - # with: - # dependency-graph: 'generate-and-submit' + with: + arguments: build + dependency-graph: 'generate-and-submit' - - name: setup gradle + - name: Build with Gradle if: ${{github.ref != 'refs/heads/main' || github.event_name == 'pull_request'}} uses: gradle/gradle-build-action@v2 - # with: - # dependency-graph: 'generate-and-upload' - - - name: gradle clean build - run: ./gradlew clean build + with: + arguments: build # - name: Capture Fabric Artifacts # if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS From 5db089fc6621aea7e15a3bf917b960f5452bf6d5 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Tue, 30 Jan 2024 13:42:22 +0100 Subject: [PATCH 16/35] Stop using deprecated Exposed select() API --- .../dev/erdragh/astralbot/handlers/WhitelistHandler.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt index 18fea9a..39ca415 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt @@ -4,6 +4,7 @@ import com.mojang.authlib.GameProfile import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.baseDirectory import dev.erdragh.astralbot.config.AstralBotConfig +import dev.erdragh.astralbot.handlers.WhitelistHandler.WhitelistedUser import net.dv8tion.jda.api.entities.User import net.minecraft.network.chat.Component import org.jetbrains.exposed.sql.* @@ -153,7 +154,7 @@ object WhitelistHandler { fun checkWhitelist(minecraftID: UUID): Long? { var result: Long? = null transaction { - val query = WhitelistedUser.select { WhitelistedUser.minecraftID eq minecraftID } + val query = WhitelistedUser.selectAll().where { WhitelistedUser.minecraftID eq minecraftID } result = if (query.empty()) null else query.iterator().next()[WhitelistedUser.discordID] } return result @@ -168,7 +169,7 @@ object WhitelistHandler { fun checkWhitelist(discordID: Long): UUID? { var result: UUID? = null transaction { - val query = WhitelistedUser.select { WhitelistedUser.discordID eq discordID } + val query = WhitelistedUser.selectAll().where { WhitelistedUser.discordID eq discordID } result = if (query.empty()) null else query.iterator().next()[WhitelistedUser.minecraftID] } return result From 8b7f16f9193eca160b00ac5340cf87a02cf2eb15 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Thu, 8 Feb 2024 11:10:51 +0100 Subject: [PATCH 17/35] Better exception handling for executing commands --- .../commands/discord/CommandHandlingListener.kt | 10 +++++++++- .../astralbot/commands/discord/DiscordCommands.kt | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt index 3f8cafc..9e2bd28 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/CommandHandlingListener.kt @@ -60,9 +60,11 @@ object CommandHandlingListener : ListenerAdapter() { * can't return anything because of its asynchronous nature */ fun updateCommands(guild: Guild, sendMessage: (msg: String) -> Unit) { + LOGGER.info("Reloading commands.") guild.retrieveCommands().submit().whenComplete { fetchedCommands, error -> if (error != null) { sendMessage(AstralBotTextConfig.RELOAD_ERROR.get().replace("{{error}}", error.localizedMessage)) + LOGGER.error("Couldn't reload commands", error) return@whenComplete } waitForSetup() @@ -70,6 +72,7 @@ object CommandHandlingListener : ListenerAdapter() { deletedCommands.forEach { it.get() } guild.updateCommands().addCommands(getEnabledCommands().map { it.command }).queue { sendMessage(AstralBotTextConfig.RELOAD_SUCCESS.get()) + LOGGER.info("Reloaded commands.") } } } @@ -83,7 +86,12 @@ object CommandHandlingListener : ListenerAdapter() { override fun onSlashCommandInteraction(event: SlashCommandInteractionEvent) { val usedCommand = getEnabledCommands().find { it.command.name == event.name } if (usedCommand != null) { - usedCommand.handle(event) + try { + usedCommand.handle(event) + } catch (e: Exception) { + LOGGER.error("Failed to execute command: ${event.name}", e) + event.hook.sendMessage(AstralBotTextConfig.GENERIC_ERROR.get()).queue() + } } else { event.reply(AstralBotTextConfig.GENERIC_ERROR.get()).queue() } diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt index a9d5a75..7554e71 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt @@ -7,6 +7,7 @@ import dev.erdragh.astralbot.minecraftHandler import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData +import kotlin.jvm.Throws /** * Array containing every single command AstralBot supports @@ -59,6 +60,7 @@ interface HandledSlashCommand { * @param event the event that is connected with the * issuing of the command */ + @Throws(Exception::class) fun handle(event: SlashCommandInteractionEvent) } From 96b305ce07d770e6e874b40d04953f203e35296f Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Thu, 8 Feb 2024 11:11:17 +0100 Subject: [PATCH 18/35] Remove stopping message (it produces an exception) --- common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt index c756ef5..08dea35 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt @@ -143,7 +143,6 @@ fun startAstralbot(server: MinecraftServer) { } fun stopAstralbot() { - if (!shuttingDown.get()) textChannel?.sendMessage("Server shutting down!")?.queue() LOGGER.info("Shutting down AstralBot") shuttingDown.set(true) if (baseDirectory != null) FAQHandler.stop() From c3f1af47d0ed4ae29a6fcdba9555dc34fd4951c0 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Thu, 8 Feb 2024 11:11:31 +0100 Subject: [PATCH 19/35] Add headpat command --- .../commands/discord/DiscordCommands.kt | 4 +- .../astralbot/commands/discord/FunCommands.kt | 49 ++++++++++++++++++ common/src/main/kotlin/module-info.java | 1 + common/src/main/resources/headpat.png | Bin 0 -> 2960 bytes 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt create mode 100644 common/src/main/resources/headpat.png diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt index 7554e71..9f78625 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/DiscordCommands.kt @@ -29,7 +29,9 @@ val allCommands = arrayOf( UptimeCommand, StopCommand, TPSCommand, - UsageCommand + UsageCommand, + // Fun commands + HeadpatCommand ) /** diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt new file mode 100644 index 0000000..a21ce7e --- /dev/null +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt @@ -0,0 +1,49 @@ +package dev.erdragh.astralbot.commands.discord + +import dev.erdragh.astralbot.config.AstralBotTextConfig +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.Commands +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData +import net.dv8tion.jda.api.utils.FileUpload +import java.awt.Color +import java.awt.image.BufferedImage +import java.io.ByteArrayOutputStream +import java.net.URL +import javax.imageio.ImageIO + +object HeadpatCommand : HandledSlashCommand { + private const val USER_OPTION = "user" + override val command: SlashCommandData = Commands.slash("headpat", "Headpats a user") + .addOption(OptionType.USER, USER_OPTION, "The user whose avatar will be headpat.", true) + + override fun handle(event: SlashCommandInteractionEvent) { + event.deferReply(false).queue() + + val user = event.getOption(USER_OPTION)?.asUser + if (user == null) { + event.hook.sendMessage("You have to specify a user to headpat.").queue() + return + } + + val headpatBase = this.javaClass.getResource("/headpat.png") + val headpatBaseImage = ImageIO.read(headpatBase) + + val url = URL(user.effectiveAvatarUrl) + val avatar = ImageIO.read(url) + val headpatImage = BufferedImage(headpatBaseImage.width, headpatBaseImage.height, BufferedImage.TYPE_INT_ARGB) + + val graphics = headpatImage.createGraphics() + + val xOffset = 20 + val yOffset = 20 + graphics.drawImage(avatar, xOffset, yOffset, headpatImage.width - xOffset, headpatImage.height - yOffset, Color(0, 0, 0, 0), null) + graphics.drawImage(headpatBaseImage, 0, 0, headpatBaseImage.width, headpatBaseImage.height, Color(0, 0, 0, 0), null) + + graphics.dispose() + val byteStream = ByteArrayOutputStream() + ImageIO.write(headpatImage, "png", byteStream) + event.hook.sendFiles(FileUpload.fromData(byteStream.toByteArray(), "headpat.png")).queue() + } + +} \ 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 f20fe66..d9bf252 100644 --- a/common/src/main/kotlin/module-info.java +++ b/common/src/main/kotlin/module-info.java @@ -23,4 +23,5 @@ // For accessing the config requires forgeconfigapiport.common; + requires java.desktop; } \ No newline at end of file diff --git a/common/src/main/resources/headpat.png b/common/src/main/resources/headpat.png new file mode 100644 index 0000000000000000000000000000000000000000..1e2763495537d787f2075e991257eac118cae8bf GIT binary patch literal 2960 zcmcIm_ct2~8;(+nqFm8Zb+1jRRijm^l-dz18e57sp{ho#;8x98wf9VHVkaLl6PsF< zs#R2}anTwjYJBeB@SX2H=Xsy=ocBG?Iq!LYd14@7T{adz761Uirmv@McFF1g;u`&B zXI*?deo1uRX1ZDc{3!p%rC@lWX{-qV)F-l@I$gcgT@WJ+o$*2PXh*|1h1f%=9B#+= zG?ewX;yduzrpkip{+8Ct{2qKUp)|X-G#j6vjL%M}!DfrgP8q1ktbgy`7!i=~W!aAnXpBZ+ zW85Z5v8nGIi!)wBpqoMUeaS9GqCx^|5gBUP`&o07qh1x%o_k;r~C`L{@3Ns z000Y{zP6@?zx{SL!jEqlsB`;9vViN2@$r-%wQKuu@qn1TWzqAC3()WRN=DoOO!B>Z z@cPGtt|fep_v?j@=5*}qT{9pw`kV=RVB2inZhGXlPbx^wf;VJf)@VGsB zkDrOU4Ix!h@q9}3Rd&;xN`v@-m5bG?jm|p$@IeRamTw`l*-ie|Q2g7X)<;N1J|a;C zy}kQ`FAxKyCP3`}iutD!(jSzM3_Qd6=P9*J3`qb+v@b{Ir!!#!!XnEAbv>Y zT4mqiAyrAnZi|IxSpK+mSr2{NIJA+~w@cx=iLYbTMcAg&2wAE~5&!C+tu-at_t{IH z|7mY|wJ@*v+S>Nyx1Cs`uV;n*MK4M@2qCWQPlYJcQQf~p1EQ>FMf?~>5_S?Y2ER88 zD-`s=W%QFqv{-=3yi-iik2~xswOB)@03q4mg?LYzsZ9;40$N5Tn5d$B;LwvGhr;jA zWb)d4;$hlTEP#F8-h{DNXd^Cb|XvUqlakuC?o+r(08OP8Wa-k zeQ+iHgGPXhtFJ1~6F&2V4_2*siX_-OjiNiOYrnhMRjX`$Koe}i824(qUo!Pu+{3Pd ztA-FvVGFf|QtcizAnp#Uv1(hZqOQ0$(y=-LrxV@cgeMd%F{Zm$NZ@)T3S#LQ;PUL9 zhsq$4v=E+gMJ2CxdbH>e%bXiO;L~m`OJnxdGWX>#*q!EN&8RNSwqmOO^;mHJu3t)t zVxCO*>qzj$82^Rh$o_= zy<{<-_6^Eq@BkF+WQ14*mECyu^w3t6`gH#-!r;R=Ze%Ps{y(B+BT^+TTnoKpCsK#< z^3+t_Q81l|o~-GE-`8WO4P2fiF-Xy<9NeXP_jh!(5P3@&(qT@fON%I8I>$)5o`1m9 z#aei$l5QIDJE5`L^-rsh%c=n;2QM$4;B_ATi#mg`CF7RAq?#^v{gjTiw}* zlNNReiV9o~eG8g?o+`I+@0t=Pn+n#BRSO=H&X2`4ETX$k9xvHiXPIu(u`;EY9zMl} zOY{lXO@@#Pesy~+e);mH*<+4)N_ToHv9L{v${Ee%ZD^2l?L43101CBG&A5HP;sxx;8KRinX%D)0L+?oAVtvI6elSCx7tglGxt=nu}ABc1hKNAn(mH1+CZF zLQMV$Eq-UPR2;MER)Z}#X#TpN({bwhe&*N*wrJ$=q|Qh66Caqu?OfuI~-$jYNZjdTf?F#o`=)IbqLnM$lR7XJ{w%3N)J2-}l4 z8rk;sqi`jic!Md+e_4K_D^Sph$}T}WbCx5odSXShEjEyV(gOpOcfjEPZ zbs9aL@&3)egRg&d-Wr}^R(xOCN{|@ph-3bW{&iSg93k{claSW1!)LY-ke*ZXAFbXA*t+j1l=&e0vI9Jzh3-CtXX zPcECHUq8i%>SrQ}ZWZ;0g@me}eeJ*hBuOB!p${p3kAufjiZYQ9I2fV^rxXVqafnm%-tCNm%Ywa zk(OtmxheJPo1ab~+B4I!oxeFp&72vI;jWTN7D3v$n1WLIiYD4_pnP~7Jt!k{ia<<*FPI8z$?s+{F%RlT+-&1Tw(N$61{5cYO{ z%MqTA*xNm#*{6iq)P*EHP~KSsl+aJMQlT%BmpRFcXEm~>I4*TY7Y7!RLW_sQlsm(S z@2P@v4TH9v?0?4em%o2R%jo>+f+^Q5v&o->S@5WdCbK3-_R8_%+&+a133dWirnO$n zj8>R&=5x=XwVGJAOYhbyV4V}_bNDGxtKx=-8-jb9JY8Cr)E&w_30QVeHN(6sb| zyCu?pgV$n~2W}JHf`3^TJp`F$5{C0u-uQ5f1^6l&07@RPUkyf|5^HX$IGokkn@2_{ zF>0Ug-34!3G~G!(x)u=RGwEe1(|v$>`!J1i($-ZNw&0pSCh0vC{oa9ZR$mG#um0#H zr>(<)mV zv(xnrSLJ+t)*1Xnr)T&jSX6BI)r*hjpbL&gC^;;a%SA2H$H-@J<$k;G4+9-?p)1Q^ zbV9@i409oYHR7a55jhkDlncR>Bl;v Date: Thu, 8 Feb 2024 11:15:09 +0100 Subject: [PATCH 20/35] Optimize headpat command --- .../astralbot/commands/discord/FunCommands.kt | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt index a21ce7e..dcebd8e 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt @@ -1,6 +1,5 @@ package dev.erdragh.astralbot.commands.discord -import dev.erdragh.astralbot.config.AstralBotTextConfig import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent import net.dv8tion.jda.api.interactions.commands.OptionType import net.dv8tion.jda.api.interactions.commands.build.Commands @@ -16,6 +15,7 @@ object HeadpatCommand : HandledSlashCommand { private const val USER_OPTION = "user" override val command: SlashCommandData = Commands.slash("headpat", "Headpats a user") .addOption(OptionType.USER, USER_OPTION, "The user whose avatar will be headpat.", true) + val headpatBaseImage = ImageIO.read(this.javaClass.getResource("/headpat.png")) override fun handle(event: SlashCommandInteractionEvent) { event.deferReply(false).queue() @@ -26,9 +26,6 @@ object HeadpatCommand : HandledSlashCommand { return } - val headpatBase = this.javaClass.getResource("/headpat.png") - val headpatBaseImage = ImageIO.read(headpatBase) - val url = URL(user.effectiveAvatarUrl) val avatar = ImageIO.read(url) val headpatImage = BufferedImage(headpatBaseImage.width, headpatBaseImage.height, BufferedImage.TYPE_INT_ARGB) @@ -37,8 +34,24 @@ object HeadpatCommand : HandledSlashCommand { val xOffset = 20 val yOffset = 20 - graphics.drawImage(avatar, xOffset, yOffset, headpatImage.width - xOffset, headpatImage.height - yOffset, Color(0, 0, 0, 0), null) - graphics.drawImage(headpatBaseImage, 0, 0, headpatBaseImage.width, headpatBaseImage.height, Color(0, 0, 0, 0), null) + graphics.drawImage( + avatar, + xOffset, + yOffset, + headpatImage.width - xOffset, + headpatImage.height - yOffset, + Color(0, 0, 0, 0), + null + ) + graphics.drawImage( + headpatBaseImage, + 0, + 0, + headpatBaseImage.width, + headpatBaseImage.height, + Color(0, 0, 0, 0), + null + ) graphics.dispose() val byteStream = ByteArrayOutputStream() From d2af63f61e77fe1a664380321d6c0108f763bd34 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Fri, 9 Feb 2024 08:34:05 +0100 Subject: [PATCH 21/35] Make headpatBaseImage private --- .../dev/erdragh/astralbot/commands/discord/FunCommands.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt index dcebd8e..3a38048 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/FunCommands.kt @@ -15,7 +15,7 @@ object HeadpatCommand : HandledSlashCommand { private const val USER_OPTION = "user" override val command: SlashCommandData = Commands.slash("headpat", "Headpats a user") .addOption(OptionType.USER, USER_OPTION, "The user whose avatar will be headpat.", true) - val headpatBaseImage = ImageIO.read(this.javaClass.getResource("/headpat.png")) + private val headpatBaseImage = ImageIO.read(this.javaClass.getResource("/headpat.png")) override fun handle(event: SlashCommandInteractionEvent) { event.deferReply(false).queue() From ef176d6514c84d99edc0fbe594455a92e344d253 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Fri, 9 Feb 2024 08:53:37 +0100 Subject: [PATCH 22/35] Update gradle and Exposed --- .../kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt | 3 +-- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt index 39ca415..61ad17c 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt @@ -4,7 +4,6 @@ import com.mojang.authlib.GameProfile import dev.erdragh.astralbot.LOGGER import dev.erdragh.astralbot.baseDirectory import dev.erdragh.astralbot.config.AstralBotConfig -import dev.erdragh.astralbot.handlers.WhitelistHandler.WhitelistedUser import net.dv8tion.jda.api.entities.User import net.minecraft.network.chat.Component import org.jetbrains.exposed.sql.* @@ -229,7 +228,7 @@ object WhitelistHandler { * @return the login code of the given user or `null` if there isn't * one for them yet. */ - fun getWhitelistCode(minecraftID: UUID): Int? = synchronized(loginCodes) { + private fun getWhitelistCode(minecraftID: UUID): Int? = synchronized(loginCodes) { return loginCodes.entries.find { it.value == minecraftID }?.key } diff --git a/gradle.properties b/gradle.properties index ceed9f1..114aaad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,5 +18,5 @@ forgeConfigAPIVersion=8.0.0 jdaVersion=5.0.0-beta.20 # Database Interactions -exposedVersion=0.46.0 +exposedVersion=0.47.0 sqliteJDBCVersion=3.44.1.0 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2bbac7d..e846b64 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file From 93ff88c52111b4ccff9c06fcb1f25a94a868a0f2 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Tue, 20 Feb 2024 10:18:01 +0100 Subject: [PATCH 23/35] use Collections.synchronizedMap --- .../dev/erdragh/astralbot/handlers/WhitelistHandler.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt index 61ad17c..b9033ee 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/WhitelistHandler.kt @@ -41,7 +41,7 @@ object WhitelistHandler { // Users whose code it is. Storing these in memory only // Results in users getting a new code when the server // restarts, which is acceptable in my opinion. - private val loginCodes = HashMap() + private val loginCodes = Collections.synchronizedMap(HashMap()) // The random used to generate the login codes. // I'm using .asKotlinRandom() here because the // default Kotlin Random constructor wants a seed. @@ -185,9 +185,7 @@ object WhitelistHandler { // so this DOS won't cause an infinite loop. Such a DOS may still cause // Players to not be able to whitelist. // while (loginCodes.containsKey(whitelistCode)) whitelistCode = loginRandom.nextInt(loginCodeRange) - synchronized(loginCodes) { - loginCodes[whitelistCode] = minecraftID - } + loginCodes[whitelistCode] = minecraftID return whitelistCode } @@ -228,7 +226,7 @@ object WhitelistHandler { * @return the login code of the given user or `null` if there isn't * one for them yet. */ - private fun getWhitelistCode(minecraftID: UUID): Int? = synchronized(loginCodes) { + private fun getWhitelistCode(minecraftID: UUID): Int? { return loginCodes.entries.find { it.value == minecraftID }?.key } @@ -240,7 +238,7 @@ object WhitelistHandler { * link code or `null` if nobody is associated with * the given code. */ - fun getPlayerFromCode(code: Int): UUID? = synchronized(loginCodes) { + fun getPlayerFromCode(code: Int): UUID? { return loginCodes[code] } From b6b5653591308f4c28f74ca8ce5fd238ae970733 Mon Sep 17 00:00:00 2001 From: Jan Bayer Date: Tue, 20 Feb 2024 10:40:51 +0100 Subject: [PATCH 24/35] also format stickers --- .../dev/erdragh/astralbot/handlers/MinecraftHandler.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 5f41689..fdf3ab2 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -307,7 +307,7 @@ 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 > 0 && message.contentDisplay.isNotBlank()) comp.append("\n ") + if (message.embeds.size + message.attachments.size + message.stickers.size > 0 && message.contentDisplay.isNotBlank()) comp.append("\n ") var i = 0 message.embeds.forEach { if (i++ != 0) comp.append(", ") @@ -321,6 +321,14 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() } comp.append(formatEmbed(it.fileName, it.url)) } + message.stickers.forEach { + if (i != 0) { + comp.append(", ") + } else { + i++ + } + comp.append(formatEmbed(it.name, it.icon.url)) + } return comp } From 3edfbc11a2d37f3c34e7bb562a291742d9511bee Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 15:46:28 +0100 Subject: [PATCH 25/35] Allow unlinking other people --- .../commands/discord/LinkingCommands.kt | 15 ++++++++++++--- .../astralbot/config/AstralBotTextConfig.kt | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt index bac3b50..e8dbe39 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt @@ -97,16 +97,25 @@ object LinkCommand : HandledSlashCommand { * @author Erdragh */ object UnlinkCommand : HandledSlashCommand { + private const val OPTION_USER = "user" override val command: SlashCommandData = Commands.slash("unlink", "Unlinks your Minecraft account with your Discord account") + .addOption(OptionType.USER, OPTION_USER, "The user that will be unlinked. If not provided, the command issuer will be used.", false) override fun handle(event: SlashCommandInteractionEvent) { // DB Interactions could take a while, so the reply needs to get deferred event.deferReply(true).queue() + val user = event.getOption(OPTION_USER)?.asUser - WhitelistHandler.unWhitelist(event.user) - - event.hook.setEphemeral(true).sendMessageFormat("Unlinked %s", event.user).queue() + when { + user == null -> WhitelistHandler.unWhitelist(event.user) + event.member?.hasPermission(Permission.MODERATE_MEMBERS) == true -> WhitelistHandler.unWhitelist(user) + else -> { + event.hook.setEphemeral(true).sendMessage(AstralBotTextConfig.UNLINK_NOPERMS.get()).queue() + return + } + } + event.hook.setEphemeral(true).sendMessageFormat(AstralBotTextConfig.UNLINK_UNLINKED.get().replace("{{name}}", (user ?: event.user).effectiveName)).queue() } } 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 893bc20..6f46b95 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotTextConfig.kt @@ -30,6 +30,9 @@ object AstralBotTextConfig { val LINK_COMMAND_MESSAGE: ForgeConfigSpec.ConfigValue val LINK_COMMAND_ALREADY_LINKED: ForgeConfigSpec.ConfigValue + val UNLINK_UNLINKED: ForgeConfigSpec.ConfigValue + val UNLINK_NOPERMS: ForgeConfigSpec.ConfigValue + init { val builder = ForgeConfigSpec.Builder() val whitespaceRegex = Regex("\n[ \t]+") @@ -125,6 +128,19 @@ object AstralBotTextConfig { """.replace(whitespaceRegex, "\n")) .define(mutableListOf("link", "command", "alreadyLinked"), "You're already linked!") + UNLINK_UNLINKED = + builder.comment(""" + The message sent to the /unlink issuer on successful unlink. The unlinked + user's name can be referenced with {{name}}. + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("unlink", "unlinked"), "Unlinked {{name}}") + UNLINK_NOPERMS = + builder.comment(""" + The message sent to the /unlink issuer when the issuer doesn't have the permissions + to unlink another user. + """.replace(whitespaceRegex, "\n")) + .define(mutableListOf("unlink", "noPerms"), "You don't have the permissions to unlink other users") + SPEC = builder.build() } } \ No newline at end of file From d6ffbb680a0d8feb37838f0c2aae1444411e6b9f Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 15:50:59 +0100 Subject: [PATCH 26/35] Fix link command discord user formatting --- .../commands/discord/LinkingCommands.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt index e8dbe39..53af4e0 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/commands/discord/LinkingCommands.kt @@ -27,6 +27,8 @@ object LinkCommand : HandledSlashCommand { // Specifying option names as constants to prevent typos private const val OPTION_CODE = "code" + private const val UNNAMED_ACCOUNT = "Unnamed Account"; + override val command: SlashCommandData = Commands.slash("link", "Links your Minecraft account with your Discord account") .addOption(OptionType.NUMBER, OPTION_CODE, "your personal link code", true) @@ -55,13 +57,13 @@ object LinkCommand : HandledSlashCommand { event.hook.setEphemeral(true) .sendMessageFormat( AstralBotTextConfig.LINK_MINECRAFT_TAKEN.get() - .replace("{{name}}", minecraftUser?.name ?: "Unnamed Account") + .replace("{{name}}", minecraftUser?.name ?: UNNAMED_ACCOUNT) ) .queue() } else if (WhitelistHandler.checkWhitelist(event.user.idLong) != null) { event.hook.setEphemeral(true).sendMessageFormat( AstralBotTextConfig.LINK_DISCORD_TAKEN.get() - .replace("{{name}}", event.member?.toString() ?: "Unnamed Account") + .replace("{{name}}", event.member?.asMention ?: UNNAMED_ACCOUNT) ).queue() } else { WhitelistHandler.whitelist(event.user, minecraftID) @@ -70,14 +72,14 @@ object LinkCommand : HandledSlashCommand { try { guild?.addRoleToMember(event.user, it)?.queue() } catch (e: Exception) { - LOGGER.error("Failed to add role ${it.name} to member ${event.user.effectiveName}", e) + LOGGER.error("Failed to add role ${it.name} to member ${event.user.asMention}", e) } } event.hook.setEphemeral(true) .sendMessageFormat( AstralBotTextConfig.LINK_SUCCESSFUL.get() - .replace("{{dc}}", event.member?.toString() ?: "Unnamed Account") - .replace("{{mc}}", minecraftUser?.name ?: "Unnamed Account") + .replace("{{dc}}", event.member?.asMention ?: UNNAMED_ACCOUNT) + .replace("{{mc}}", minecraftUser?.name ?: UNNAMED_ACCOUNT) ).queue() } } catch (e: Exception) { @@ -115,7 +117,7 @@ object UnlinkCommand : HandledSlashCommand { return } } - event.hook.setEphemeral(true).sendMessageFormat(AstralBotTextConfig.UNLINK_UNLINKED.get().replace("{{name}}", (user ?: event.user).effectiveName)).queue() + event.hook.setEphemeral(true).sendMessageFormat(AstralBotTextConfig.UNLINK_UNLINKED.get().replace("{{name}}", (user ?: event.user).asMention)).queue() } } @@ -195,12 +197,12 @@ object LinkCheckCommand : HandledSlashCommand, MinecraftUserAutocompleteCommand( val minecraftUser = minecraftHandler?.byUUID(minecraftID) if (minecraftUser != null) { event.hook.setEphemeral(true).sendMessageFormat( - "%s is linked to Minecraft username %s", discordUser, minecraftUser.name + "%s is linked to Minecraft username %s", discordUser.asMention, minecraftUser.name ).queue() return } } - event.hook.setEphemeral(true).sendMessageFormat("%s not linked to any Minecraft username", discordUser).queue() + event.hook.setEphemeral(true).sendMessageFormat("%s not linked to any Minecraft username", discordUser.asMention).queue() } override fun handle(event: SlashCommandInteractionEvent) { From 2ac02b8c23bad125962d07a2c5a4603c9fd93ffc Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 15:57:35 +0100 Subject: [PATCH 27/35] Capture artifacts in build step --- .github/workflows/build.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b90ca8d..5d2b23f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,15 +43,15 @@ jobs: with: arguments: build -# - name: Capture Fabric Artifacts -# if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS -# uses: actions/upload-artifact@v3 -# with: -# name: Fabric Artifacts -# path: fabric/build/libs -# - name: Capture Forge Artifacts -# if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS -# uses: actions/upload-artifact@v3 -# with: -# name: Forge Artifacts -# path: forge/build/libs \ No newline at end of file + - name: Capture Fabric Artifacts + if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v3 + with: + name: Fabric Artifacts + path: fabric/build/libs + - name: Capture Forge Artifacts + if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v3 + with: + name: Forge Artifacts + path: forge/build/libs \ No newline at end of file From 13c04d6ae7ae4ed00088bfdce58d59bcd396960f Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 16:41:11 +0100 Subject: [PATCH 28/35] Prepare for auto publishing --- .github/workflows/build.yml | 128 +++++++++++++++++++++++++++++++++--- Changelog.md | 30 +++++++++ build.gradle.kts | 7 ++ 3 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 Changelog.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5d2b23f..a7e7c6e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,9 +1,9 @@ name: build on: push: - branches: [ "main", "develop" ] + branches: [ "main", "develop", "version/*" ] pull_request: - branches: [ "main", "develop" ] + branches: [ "main", "develop", "version/*" ] permissions: contents: write @@ -17,7 +17,7 @@ jobs: 17, # Current Java LTS & minimum supported by Minecraft ] # and run on Linux - os: [ubuntu-latest] + os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} steps: @@ -43,15 +43,127 @@ jobs: with: arguments: build + - name: Prepare Changelog + run: ./gradlew -q prepareChangelog > prepared_changelog.md + - name: Capture Fabric Artifacts if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: Fabric Artifacts + name: build-fabric path: fabric/build/libs - name: Capture Forge Artifacts if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 + with: + name: build-forge + path: forge/build/libs + - name: Capture Changelog + if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v4 + with: + name: Changelog + path: prepared_changelog.md + publish: + needs: + - build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download Fabric artifacts + uses: actions/download-artifact@v4 + with: + path: build/fabric + pattern: build-fabric + merge-multiple: true + - name: Download Forge artifacts + uses: actions/download-artifact@v4 + with: + path: build/forge + pattern: build-forge + merge-multiple: true + - name: Download Changelog + uses: actions/download-artifact@v4 + with: + path: prepared_changelog.md + pattern: Changelog + + - name: List build artifacts + run: ls -R fabric forge + - name: Show Changelog + run: cat prepared_changelog.md + + - name: Get Version and Platform + id: properties + uses: christian-draeger/read-properties@1.1.1 with: - name: Forge Artifacts - path: forge/build/libs \ No newline at end of file + path: "./gradle.properties" + properties: "version enabledPlatforms minecraftVersion" + + - name: Upload Forge Releases (Curse/Modrinth/Github) + id: forge_release + if: contains(steps.properties.outputs.enabledPlatforms, 'forge') + uses: Kir-Antipov/mc-publish@v3.3.0 + with: + curseforge-id: ${{ vars.CURSE_ID }} + curseforge-token: ${{ secrets.CURSE_TOKEN }} + + modrinth-id: ${{ vars.MODRINTH_ID }} + modrinth-token: ${{ secrets.MODRINTH_TOKEN }} + + github-tag: "mc${{ steps.properties.outputs.minecraftVersion }}-${{ steps.properties.output.version }}" + github-commitish: "version/${{ steps.properties.outputs.minecraftVersion }}" + github-token: ${{ secrets.GITHUB_TOKEN }} + + files: ./build/forge/!(*-@(dev|sources|dev-shadow)).jar + name: "AstralBot ${{ steps.properties.outputs.version }} Forge ${{ steps.properties.output.minecraftVersion }}" + version: ${{ steps.properties.outputs.version }} + version-type: release + changelog-file: prepared_changelog.md + loaders: forge + game-versions: ${{ steps.properties.outputs.minecraftVersion }} + version-resolver: exact + + curseforge-dependencies: | + sqlite-jdbc(optional) + kotlin-for-forge(required) + modrinth-dependencies: | + sqlite-jdbc(optional) + kotlin-for-forge(required) + + - name: Upload Fabric Releases (Curse/Modrinth/Github) + id: fabric_release + if: contains(steps.properties.outputs.enabledPlatforms, 'fabric') + uses: Kir-Antipov/mc-publish@v3.3.0 + with: + curseforge-id: ${{ vars.CURSE_ID }} + curseforge-token: ${{ secrets.CURSE_TOKEN }} + + modrinth-id: ${{ vars.MODRINTH_ID }} + modrinth-token: ${{ secrets.MODRINTH_TOKEN }} + + github-tag: "mc${{ steps.properties.outputs.minecraftVersion }}-${{ steps.properties.output.version }}" + github-commitish: "version/${{ steps.properties.outputs.minecraftVersion }}" + github-token: ${{ secrets.GITHUB_TOKEN }} + + files: ./build/fabric/!(*-@(dev|sources|dev-shadow)).jar + name: "AstralBot ${{ steps.properties.outputs.version }} Fabric ${{ steps.properties.output.minecraftVersion }}" + version: ${{ steps.properties.outputs.version }} + version-type: release + changelog-file: prepared_changelog.md + loaders: fabric + game-versions: ${{ steps.properties.outputs.minecraftVersion }} + version-resolver: exact + + curseforge-dependencies: | + fabric-api(required) + fabric-language-kotlin(required) + sqlite-jdbc(optional) + ledger(optional) + modrinth-dependencies: | + fabric-api(required) + fabric-language-kotlin(required) + sqlite-jdbc(optional) + ledger(optional) \ No newline at end of file diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..4f1f34a --- /dev/null +++ b/Changelog.md @@ -0,0 +1,30 @@ +# 1.2.0 +- Unlink other Discord users with permissions +- Customizable text for basically anything +- `/headpat` command +- More graceful shutdown +- `/link` as a Minecraft command for people who want to be linked but are already whitelisted by another way +- Exception handling for commands server side, resulting in less commands that don't get a response + +# 1.1.0 +- Management Commands: + - `/tps` + - `/usage` + - `/stop` + - `/uptime` +- Stop Minecraft usernames being formatted as Markdown on Discord +- Rework enabled commands config + +# 1.0.2 +- Solve Compatibility issue with [GML](https://modrinth.com/mod/gml) on Forge +- Fix empty whitelist Database handling + +# 1.0.1 +- Config option to disable `/unlink` +- Async bot startup +- Make `/reload` command remove no longer registered commands +- Update dependencies +- Make SQLite driver an external dependency, allowing compatibility with [Ledger](https://modrinth.com/mod/ledger) + +# 1.0.0 +Initial Release \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 0b746c8..ab05878 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import dev.architectury.plugin.ArchitectPluginExtension import net.fabricmc.loom.api.LoomGradleExtensionAPI import net.fabricmc.loom.task.RemapJarTask +import java.nio.charset.StandardCharsets plugins { // This is an Architectury repository, as such the relevant plugins are needed @@ -218,4 +219,10 @@ subprojects { kotlin { jvmToolchain(17) +} + +tasks.create("prepareChangelog") { + var changelog = File("Changelog.md").readText(StandardCharsets.UTF_8) + changelog = changelog.replace(Regex("[^^](#(#|\\n|.)+)|(^#.+)"), "") + println(changelog.trim()) } \ No newline at end of file From ff5a4b46265e0cbca0fe726058f1d04cf190e335 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 16:45:20 +0100 Subject: [PATCH 29/35] Slight fixes to the build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7e7c6e..3a02ff7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,11 +87,11 @@ jobs: - name: Download Changelog uses: actions/download-artifact@v4 with: - path: prepared_changelog.md + path: . pattern: Changelog - name: List build artifacts - run: ls -R fabric forge + run: ls -R build - name: Show Changelog run: cat prepared_changelog.md From 483273391e39568d9cfc9e22ef5431bb87b58fb6 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 16:49:15 +0100 Subject: [PATCH 30/35] Fix changelog download --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a02ff7..3e9bb8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS uses: actions/upload-artifact@v4 with: - name: Changelog + name: prepared_changelog.md path: prepared_changelog.md publish: needs: @@ -88,7 +88,7 @@ jobs: uses: actions/download-artifact@v4 with: path: . - pattern: Changelog + pattern: prepared_changelog.md - name: List build artifacts run: ls -R build From 68c39d6e1432b909e1a47c2340cc4ec84ed5f7f7 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 17:01:23 +0100 Subject: [PATCH 31/35] Fix changelog download again --- .github/workflows/build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e9bb8c..712a1a0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS uses: actions/upload-artifact@v4 with: - name: prepared_changelog.md + name: build-changelog path: prepared_changelog.md publish: needs: @@ -87,13 +87,13 @@ jobs: - name: Download Changelog uses: actions/download-artifact@v4 with: - path: . - pattern: prepared_changelog.md + path: build/changelog + pattern: build-changelog - name: List build artifacts run: ls -R build - name: Show Changelog - run: cat prepared_changelog.md + run: cat build/changelog/prepared_changelog.md - name: Get Version and Platform id: properties @@ -121,7 +121,7 @@ jobs: name: "AstralBot ${{ steps.properties.outputs.version }} Forge ${{ steps.properties.output.minecraftVersion }}" version: ${{ steps.properties.outputs.version }} version-type: release - changelog-file: prepared_changelog.md + changelog-file: build/changelog/prepared_changelog.md loaders: forge game-versions: ${{ steps.properties.outputs.minecraftVersion }} version-resolver: exact @@ -152,7 +152,7 @@ jobs: name: "AstralBot ${{ steps.properties.outputs.version }} Fabric ${{ steps.properties.output.minecraftVersion }}" version: ${{ steps.properties.outputs.version }} version-type: release - changelog-file: prepared_changelog.md + changelog-file: build/changelog/prepared_changelog.md loaders: fabric game-versions: ${{ steps.properties.outputs.minecraftVersion }} version-resolver: exact From 6b3e9f6b0624127473ae6cc7e66910cfe8bfc7c7 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 17:08:33 +0100 Subject: [PATCH 32/35] Fix changelog download again x2 --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 712a1a0..121a683 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,13 +87,13 @@ jobs: - name: Download Changelog uses: actions/download-artifact@v4 with: - path: build/changelog + path: . pattern: build-changelog - name: List build artifacts run: ls -R build - name: Show Changelog - run: cat build/changelog/prepared_changelog.md + run: cat build-changelog/prepared_changelog.md - name: Get Version and Platform id: properties @@ -121,7 +121,7 @@ jobs: name: "AstralBot ${{ steps.properties.outputs.version }} Forge ${{ steps.properties.output.minecraftVersion }}" version: ${{ steps.properties.outputs.version }} version-type: release - changelog-file: build/changelog/prepared_changelog.md + changelog-file: build-changelog/prepared_changelog.md loaders: forge game-versions: ${{ steps.properties.outputs.minecraftVersion }} version-resolver: exact @@ -152,7 +152,7 @@ jobs: name: "AstralBot ${{ steps.properties.outputs.version }} Fabric ${{ steps.properties.output.minecraftVersion }}" version: ${{ steps.properties.outputs.version }} version-type: release - changelog-file: build/changelog/prepared_changelog.md + changelog-file: build-changelog/prepared_changelog.md loaders: fabric game-versions: ${{ steps.properties.outputs.minecraftVersion }} version-resolver: exact From d77bf2ab008e7476290292837b0c04043b9e79f4 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 17:14:36 +0100 Subject: [PATCH 33/35] Prepare for actually using publish step --- .github/workflows/build.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 121a683..69756e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,12 @@ on: branches: [ "main", "develop", "version/*" ] pull_request: branches: [ "main", "develop", "version/*" ] + workflow_dispatch: + inputs: + publish: + description: Publish to Modrinth and CurseForge + required: true + default: "false" permissions: contents: write @@ -65,6 +71,7 @@ jobs: name: build-changelog path: prepared_changelog.md publish: + if: ${{ github.event.inputs.publish }} needs: - build runs-on: ubuntu-latest @@ -124,7 +131,6 @@ jobs: changelog-file: build-changelog/prepared_changelog.md loaders: forge game-versions: ${{ steps.properties.outputs.minecraftVersion }} - version-resolver: exact curseforge-dependencies: | sqlite-jdbc(optional) @@ -155,7 +161,6 @@ jobs: changelog-file: build-changelog/prepared_changelog.md loaders: fabric game-versions: ${{ steps.properties.outputs.minecraftVersion }} - version-resolver: exact curseforge-dependencies: | fabric-api(required) From bf166510cab53ab9a235f052cd1083c085075691 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Wed, 21 Feb 2024 17:25:33 +0100 Subject: [PATCH 34/35] Use GH_TOKEN --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69756e3..a04596c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -122,7 +122,7 @@ jobs: github-tag: "mc${{ steps.properties.outputs.minecraftVersion }}-${{ steps.properties.output.version }}" github-commitish: "version/${{ steps.properties.outputs.minecraftVersion }}" - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GH_TOKEN }} files: ./build/forge/!(*-@(dev|sources|dev-shadow)).jar name: "AstralBot ${{ steps.properties.outputs.version }} Forge ${{ steps.properties.output.minecraftVersion }}" @@ -152,7 +152,7 @@ jobs: github-tag: "mc${{ steps.properties.outputs.minecraftVersion }}-${{ steps.properties.output.version }}" github-commitish: "version/${{ steps.properties.outputs.minecraftVersion }}" - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GH_TOKEN }} files: ./build/fabric/!(*-@(dev|sources|dev-shadow)).jar name: "AstralBot ${{ steps.properties.outputs.version }} Fabric ${{ steps.properties.output.minecraftVersion }}" From f0b6191e33bff090a3a44d103b1028048bea57bf Mon Sep 17 00:00:00 2001 From: Erdragh Date: Thu, 22 Feb 2024 16:43:50 +0100 Subject: [PATCH 35/35] Don't automatically publish GitHub release --- .github/workflows/build.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a04596c..9606a4f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -120,10 +120,6 @@ jobs: modrinth-id: ${{ vars.MODRINTH_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} - github-tag: "mc${{ steps.properties.outputs.minecraftVersion }}-${{ steps.properties.output.version }}" - github-commitish: "version/${{ steps.properties.outputs.minecraftVersion }}" - github-token: ${{ secrets.GH_TOKEN }} - files: ./build/forge/!(*-@(dev|sources|dev-shadow)).jar name: "AstralBot ${{ steps.properties.outputs.version }} Forge ${{ steps.properties.output.minecraftVersion }}" version: ${{ steps.properties.outputs.version }} @@ -150,10 +146,6 @@ jobs: modrinth-id: ${{ vars.MODRINTH_ID }} modrinth-token: ${{ secrets.MODRINTH_TOKEN }} - github-tag: "mc${{ steps.properties.outputs.minecraftVersion }}-${{ steps.properties.output.version }}" - github-commitish: "version/${{ steps.properties.outputs.minecraftVersion }}" - github-token: ${{ secrets.GH_TOKEN }} - files: ./build/fabric/!(*-@(dev|sources|dev-shadow)).jar name: "AstralBot ${{ steps.properties.outputs.version }} Fabric ${{ steps.properties.output.minecraftVersion }}" version: ${{ steps.properties.outputs.version }}