From 416ff1623df04c8f5f0ad35629487932305b86b8 Mon Sep 17 00:00:00 2001 From: Silly Date: Sun, 6 Oct 2024 16:03:43 -0400 Subject: [PATCH 1/6] Make headpats animated :3 --- .../astralbot/commands/discord/FunCommands.kt | 77 ++++++++++-------- .../dev/erdragh/astralbot/util/GifWriter.kt | 70 ++++++++++++++++ common/src/main/resources/headpat.png | Bin 2960 -> 0 bytes common/src/main/resources/headpat/pet0.gif | Bin 0 -> 2764 bytes common/src/main/resources/headpat/pet1.gif | Bin 0 -> 3042 bytes common/src/main/resources/headpat/pet2.gif | Bin 0 -> 2934 bytes common/src/main/resources/headpat/pet3.gif | Bin 0 -> 2936 bytes common/src/main/resources/headpat/pet4.gif | Bin 0 -> 2598 bytes 8 files changed, 115 insertions(+), 32 deletions(-) create mode 100644 common/src/main/kotlin/dev/erdragh/astralbot/util/GifWriter.kt delete mode 100644 common/src/main/resources/headpat.png create mode 100644 common/src/main/resources/headpat/pet0.gif create mode 100644 common/src/main/resources/headpat/pet1.gif create mode 100644 common/src/main/resources/headpat/pet2.gif create mode 100644 common/src/main/resources/headpat/pet3.gif create mode 100644 common/src/main/resources/headpat/pet4.gif 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 3a38048..3a50e4a 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,11 +1,13 @@ package dev.erdragh.astralbot.commands.discord +import dev.erdragh.astralbot.util.GifWriter 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.Graphics2D +import java.awt.RenderingHints import java.awt.image.BufferedImage import java.io.ByteArrayOutputStream import java.net.URL @@ -15,7 +17,13 @@ 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) - private val headpatBaseImage = ImageIO.read(this.javaClass.getResource("/headpat.png")) + + private val ANIMATION = floatArrayOf(-.05f, .1f, .2f, .19f, .1f) + private val FRAMES: Array = Array(5) { ImageIO.read(this::class.java.getResourceAsStream("/headpat/pet$it.gif")) } + private val RENDERING_HINTS = RenderingHints(mapOf( + RenderingHints.KEY_ANTIALIASING to RenderingHints.VALUE_ANTIALIAS_ON, + RenderingHints.KEY_RENDERING to RenderingHints.VALUE_RENDER_QUALITY + )) override fun handle(event: SlashCommandInteractionEvent) { event.deferReply(false).queue() @@ -28,35 +36,40 @@ object HeadpatCommand : HandledSlashCommand { 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() - } + val stream: ByteArrayOutputStream + + ByteArrayOutputStream().use { output -> + ImageIO.createImageOutputStream(output).use { out -> + GifWriter( + out, BufferedImage.TYPE_INT_ARGB, + timeBetweenFramesMS = 50, loopContinuously = true, transparent = true + ).use { gifWriter -> + for (i in FRAMES.indices) { + val frame = BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB) + val graphics = frame.graphics as Graphics2D + // set rendering hints to slightly improve quality + graphics.setRenderingHints(RENDERING_HINTS) + + val offset1 = Math.round(ANIMATION[i] * 64) + val offset2 = Math.round((-ANIMATION[i]) * 64) + + // draw avatar + graphics.drawImage(avatar, 2, 32 + offset1, 128 - offset2, 128 - 32 - offset1, null) + // draw hand + graphics.drawImage(FRAMES[i], 0, 0, 128, 128, null) + + gifWriter.write(frame) + + graphics.dispose() + } + } + out.flush() + + stream = output + } + } + + event.hook.sendFiles(FileUpload.fromData(stream.toByteArray(), "headpat.gif")).queue() + } } \ No newline at end of file diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/util/GifWriter.kt b/common/src/main/kotlin/dev/erdragh/astralbot/util/GifWriter.kt new file mode 100644 index 0000000..1b61f5a --- /dev/null +++ b/common/src/main/kotlin/dev/erdragh/astralbot/util/GifWriter.kt @@ -0,0 +1,70 @@ +package dev.erdragh.astralbot.util + +import java.awt.image.RenderedImage +import java.io.IOException +import javax.imageio.* +import javax.imageio.metadata.IIOMetadata +import javax.imageio.metadata.IIOMetadataNode +import javax.imageio.stream.ImageOutputStream + +/** + * A simple utility for creating gifs. + * + * @author femmeromantic + */ +class GifWriter( + os: ImageOutputStream?, imageType: Int, + timeBetweenFramesMS: Int, loopContinuously: Boolean, transparent: Boolean +) : AutoCloseable { + private val writer: ImageWriter = + ImageIO.getImageWritersBySuffix("gif").next() ?: throw IOException("No GIF Image Writers Exist!") + private val imageWriteParam: ImageWriteParam = writer.defaultWriteParam + private val metadata: IIOMetadata = writer.getDefaultImageMetadata( + ImageTypeSpecifier.createFromBufferedImageType(imageType), + imageWriteParam + ) + + init { + val root = metadata.getAsTree(metadata.nativeMetadataFormatName) as IIOMetadataNode + setGifAttributes(root, timeBetweenFramesMS, transparent, loopContinuously) + metadata.setFromTree(metadata.nativeMetadataFormatName, root) + writer.output = os + writer.prepareWriteSequence(null) + } + + fun write(img: RenderedImage) { + writer.writeToSequence(IIOImage(img, null, metadata), imageWriteParam) + } + + override fun close() { + writer.endWriteSequence() + } + + private fun getOrCreate(root: IIOMetadataNode, name: String): IIOMetadataNode = + (0 until root.length) + .map { root.item(it) as IIOMetadataNode } + .firstOrNull { it.nodeName == name } + ?: IIOMetadataNode(name).also { root.appendChild(it) } + + private fun setGifAttributes( + root: IIOMetadataNode, timeBetweenFramesMS: Int, transparent: Boolean, loopContinuously: Boolean + ) { + getOrCreate(root, "GraphicControlExtension").apply { + setAttribute("disposalMethod", "restoreToBackgroundColor") + setAttribute("userInputFlag", "FALSE") + setAttribute("transparentColorFlag", if (transparent) "TRUE" else "FALSE") + setAttribute("delayTime", (timeBetweenFramesMS / 10).toString()) + setAttribute("transparentColorIndex", "0") + } + getOrCreate(root, "CommentExtensions").setAttribute("CommentExtension", "Test Comment") + + val appEN = getOrCreate(root, "ApplicationExtensions") + val loop = if (loopContinuously) 0 else 1 + IIOMetadataNode("ApplicationExtension").apply { + setAttribute("applicationID", "NETSCAPE") + setAttribute("authenticationCode", "2.0") + userObject = byteArrayOf(0x1, loop.toByte(), 0) + appEN.appendChild(this) + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/headpat.png b/common/src/main/resources/headpat.png deleted file mode 100644 index 1e2763495537d787f2075e991257eac118cae8bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2960 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ℜ%j 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 literal 0 HcmV?d00001 diff --git a/common/src/main/resources/headpat/pet4.gif b/common/src/main/resources/headpat/pet4.gif new file mode 100644 index 0000000000000000000000000000000000000000..f9fb14c6d828624605155b6ae4e290ec2a8d6c88 GIT binary patch literal 2598 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 I{T>7WJAqclwEzGB literal 0 HcmV?d00001 From 64421d21b629a777380ce49d6511ddbe08c1da78 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Mon, 7 Oct 2024 10:27:23 +0200 Subject: [PATCH 2/6] Update dependencies --- build.gradle.kts | 10 ++++------ fabric/build.gradle.kts | 2 +- gradle.properties | 10 +++++----- gradle/wrapper/gradle-wrapper.properties | 2 +- neoforge/build.gradle.kts | 2 +- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a1a3928..de61f46 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,12 +5,10 @@ import java.text.SimpleDateFormat import java.util.* plugins { - // I'm temporarily using a fork of the original plugin to resolve "Unsupported java classfile major version 65" - // see: https://github.com/johnrengelman/shadow/issues/911 - id("io.github.goooler.shadow") version "8.1.8" apply false + id("com.gradleup.shadow") version "8.3.3" apply false // Since this mod/bot is written in Kotlin and expected to run on Minecraft and as such // the JVM, the Kotlin plugin is needed - kotlin("jvm") version "2.0.10" + kotlin("jvm") version "2.0.20" // For generating documentation based on comments in the code id("org.jetbrains.dokka") version "1.9.10" java @@ -20,7 +18,7 @@ plugins { id("me.modmuss50.mod-publish-plugin") version "0.6.2" // NeoForge and Common development - id("net.neoforged.moddev") version "1.0.19" apply false + id("net.neoforged.moddev") version "2.0.34-beta" apply false // Fabric development id("fabric-loom") version "1.7-SNAPSHOT" apply false } @@ -215,7 +213,7 @@ subprojects { } if (!isCommon) { - apply(plugin = "io.github.goooler.shadow") + apply(plugin = "com.gradleup.shadow") dependencies { // This is runtimeLib, because NG doesn't add the common classes to the runtime classpath correctly diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 8362dcd..8798e7a 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -9,7 +9,7 @@ plugins { idea `maven-publish` id("fabric-loom") - id("io.github.goooler.shadow") + id("com.gradleup.shadow") id("me.modmuss50.mod-publish-plugin") } diff --git a/gradle.properties b/gradle.properties index f689b61..6cfc8ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ fabricApiVersion=0.102.0 fabricKotlinVersion=1.12.1+kotlin.2.0.20 # Neo -neoVersion=21.1.31 +neoVersion=21.1.66 neoVersionRange=[21.0,21.1) kotlinForgeVersion=5.5.0 kffLoaderRange=[5,) @@ -35,12 +35,12 @@ parchmentVersion=2024.07.28 forgeConfigAPIVersion=21.1.0 # Discord Interactions -jdaVersion=5.1.0 +jdaVersion=5.1.2 dcWebhooksVersion=0.8.4 # Database Interactions -exposedVersion=0.54.0 -sqliteJDBCVersion=3.46.1.0 +exposedVersion=0.55.0 +sqliteJDBCVersion=3.46.1.3 # Message parsing -commonmarkVersion=0.22.0 \ No newline at end of file +commonmarkVersion=0.23.0 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a441313..df97d72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 69e47d7..5247025 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -7,7 +7,7 @@ plugins { idea java id("net.neoforged.moddev") - id("io.github.goooler.shadow") + id("com.gradleup.shadow") } val modId: String by project From c4c321b42aeb9d4251b17c49f82e3f25679e6bae Mon Sep 17 00:00:00 2001 From: Erdragh Date: Mon, 7 Oct 2024 12:01:26 +0200 Subject: [PATCH 3/6] Replace shadow plugin with JarInJar usage --- build.gradle.kts | 130 +++++------------- common/build.gradle.kts | 4 +- fabric/build.gradle.kts | 44 ++---- gradle.properties | 4 +- gradle/dcwebhooks.versions.toml | 7 + gradle/exposed.versions.toml | 7 + gradle/jda.versions.toml | 23 ++++ gradle/libs.versions.toml | 22 +++ neoforge/build.gradle.kts | 26 +--- .../{forge => neoforge}/PlayerListMixin.java | 2 +- .../src/main/resources/astralbot.mixins.json | 3 +- settings.gradle.kts | 15 ++ 12 files changed, 132 insertions(+), 155 deletions(-) create mode 100644 gradle/dcwebhooks.versions.toml create mode 100644 gradle/exposed.versions.toml create mode 100644 gradle/jda.versions.toml create mode 100644 gradle/libs.versions.toml rename neoforge/src/main/java/dev/erdragh/astralbot/mixins/{forge => neoforge}/PlayerListMixin.java (97%) diff --git a/build.gradle.kts b/build.gradle.kts index de61f46..3acfeb8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,26 +1,24 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.kotlin.gradle.utils.extendsFrom import java.nio.charset.StandardCharsets import java.text.SimpleDateFormat import java.util.* plugins { - id("com.gradleup.shadow") version "8.3.3" apply false // Since this mod/bot is written in Kotlin and expected to run on Minecraft and as such // the JVM, the Kotlin plugin is needed - kotlin("jvm") version "2.0.20" + alias(libs.plugins.kotlin) // For generating documentation based on comments in the code - id("org.jetbrains.dokka") version "1.9.10" + alias(libs.plugins.dokka) java // Required for NeoGradle idea // For publishing the mod - id("me.modmuss50.mod-publish-plugin") version "0.6.2" + alias(libs.plugins.publish) // NeoForge and Common development - id("net.neoforged.moddev") version "2.0.34-beta" apply false + alias(libs.plugins.moddev) apply false // Fabric development - id("fabric-loom") version "1.7-SNAPSHOT" apply false + alias(libs.plugins.loom) apply false } val minecraftVersion: String by project @@ -31,9 +29,7 @@ repositories { subprojects { apply(plugin = "java") - apply(plugin = "kotlin") - apply(plugin = "org.jetbrains.dokka") - apply(plugin = "me.modmuss50.mod-publish-plugin") + apply(plugin = rootProject.libs.plugins.publish.get().pluginId) // Gets some values from the gradle.properties files in the // sub- and root projects @@ -72,72 +68,60 @@ subprojects { } } - // Bot dependencies - val jdaVersion: String by project - val dcWebhooksVersion: String by project - val exposedVersion: String by project - val sqliteJDBCVersion: String by project - val commonmarkVersion: String by project - - // Configuration for shaded dependencies, get relocated to dev.erdragh.astralbot.shadowed - val shadowBotDep by configurations.creating { - isTransitive = true - } // Configuration for JiJ-ed dependencies - val includeBotDep by configurations.creating { + val includeBotDep by configurations.registering { isTransitive = false } // Configuration for libraries that are needed at runtime - val runtimeLib by configurations.creating { - isTransitive = true + val runtimeLib by configurations.registering { + isTransitive = false } // Configuration for depending on the common project val commonDep by configurations.creating - configurations.implementation.extendsFrom(configurations.named(shadowBotDep.name)) configurations.implementation.extendsFrom(configurations.named(includeBotDep.name)) configurations.implementation.extendsFrom(configurations.named(runtimeLib.name)) configurations.implementation.extendsFrom(configurations.named(commonDep.name)) dependencies { - runtimeLib("org.xerial:sqlite-jdbc:$sqliteJDBCVersion") - includeBotDep("org.xerial:sqlite-jdbc:$sqliteJDBCVersion") - - runtimeLib("org.commonmark:commonmark:$commonmarkVersion") - includeBotDep("org.commonmark:commonmark:$commonmarkVersion") - - arrayOf( + // Library to build a connection with the sqlite database + rootProject.libs.sqlite, + // Library used to parse and convert markdown + rootProject.libs.commonmark, + // Library used to communicate with Discord, see https://jda.wiki - "net.dv8tion:JDA:$jdaVersion", + rootProject.jda.jda, + // JDA's dependencies + rootProject.jda.commons.collections, + rootProject.jda.trove4j, + rootProject.jda.jackson.annotations, + rootProject.jda.jackson.core, + rootProject.jda.jackson.databind, + rootProject.jda.websocket, + rootProject.jda.okhttp, + rootProject.jda.okio, + rootProject.jda.tink, // Library used for sending messages via Discord Webhooks - "club.minnced:discord-webhooks:$dcWebhooksVersion", + rootProject.dcwebhooks.webhooks, + rootProject.dcwebhooks.json, // Library to interact with the SQLite database, // see: https://github.com/JetBrains/Exposed - "org.jetbrains.exposed:exposed-core:$exposedVersion", - "org.jetbrains.exposed:exposed-dao:$exposedVersion", - "org.jetbrains.exposed:exposed-jdbc:$exposedVersion", + rootProject.exposed.core, + rootProject.exposed.dao, + rootProject.exposed.jdbc ).forEach { - implementation(it) { - exclude(module = "opus-java") - exclude(group = "org.slf4j") - } runtimeLib(it) { exclude(module = "opus-java") exclude(group = "org.slf4j") exclude(group = "org.jetbrains.kotlin") exclude(group = "org.jetbrains.kotlinx") } - shadowBotDep(it) { - // opus-java is for audio, which this bot doesn't need + includeBotDep(it) { exclude(module = "opus-java") - // Kotlin would be included as a transitive dependency - // on JDA and Exposed, but is already provided by the - // respective Kotlin implementation of the mod loaders + exclude(group = "org.slf4j") exclude(group = "org.jetbrains.kotlin") exclude(group = "org.jetbrains.kotlinx") - // Minecraft already ships with a logging system - exclude(group = "org.slf4j") } } } @@ -213,58 +197,16 @@ subprojects { } if (!isCommon) { - apply(plugin = "com.gradleup.shadow") - dependencies { - // This is runtimeLib, because NG doesn't add the common classes to the runtime classpath correctly commonDep(project(":common")) { isTransitive = false } } - // Include common classes in jar and shadowJar output - listOf(tasks.jar, tasks.named("shadowJar")).forEach { - it { from(project(":common").sourceSets.main.get().output) } - } - - tasks.named("shadowJar") { - // The shadowBotDep configuration was explicitly made to be shaded in, this is where that happens - configurations = listOf(shadowBotDep) - - // This transforms the service files to make relocated Exposed work (see: https://github.com/JetBrains/Exposed/issues/1353) - mergeServiceFiles() - - // (Neo-)Forge restricts loading certain classes for security reasons. - // Luckily, shadow can relocate them to a different package. - relocate("org.apache.commons.collections4", "dev.erdragh.shadowed.org.apache.commons.collections4") - - // Relocating Exposed somewhere different so other mods not doing that don't run into issues (e.g. Ledger) - relocate("org.jetbrains.exposed", "dev.erdragh.shadowed.org.jetbrains.exposed") - - // Relocating jackson to prevent incompatibilities with other mods also bundling it (e.g. GroovyModLoader on Forge) - relocate("com.fasterxml.jackson", "dev.erdragh.shadowed.com.fasterxml.jackson") - - // relocate discord interaction stuff to maybe allow other discord integrations mods to work - relocate("club.minnced.discord", "dev.erdragh.shadowed.club.minnced.discord") - relocate("net.dv8tion.jda", "dev.erdragh.shadowed.net.dv8tion.jda") - - // relocate dependencies of discord stuff - relocate("okhttp3", "dev.erdragh.shadowed.okhttp3") - relocate("okio", "dev.erdragh.shadowed.okio") - relocate("gnu.trove", "dev.erdragh.shadowed.gnu.trove") - relocate("com.iwebpp.crypto", "dev.erdragh.shadowed.com.iwebpp.crypto") - relocate("com.neovisionaries.ws", "dev.erdragh.shadowed.com.neovisionaries.ws") - relocate("org.json", "dev.erdragh.shadowed.org.json") - relocate("net.bytebuddy", "dev.erdragh.shadowed.net.bytebuddy") - - relocate("com.google", "dev.erdragh.shadowed.com.google") - relocate("google", "dev.erdragh.shadowed.google") - relocate("javax.annotation", "dev.erdragh.shadowed.javax.annotation") - - exclude("**/org/slf4j/**") - - exclude("**/org/jetbrains/annotations/*") - exclude("**/org/intellij/**") + tasks.jar { + dependsOn(project(":common").tasks.jar) + from(project(":common").sourceSets.main.get().output) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 310d465..e1d4819 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,7 +1,8 @@ plugins { idea java - id("net.neoforged.moddev") + alias(libs.plugins.kotlin) + alias(libs.plugins.moddev) } val neoformVersion: String by project @@ -25,4 +26,5 @@ dependencies { api("fuzs.forgeconfigapiport:forgeconfigapiport-common-neoforgeapi:$forgeConfigAPIVersion") compileOnly("org.spongepowered:mixin:0.8.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") } \ No newline at end of file diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 8798e7a..6fde5f2 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -1,22 +1,18 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import me.modmuss50.mpp.ReleaseType import me.modmuss50.mpp.platforms.curseforge.CurseforgeOptions import me.modmuss50.mpp.platforms.modrinth.ModrinthOptions -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { java + alias(libs.plugins.kotlin) idea - `maven-publish` - id("fabric-loom") - id("com.gradleup.shadow") - id("me.modmuss50.mod-publish-plugin") + alias(libs.plugins.loom) + alias(libs.plugins.publish) } val modId: String by project val includeBotDep: Configuration by configurations.getting -val shadowBotDep: Configuration by configurations.getting dependencies { mappings(loom.officialMojangMappings()) @@ -44,7 +40,11 @@ loom { accessWidenerPath.set(project(":common").file("src/main/resources/${modId}.accesswidener")) @Suppress("UnstableApiUsage") - mixin { defaultRefmapName.set("${modId}.refmap.json") } + mixin { + // TODO: Somehow figure out a way to get loom to create a refmap for common mixins + // add(project(":common").sourceSets.main.get()) + defaultRefmapName.set("${modId}.refmap.json") + } mods { create("astralbot") { @@ -62,34 +62,6 @@ loom { } } -tasks { - jar { - archiveClassifier.set("dev") - } - - shadowJar { - archiveClassifier.set("dev-shadow") - } - - remapJar { - inputFile.set(named("shadowJar").get().archiveFile) - dependsOn("shadowJar") - } -} - -publishing { - publications { - register("mavenJava", MavenPublication::class) { - artifactId = base.archivesName.get() - from(components["java"]) - } - } - - repositories { - maven("file://${System.getenv("local_maven")}") - } -} - publishMods { val minecraftVersion: String by project val title: String by project diff --git a/gradle.properties b/gradle.properties index 6cfc8ca..a5ee74b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ enabledPlatforms=fabric,neoforge # Fabric fabricLoaderVersion=0.16.3 fabricApiVersion=0.102.0 -fabricKotlinVersion=1.12.1+kotlin.2.0.20 +fabricKotlinVersion=1.12.2+kotlin.2.0.20 # Neo neoVersion=21.1.66 @@ -36,6 +36,8 @@ forgeConfigAPIVersion=21.1.0 # Discord Interactions jdaVersion=5.1.2 + # JDA Dependencies + websocketClientVersion= dcWebhooksVersion=0.8.4 # Database Interactions diff --git a/gradle/dcwebhooks.versions.toml b/gradle/dcwebhooks.versions.toml new file mode 100644 index 0000000..9a06a7b --- /dev/null +++ b/gradle/dcwebhooks.versions.toml @@ -0,0 +1,7 @@ +[versions] +webhooks = "0.8.4" +json = "20230618" + +[libraries] +webhooks = { group = "club.minnced", name = "discord-webhooks", version.ref = "webhooks" } +json = { group = "org.json", name = "json", version.ref = "json" } \ No newline at end of file diff --git a/gradle/exposed.versions.toml b/gradle/exposed.versions.toml new file mode 100644 index 0000000..3961eee --- /dev/null +++ b/gradle/exposed.versions.toml @@ -0,0 +1,7 @@ +[versions] +exposed = "0.55.0" + +[libraries] +core = { group = "org.jetbrains.exposed", name = "exposed-core", version.ref = "exposed" } +dao = { group = "org.jetbrains.exposed", name = "exposed-dao", version.ref = "exposed" } +jdbc = { group = "org.jetbrains.exposed", name = "exposed-jdbc", version.ref = "exposed" } \ No newline at end of file diff --git a/gradle/jda.versions.toml b/gradle/jda.versions.toml new file mode 100644 index 0000000..d6967bf --- /dev/null +++ b/gradle/jda.versions.toml @@ -0,0 +1,23 @@ +[versions] +jda = "5.1.2" + +websocket = "2.14" +okhttp = "4.12.0" +okio = "3.9.1" +trove4j = "3.1.0" +commons-collections = "4.4" +jackson = "2.17.2" +tink = "1.14.1" + +[libraries] +jda = { group = "net.dv8tion", name = "JDA", version.ref = "jda" } + +commons-collections = { group = "org.apache.commons", name = "commons-collections4", version.ref = "commons-collections" } +trove4j = { group = "net.sf.trove4j", name = "core", version.ref = "trove4j" } +jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } +jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-core", version.ref = "jackson" } +jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } +websocket = { group = "com.neovisionaries", name = "nv-websocket-client", version.ref = "websocket" } +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +okio = { group = "com.squareup.okio", name = "okio-jvm", version.ref = "okio" } +tink = { group = "com.google.crypto.tink", name = "tink", version.ref = "tink" } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..d7b8ec8 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,22 @@ +[versions] +kotlin = "2.0.20" +moddev = "2.0.34-beta" +loom = "1.7-SNAPSHOT" + +dokka = "1.9.10" +publish = "0.6.2" + +sqlite = "3.46.1.3" +commonmark = "0.23.0" + +[libraries] +sqlite = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite" } +commonmark = { group = "org.commonmark", name = "commonmark", version.ref = "commonmark" } + +[plugins] +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +moddev = { id = "net.neoforged.moddev", version.ref = "moddev" } +loom = { id = "fabric-loom", version.ref = "loom" } + +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +publish = { id = "me.modmuss50.mod-publish-plugin", version.ref = "publish" } \ No newline at end of file diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 5247025..468063d 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -6,13 +6,12 @@ import org.jetbrains.kotlin.gradle.utils.extendsFrom plugins { idea java - id("net.neoforged.moddev") - id("com.gradleup.shadow") + alias(libs.plugins.kotlin) + alias(libs.plugins.moddev) } val modId: String by project val includeBotDep: Configuration by configurations.getting -val shadowBotDep: Configuration by configurations.getting val runtimeLib: Configuration by configurations.getting val minecraftVersion: String by project @@ -66,8 +65,8 @@ dependencies { // Adds KFF as dependency and Kotlin libs implementation("thedarkcolour:kotlinforforge-neoforge:$kotlinForgeVersion") - configurations.named("additionalRuntimeClasspath").extendsFrom(configurations.named("runtimeLib")) - configurations.named("jarJar").extendsFrom(configurations.named("includeBotDep")) + configurations.additionalRuntimeClasspath.extendsFrom(configurations.runtimeLib) + configurations.jarJar.extendsFrom(configurations.includeBotDep) } tasks { @@ -75,19 +74,6 @@ tasks { processResources { from(project(":common").sourceSets.main.get().resources) } - jar { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - archiveClassifier = "slim" - finalizedBy(shadowJar) - } - shadowJar { - dependsOn(jar) - from(jar) - archiveClassifier = null - } - withType { - println("archive task: ${this.name}") - } } publishMods { @@ -105,7 +91,7 @@ publishMods { curseforge("curseNeo") { from(curseforgePublish) modLoaders.add(project.name) - file.set(tasks.shadowJar.get().archiveFile) + file.set(tasks.jar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) displayName = "$title $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" @@ -115,7 +101,7 @@ publishMods { modrinth("modrinthNeo") { from(modrinthPublish) modLoaders.add(project.name) - file.set(tasks.shadowJar.get().archiveFile) + file.set(tasks.jar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) displayName = "$title $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" diff --git a/neoforge/src/main/java/dev/erdragh/astralbot/mixins/forge/PlayerListMixin.java b/neoforge/src/main/java/dev/erdragh/astralbot/mixins/neoforge/PlayerListMixin.java similarity index 97% rename from neoforge/src/main/java/dev/erdragh/astralbot/mixins/forge/PlayerListMixin.java rename to neoforge/src/main/java/dev/erdragh/astralbot/mixins/neoforge/PlayerListMixin.java index 0ea3b04..e221550 100644 --- a/neoforge/src/main/java/dev/erdragh/astralbot/mixins/forge/PlayerListMixin.java +++ b/neoforge/src/main/java/dev/erdragh/astralbot/mixins/neoforge/PlayerListMixin.java @@ -1,4 +1,4 @@ -package dev.erdragh.astralbot.mixins.forge; +package dev.erdragh.astralbot.mixins.neoforge; import dev.erdragh.astralbot.neoforge.event.CommandMessageEvent; import dev.erdragh.astralbot.neoforge.event.SystemMessageEvent; diff --git a/neoforge/src/main/resources/astralbot.mixins.json b/neoforge/src/main/resources/astralbot.mixins.json index 81bac46..12bc704 100644 --- a/neoforge/src/main/resources/astralbot.mixins.json +++ b/neoforge/src/main/resources/astralbot.mixins.json @@ -1,9 +1,8 @@ { "required": true, "minVersion": "0.8", - "package": "dev.erdragh.astralbot.mixins.forge", + "package": "dev.erdragh.astralbot.mixins.neoforge", "compatibilityLevel": "JAVA_17", - "refmap": "${mod_id}.refmap.json", "server": [ "PlayerListMixin" ], diff --git a/settings.gradle.kts b/settings.gradle.kts index 11ac206..621f357 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,4 +16,19 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } +dependencyResolutionManagement { + versionCatalogs { + register("libs") + register("jda") { + from(files("gradle/jda.versions.toml")) + } + register("dcwebhooks") { + from(files("gradle/dcwebhooks.versions.toml")) + } + register("exposed") { + from(files("gradle/exposed.versions.toml")) + } + } +} + include("common", "fabric", "neoforge") \ No newline at end of file From ab198758a890ae302be58303e49c4e3396cb0e60 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Fri, 7 Feb 2025 18:33:27 +0100 Subject: [PATCH 4/6] Improve gradle build setup --- .gitignore | 1 + build.gradle.kts | 276 +----------------- buildSrc/build.gradle.kts | 14 + buildSrc/settings.gradle.kts | 7 + .../src/main/groovy/multiloader-common.gradle | 202 +++++++++++++ .../src/main/groovy/multiloader-loader.gradle | 100 +++++++ common/build.gradle.kts | 55 ++-- .../main/kotlin/dev/erdragh/astralbot/Bot.kt | 5 +- fabric/build.gradle.kts | 69 ++--- .../dev/erdragh/astralbot/fabric/BotMod.kt | 4 +- fabric/src/main/resources/fabric.mod.json | 2 +- gradle.properties | 37 +-- gradle/libs.versions.toml | 22 -- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 +- gradlew.bat | 2 + libs.versions.toml | 61 ++++ neoforge/build.gradle.kts | 42 +-- .../dev/erdragh/astralbot/neoforge/BotMod.kt | 4 +- .../resources/META-INF/neoforge.mods.toml | 8 +- settings.gradle.kts | 4 +- 22 files changed, 491 insertions(+), 430 deletions(-) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/settings.gradle.kts create mode 100644 buildSrc/src/main/groovy/multiloader-common.gradle create mode 100644 buildSrc/src/main/groovy/multiloader-loader.gradle delete mode 100644 gradle/libs.versions.toml create mode 100644 libs.versions.toml diff --git a/.gitignore b/.gitignore index f95b34b..5380871 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ faq # Minecraft **/run +**/runs # Architectury .architectury-transformer \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 3acfeb8..ba23668 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,278 +1,12 @@ -import org.jetbrains.kotlin.gradle.utils.extendsFrom -import java.nio.charset.StandardCharsets -import java.text.SimpleDateFormat -import java.util.* - plugins { - // Since this mod/bot is written in Kotlin and expected to run on Minecraft and as such - // the JVM, the Kotlin plugin is needed - alias(libs.plugins.kotlin) - // For generating documentation based on comments in the code - alias(libs.plugins.dokka) - java - // Required for NeoGradle - idea - // For publishing the mod - alias(libs.plugins.publish) - - // NeoForge and Common development - alias(libs.plugins.moddev) apply false - // Fabric development + // see https://fabricmc.net/develop/ for new versions alias(libs.plugins.loom) apply false + // see https://projects.neoforged.net/neoforged/moddevgradle for new versions + alias(libs.plugins.moddev) apply false + // so we can enable soruce download + idea } -val minecraftVersion: String by project - -repositories { - mavenCentral() -} - -subprojects { - apply(plugin = "java") - apply(plugin = rootProject.libs.plugins.publish.get().pluginId) - - // Gets some values from the gradle.properties files in the - // sub- and root projects - val modLoader = project.name - val modId: String by project - val modName = rootProject.name - val modAuthor: String by project - val isCommon = modLoader == rootProject.projects.common.name - - base { - // This will be the final name of the exported JAR file - archivesName.set("$modId-$modLoader-$minecraftVersion") - } - - extensions.configure { - toolchain.languageVersion.set(JavaLanguageVersion.of(21)) - withSourcesJar() - } - - repositories { - mavenCentral() - maven(url = "https://maven.neoforged.net/releases/") - maven("https://repo.spongepowered.org/repository/maven-public/") { name = "Sponge / Mixin" } - maven("https://maven.blamejared.com") { name = "BlameJared Maven (JEI / CraftTweaker / Bookshelf)" } - // For the parchment mappings - maven(url = "https://maven.parchmentmc.org") - maven(url = "https://maven.resourcefulbees.com/repository/maven-public/") - maven { - name = "Kotlin for Forge" - setUrl("https://thedarkcolour.github.io/KotlinForForge/") - } - // Forge Config API port - maven { - name = "Fuzs Mod Resources" - setUrl("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") - } - } - - // Configuration for JiJ-ed dependencies - val includeBotDep by configurations.registering { - isTransitive = false - } - // Configuration for libraries that are needed at runtime - val runtimeLib by configurations.registering { - isTransitive = false - } - // Configuration for depending on the common project - val commonDep by configurations.creating - configurations.implementation.extendsFrom(configurations.named(includeBotDep.name)) - configurations.implementation.extendsFrom(configurations.named(runtimeLib.name)) - configurations.implementation.extendsFrom(configurations.named(commonDep.name)) - - dependencies { - arrayOf( - // Library to build a connection with the sqlite database - rootProject.libs.sqlite, - // Library used to parse and convert markdown - rootProject.libs.commonmark, - - // Library used to communicate with Discord, see https://jda.wiki - rootProject.jda.jda, - // JDA's dependencies - rootProject.jda.commons.collections, - rootProject.jda.trove4j, - rootProject.jda.jackson.annotations, - rootProject.jda.jackson.core, - rootProject.jda.jackson.databind, - rootProject.jda.websocket, - rootProject.jda.okhttp, - rootProject.jda.okio, - rootProject.jda.tink, - // Library used for sending messages via Discord Webhooks - rootProject.dcwebhooks.webhooks, - rootProject.dcwebhooks.json, - - // Library to interact with the SQLite database, - // see: https://github.com/JetBrains/Exposed - rootProject.exposed.core, - rootProject.exposed.dao, - rootProject.exposed.jdbc - ).forEach { - runtimeLib(it) { - exclude(module = "opus-java") - exclude(group = "org.slf4j") - exclude(group = "org.jetbrains.kotlin") - exclude(group = "org.jetbrains.kotlinx") - } - includeBotDep(it) { - exclude(module = "opus-java") - exclude(group = "org.slf4j") - exclude(group = "org.jetbrains.kotlin") - exclude(group = "org.jetbrains.kotlinx") - } - } - } - - tasks.test { - // There are no tests and the Neo build fails - exclude("**/*") - } - - java { - withSourcesJar() - modularity.inferModulePath = true - } - - tasks.jar { - from(rootProject.file("LICENSE")) { - rename { "${it}_$modId" } - } - - manifest { - attributes( - "Specification-Title" to modId, - "Specification-Vendor" to modAuthor, - "Specification-Version" to archiveVersion, - "Implementation-Title" to project.name, - "Implementation-Version" to archiveVersion, - "Implementation-Vendor" to modAuthor, - "Implementation-Timestamp" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(Date()), - "Timestamp" to System.currentTimeMillis(), - "Built-On-Java" to "${System.getProperty("java.vm.version")} (${System.getProperty("java.vm.vendor")})", - "Built-On-Minecraft" to minecraftVersion - ) - } - } - - tasks.processResources { - val version: String by project - val group: String by project - val minecraftVersionRange: String by project - val fabricApiVersion: String by project - val fabricLoaderVersion: String by project - val fabricKotlinVersion: String by project - val neoVersion: String by project - val neoVersionRange: String by project - val kffLoaderRange: String by project - val license: String by project - val description: String by project - val credits: String by project - - val expandProps = mapOf( - "version" to version, - "group" to group, //Else we target the task's group. - "minecraft_version" to minecraftVersion, - "minecraft_version_range" to minecraftVersionRange, - "fabric_version" to fabricApiVersion, - "fabric_loader_version" to fabricLoaderVersion, - "fabric_kotlin_version" to fabricKotlinVersion, - "neoforge_version" to neoVersion, - "neoforge_loader_version_range" to neoVersionRange, - "kff_loader_range" to kffLoaderRange, - "mod_name" to modName, - "mod_author" to modAuthor, - "mod_id" to modId, - "license" to license, - "description" to description, - "credits" to credits - ) - - filesMatching(listOf("pack.mcmeta", "*.mixins.json", "META-INF/*.mods.toml", "fabric.mod.json")) { - expand(expandProps) - } - inputs.properties(expandProps) - } - - if (!isCommon) { - dependencies { - commonDep(project(":common")) { - isTransitive = false - } - } - - tasks.jar { - dependsOn(project(":common").tasks.jar) - from(project(":common").sourceSets.main.get().output) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - } - } - - // Disables Gradle's custom module metadata from being published to maven. The - // metadata includes mapped dependencies which are not reasonably consumable by - // other mod developers. - tasks.withType { - enabled = false - } - - tasks.withType { - options.encoding = "UTF-8" - targetCompatibility = JavaVersion.VERSION_21.majorVersion - sourceCompatibility = JavaVersion.VERSION_21.majorVersion - } - - // Publishing settings - if (!isCommon) { - publishMods { - // These titles get used based on subproject name - val titles by extra { - mapOf( - "fabric" to "Fabric", - "neoforge" to "NeoForge", - "forge" to "Forge", - "quilt" to "Quilt" - ) - } - val curseforgePublish by extra { - curseforgeOptions { - accessToken = providers.environmentVariable("CURSEFORGE_TOKEN") - minecraftVersions.add(minecraftVersion) - projectId = providers.environmentVariable("CURSEFORGE_ID") - embeds("sqlite-jdbc") - } - } - val modrinthPublish by extra { - modrinthOptions { - accessToken = providers.environmentVariable("MODRINTH_TOKEN") - minecraftVersions.add(minecraftVersion) - projectId = providers.environmentVariable("MODRINTH_ID") - embeds("sqlite-jdbc") - } - } - val changelog by extra { - // Only gets the lines for the latest version from the Changelog - // file. This allows me to keep all previous changes in the file - // without having to worry about them being included on new file - // uploads. - File(rootDir, "CHANGELOG.md") - .readText(StandardCharsets.UTF_8) - .replace(Regex("[^^](#(#|\\n|.)+)|(^#.+)"), "") - .trim() - } - val type by extra { - STABLE - } - } - } -} - -kotlin { - jvmToolchain(21) -} - - // IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior. idea { module { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..f80c745 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("groovy-gradle-plugin") +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}") + implementation("org.jetbrains.dokka:dokka-gradle-plugin:${libs.versions.dokka.get()}") + implementation("me.modmuss50:mod-publish-plugin:${libs.versions.publish.get()}") +} + +repositories { + mavenCentral() + gradlePluginPortal() +} \ No newline at end of file diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 0000000..36adc8e --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + register("libs") { + from(files("../libs.versions.toml")) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle new file mode 100644 index 0000000..230938e --- /dev/null +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -0,0 +1,202 @@ +import org.jetbrains.dokka.gradle.DokkaTaskPartial + +plugins { + id 'java-library' + id 'maven-publish' + id "org.jetbrains.kotlin.jvm" + id "org.jetbrains.dokka" +} + +base { + archivesName = "${modId}-${project.name}-${libs.versions.minecraft.get()}" +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(libs.versions.java.get()) + withSourcesJar() + withJavadocJar() +} + +kotlin { + jvmToolchain(Integer.parseInt(libs.versions.java.get())) +} + +repositories { + mavenCentral() + exclusiveContent { + forRepositories( + maven { + name = 'ParchmentMC' + url = 'https://maven.parchmentmc.org/' + }, + maven { + name = "NeoForge" + url = 'https://maven.neoforged.net/releases' + } + ) + filter { includeGroup('org.parchmentmc.data') } + } + maven { + name = 'BlameJared' + url = 'https://maven.blamejared.com' + } + maven { + name = "kotlinforforge" + url = "https://thedarkcolour.github.io/KotlinForForge/" + } + maven { + name = "Sponge / Mixin" + url = "https://repo.spongepowered.org/repository/maven-public/" + } + // Forge Config API port + maven { + name = "Fuzs Mod Resources" + setUrl("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + } +} + +// Declare capabilities on the outgoing configurations. +// Read more about capabilities here: https://docs.gradle.org/current/userguide/component_capabilities.html#sec:declaring-additional-capabilities-for-a-local-component +['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant -> + configurations."$variant".outgoing { + capability("$group:${base.archivesName.get()}:$version") + capability("$group:$modId-${project.name}-${libs.versions.minecraft.get()}:$version") + capability("$group:$modId:$version") + } + publishing.publications.configureEach { + suppressPomMetadataWarningsFor(variant) + } +} + +sourcesJar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${modId}" } + } +} + +jar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${modId}" } + } + + manifest { + attributes([ + 'Specification-Title' : modName, + 'Specification-Vendor' : modAuthor, + 'Specification-Version' : project.jar.archiveVersion, + 'Implementation-Title' : project.name, + 'Implementation-Version': project.jar.archiveVersion, + 'Implementation-Vendor' : modAuthor, + 'Built-On-Minecraft' : libs.versions.minecraft.get() + ]) + } +} + +tasks.withType(DokkaTaskPartial).configureEach { + dokkaSourceSets.configureEach { + includeNonPublic = false + skipDeprecated = false + reportUndocumented = false + jdkVersion = Integer.parseInt(libs.versions.java.get()) + sourceRoots.from(sourceSets.main.allSource) + } +} + +// Prevent the default javadoc task from running, as Dokka is +// responsible for generating the docs now +tasks.named("javadoc", Javadoc) { + enabled = false +} + +// Make the javadoc jar take in the Dokka output +tasks.named("javadocJar", Jar) { + dependsOn(tasks.named("dokkaJavadoc")) + from(tasks.named("dokkaJavadoc")) +} + +processResources { + var expandProps = [ + 'version' : version, + 'group' : project.group, //Else we target the task's group. + 'minecraft_version' : libs.versions.minecraft.get(), + 'minecraft_version_range' : libs.versions.minecraftRange.get(), + 'fabric_version' : libs.versions.fabricApi.get(), + 'fabric_loader_version' : libs.versions.fabricLoader.get(), + 'flk_version' : libs.versions.flk.get(), + 'mod_name' : modName, + 'mod_author' : modAuthor, + 'mod_id' : modId, + 'license' : license, + 'description' : project.description, + 'neoforge_version' : libs.versions.neoforge.get(), + 'neoforge_range' : libs.versions.neoforgeRange.get(), + 'kff_version' : libs.versions.kff.get(), + 'kff_version_range' : libs.versions.kffRange.get(), + 'credits' : credits, + 'java_version' : libs.versions.java.get() + ] + + filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/neoforge.mods.toml', '*.mixins.json']) { + expand expandProps + } + inputs.properties(expandProps) +} + +publishing { + publications { + register('mavenJava', MavenPublication) { + artifactId base.archivesName.get() + from components.java + } + } + repositories { + maven { + url System.getenv('local_maven_url') + } + } +} + +configurations { + botLib { + transitive = false + } + implementation.extendsFrom(botLib) +} + +dependencies { + [ + // Library to build a connection with the sqlite database + libs.sqlite, + // Library used to parse and convert markdown + libs.commonmark, + + // Library used to communicate with Discord, see https://jda.wiki + jda.jda, + // JDA's dependencies + jda.commons.collections, + jda.trove4j, + jda.jackson.annotations, + jda.jackson.core, + jda.jackson.databind, + jda.websocket, + jda.okhttp, + jda.okio, + jda.tink, + // Library used for sending messages via Discord Webhooks + dcwebhooks.webhooks, + dcwebhooks.json, + + // Library to interact with the SQLite database, + // see: https://github.com/JetBrains/Exposed + exposed.core, + exposed.dao, + exposed.jdbc, + ].forEach { + botLib(it) { + exclude group: "org.slf4j" + exclude group: "org.jetbrains.kotlin" + exclude group: "org.jetbrains.kotlinx" + exclude module: "opus-java" + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/multiloader-loader.gradle b/buildSrc/src/main/groovy/multiloader-loader.gradle new file mode 100644 index 0000000..b5f701a --- /dev/null +++ b/buildSrc/src/main/groovy/multiloader-loader.gradle @@ -0,0 +1,100 @@ +import org.jetbrains.dokka.gradle.DokkaTask + +import java.nio.charset.StandardCharsets +import java.nio.file.Files + +plugins { + id 'multiloader-common' + id "org.jetbrains.kotlin.jvm" + id "me.modmuss50.mod-publish-plugin" +} + +configurations { + commonJava { + canBeResolved = true + } + commonKotlin { + canBeResolved = true + } + commonResources { + canBeResolved = true + } +} + +dependencies { + compileOnly(project(':common')) { + capabilities { + requireCapability "$group:$modId" + } + } + commonJava project(path: ':common', configuration: 'commonJava') + commonKotlin project(path: ':common', configuration: 'commonKotlin') + commonResources project(path: ':common', configuration: 'commonResources') +} + +tasks.named('compileJava', JavaCompile) { + dependsOn(configurations.commonJava) + source(configurations.commonJava) +} + +tasks.named('compileKotlin') { + dependsOn(configurations.commonKotlin) + dependsOn(configurations.commonJava) + source(configurations.commonJava) + source(configurations.commonKotlin) +} + +processResources { + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} + +tasks.named('sourcesJar', Jar) { + dependsOn(configurations.commonJava) + from(configurations.commonJava) + dependsOn(configurations.commonKotlin) + from(configurations.commonKotlin) + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} + +// Use dokka to generate javadoc for both Java and Kotlin sources +// instead of using the builtin javadoc tools. This allows mixing +// Kotlin and Java +tasks.named("dokkaJavadoc", DokkaTask) { + dependsOn(configurations.commonJava) + dependsOn(configurations.commonKotlin) + dokkaSourceSets.configureEach { + sourceRoots.from(configurations.commonJava.singleFile, configurations.commonKotlin.singleFile) + } +} + + +// These titles get used based on subproject name +ext.titles = [ + "fabric" : "Fabric", + "neoforge" : "NeoForge", + "forge" : "Forge" +] +ext.curseforgePublish = publishMods.curseforgeOptions { + accessToken = providers.environmentVariable("CURSEFORGE_TOKEN") + minecraftVersions.add(libs.versions.minecraft.get()) + projectId = providers.environmentVariable("CURSEFORGE_ID") + embeds("sqlite-jdbc") +} +ext.modrinthPublish = publishMods.modrinthOptions { + accessToken = providers.environmentVariable("MODRINTH_TOKEN") + minecraftVersions.add(libs.versions.minecraft.get()) + projectId = providers.environmentVariable("MODRINTH_ID") + embeds("sqlite-jdbc") +} + +// Only gets the lines for the latest version from the Changelog +// file. This allows me to keep all previous changes in the file +// without having to worry about them being included on new file +// uploads. +ext.changelog = Files.readString(rootDir.toPath().resolve("CHANGELOG.md")) + .replaceAll("[^^](#(#|\\n|.)+)|(^#.+)", "") + .trim() + +ext.type = publishMods.STABLE \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index e1d4819..31502b6 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,30 +1,49 @@ plugins { - idea - java - alias(libs.plugins.kotlin) + id("multiloader-common") alias(libs.plugins.moddev) } -val neoformVersion: String by project -val minecraftVersion: String by project -val mcVersion = minecraftVersion -val parchmentVersion: String by project -val parchmentMinecraft: String by project -val modId: String by project - neoForge { - neoFormVersion = neoformVersion - + neoFormVersion = libs.versions.neoForm.get() + // Automatically enable AccessTransformers if the file exists + val at = file("src/main/resources/META-INF/accesstransformer.cfg") + if (at.exists()) { + accessTransformers.from(at.absolutePath) + } parchment { - minecraftVersion = parchmentMinecraft - mappingsVersion = parchmentVersion + minecraftVersion = libs.versions.parchmentMC + mappingsVersion = libs.versions.parchment } } dependencies { - val forgeConfigAPIVersion: String by project + api(libs.slf4j) + compileOnly(libs.kotlinx.coroutines) + compileOnly(libs.mixin) + // fabric and neoforge both bundle mixinextras, so it is safe to use it in common + compileOnly(libs.mixinExtras.common) + annotationProcessor(libs.mixinExtras.common) + + api(libs.fcapi.common) +} + +configurations { + create("commonJava") { + isCanBeResolved = false + isCanBeConsumed = true + } + create("commonKotlin") { + isCanBeResolved = false + isCanBeConsumed = true + } + create("commonResources") { + isCanBeResolved = false + isCanBeConsumed = true + } +} - api("fuzs.forgeconfigapiport:forgeconfigapiport-common-neoforgeapi:$forgeConfigAPIVersion") - compileOnly("org.spongepowered:mixin:0.8.7") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") +artifacts { + add("commonJava", sourceSets.main.get().java.sourceDirectories.singleFile) + add("commonKotlin", sourceSets.main.get().kotlin.sourceDirectories.filter { !it.name.endsWith("java") }.singleFile) + add("commonResources", sourceSets.main.get().resources.sourceDirectories.singleFile) } \ No newline at end of file diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt index 6ae89a3..fe2f4cc 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt @@ -1,5 +1,6 @@ package dev.erdragh.astralbot +import com.mojang.logging.LogUtils import dev.erdragh.astralbot.listeners.CommandHandlingListener import dev.erdragh.astralbot.listeners.UserEventListener import dev.erdragh.astralbot.config.AstralBotConfig @@ -13,8 +14,6 @@ import net.dv8tion.jda.api.entities.Guild import net.dv8tion.jda.api.entities.channel.concrete.TextChannel import net.dv8tion.jda.api.requests.GatewayIntent 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 @@ -23,7 +22,7 @@ import kotlin.io.path.absolute import kotlin.properties.Delegates const val MODID = "astralbot" -val LOGGER: Logger = LoggerFactory.getLogger(MODID) +val LOGGER = LogUtils.getLogger() private lateinit var startTimestamp: LocalDateTime var minecraftHandler: MinecraftHandler? = null diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 6fde5f2..ba625b1 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -3,68 +3,59 @@ import me.modmuss50.mpp.platforms.curseforge.CurseforgeOptions import me.modmuss50.mpp.platforms.modrinth.ModrinthOptions plugins { - java - alias(libs.plugins.kotlin) - idea + id("multiloader-loader") alias(libs.plugins.loom) - alias(libs.plugins.publish) } val modId: String by project -val includeBotDep: Configuration by configurations.getting +val botLib: Configuration by configurations.getting dependencies { - mappings(loom.officialMojangMappings()) - val minecraftVersion: String by project - val fabricLoaderVersion: String by project - val fabricApiVersion: String by project - val fabricKotlinVersion: String by project - val forgeConfigAPIVersion: String by project + minecraft(libs.minecraft) + mappings(loom.layered { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${libs.versions.parchmentMC.get()}:${libs.versions.parchment.get()}@zip") + }) + modImplementation(libs.fabricLoader) + modImplementation(libs.fabricApi) - minecraft("com.mojang:minecraft:${minecraftVersion}") + modImplementation(libs.flk) - modImplementation(group = "net.fabricmc", name = "fabric-loader", version = fabricLoaderVersion) - modApi(group = "net.fabricmc.fabric-api", name = "fabric-api", version = "$fabricApiVersion+$minecraftVersion") - modImplementation("net.fabricmc:fabric-language-kotlin:${fabricKotlinVersion}") + modApi(libs.fcapi.fabric) - modApi("fuzs.forgeconfigapiport:forgeconfigapiport-fabric:$forgeConfigAPIVersion") - - includeBotDep.dependencies.forEach { include(it) } + botLib.dependencies.forEach { include(it) } } loom { - serverOnlyMinecraftJar() - - if (project(":common").file("src/main/resources/${modId}.accesswidener").exists()) - accessWidenerPath.set(project(":common").file("src/main/resources/${modId}.accesswidener")) - - @Suppress("UnstableApiUsage") + val aw = project(":common").file("src/main/resources/${modId}.accesswidener") + if (aw.exists()) { + accessWidenerPath.set(aw) + } mixin { - // TODO: Somehow figure out a way to get loom to create a refmap for common mixins - // add(project(":common").sourceSets.main.get()) defaultRefmapName.set("${modId}.refmap.json") } - - mods { - create("astralbot") { - sourceSet(sourceSets.main.get()) - } - } - runs { + named("client") { + client() + setConfigName("Fabric Client") + ideConfigGenerated(true) + mkdir("runs/server") + runDir("runs/client") + } named("server") { server() - configName = "Fabric Server" + setConfigName("Fabric Server") ideConfigGenerated(true) - runDir("run") + mkdir("runs/server") + runDir("runs/server") } } } publishMods { - val minecraftVersion: String by project - val title: String by project + val minecraftVersion = libs.versions.minecraft.get() + val modName: String by project val version: String by project val titles: Map by extra @@ -79,7 +70,7 @@ publishMods { modLoaders.add(project.name) file.set(tasks.remapJar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" + displayName = "$modName $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" requires("fabric-language-kotlin", "forge-config-api-port-fabric", "fabric-api") } @@ -89,7 +80,7 @@ publishMods { modLoaders.add(project.name) file.set(tasks.remapJar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" + displayName = "$modName $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" requires("fabric-language-kotlin", "forge-config-api-port", "fabric-api") } 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 ac327fd..4bec884 100644 --- a/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt +++ b/fabric/src/main/kotlin/dev/erdragh/astralbot/fabric/BotMod.kt @@ -17,8 +17,8 @@ import net.neoforged.fml.config.ModConfig object BotMod : ModInitializer { override fun onInitialize() { - NeoForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotConfig.SPEC) - NeoForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text.toml") + NeoForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.COMMON, AstralBotConfig.SPEC, "astralbot-server.toml") + NeoForgeConfigRegistry.INSTANCE.register(MODID, ModConfig.Type.COMMON, AstralBotTextConfig.SPEC, "astralbot-text.toml") NeoForgeModConfigEvents.reloading(MODID).register { // Updates the webhook client if the URL changed diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 4d4bb75..aa7852b 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -31,7 +31,7 @@ "fabric": "*", "minecraft": ">=${minecraft_version}", "java": ">=17", - "fabric-language-kotlin": ">=${fabric_kotlin_version}", + "fabric-language-kotlin": ">=${flk_version}", "forgeconfigapiport": ">=20.0.0" } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index a5ee74b..a4644a7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,45 +4,12 @@ org.gradle.jvmargs=-Xmx3G -XX:ThreadStackSize=4096 -XX:CompilerThreadStackSize=4 # Minecraft things enabledPlatforms=fabric,neoforge -# Fabric -fabricLoaderVersion=0.16.3 -fabricApiVersion=0.102.0 -fabricKotlinVersion=1.12.2+kotlin.2.0.20 - -# Neo -neoVersion=21.1.66 -neoVersionRange=[21.0,21.1) -kotlinForgeVersion=5.5.0 -kffLoaderRange=[5,) - version=1.5.3 group=dev.erdragh.astralbot +modName=AstralBot modId=astralbot modAuthor=Erdragh license=MIT -title=AstralBot description=Discord Bot and Minecraft Mod in one bundle. -credits=Erdragh - -minecraftVersion=1.21.1 -# https://projects.neoforged.net/neoforged/neoform -neoformVersion=1.21.1-20240808.144430 -minecraftVersionRange=[1.21,1.21.1) -parchmentMinecraft=1.21 -parchmentVersion=2024.07.28 - -forgeConfigAPIVersion=21.1.0 - -# Discord Interactions -jdaVersion=5.1.2 - # JDA Dependencies - websocketClientVersion= -dcWebhooksVersion=0.8.4 - -# Database Interactions -exposedVersion=0.55.0 -sqliteJDBCVersion=3.46.1.3 - -# Message parsing -commonmarkVersion=0.23.0 \ No newline at end of file +credits=Erdragh \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml deleted file mode 100644 index d7b8ec8..0000000 --- a/gradle/libs.versions.toml +++ /dev/null @@ -1,22 +0,0 @@ -[versions] -kotlin = "2.0.20" -moddev = "2.0.34-beta" -loom = "1.7-SNAPSHOT" - -dokka = "1.9.10" -publish = "0.6.2" - -sqlite = "3.46.1.3" -commonmark = "0.23.0" - -[libraries] -sqlite = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite" } -commonmark = { group = "org.commonmark", name = "commonmark", version.ref = "commonmark" } - -[plugins] -kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -moddev = { id = "net.neoforged.moddev", version.ref = "moddev" } -loom = { id = "fabric-loom", version.ref = "loom" } - -dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } -publish = { id = "me.modmuss50.mod-publish-plugin", version.ref = "publish" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 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 HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72..cea7a79 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf1..f3b75f3 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30d..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/libs.versions.toml b/libs.versions.toml new file mode 100644 index 0000000..1ba0af3 --- /dev/null +++ b/libs.versions.toml @@ -0,0 +1,61 @@ +[versions] +java = "21" +kotlin = "2.1.10" +moddev = "2.0.78" +loom = "1.9-SNAPSHOT" +dokka = "2.0.0" + +kotlinx-coroutines = "1.10.1" + +minecraft = "1.21.1" +minecraftRange = "[1.21.1, 1.21.2)" + +# The version of ParchmentMC that is used, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions +parchment = "2024.11.17" +parchmentMC = "1.21.1" + +neoforge = "21.1.116" +neoforgeRange = "[21.1, 21.2)" +## This is the version of minecraft that the 'common' project uses, you can find a list of all versions here +## https://projects.neoforged.net/neoforged/neoform +neoForm = "1.21.1-20240808.144430" +kff = "5.7.0" +kffRange = "[5.7, )" + +slf4j = "2.0.9" + +fcapi = "21.1.3" + +fabricLoader = "0.16.10" +fabricApi = "0.102.0+1.21.1" +flk = "1.13.1+kotlin.2.1.10" +publish = "0.8.4" + +sqlite = "3.49.0.0" +commonmark = "0.24.0" + +mixin = "0.8.5" +mixinExtras = "0.3.5" + +[libraries] +minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } +fabricLoader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabricLoader" } +fabricApi = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabricApi" } +flk = { group = "net.fabricmc", name = "fabric-language-kotlin", version.ref = "flk" } +kff = { group = "thedarkcolour", name = "kotlinforforge-neoforge", version.ref = "kff" } +mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" } +mixinExtras-common = { group = "io.github.llamalad7", name = "mixinextras-common", version.ref = "mixinExtras" } +sqlite = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite" } +commonmark = { group = "org.commonmark", name = "commonmark", version.ref = "commonmark" } +fcapi-fabric = { group = "fuzs.forgeconfigapiport", name = "forgeconfigapiport-fabric", version.ref = "fcapi" } +fcapi-common = { group = "fuzs.forgeconfigapiport", name = "forgeconfigapiport-common-neoforgeapi", version.ref = "fcapi" } +parchment = { group = "org.parchmentmc.data", name = "parchment-1.21.1", version.ref = "parchment" } +slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" } +kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } + +[plugins] +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +moddev = { id = "net.neoforged.moddev", version.ref = "moddev" } +loom = { id = "fabric-loom", version.ref = "loom" } +publish = { id = "me.modmuss50.mod-publish-plugin", version.ref = "publish" } \ No newline at end of file diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 468063d..ab304ea 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -4,29 +4,19 @@ import me.modmuss50.mpp.platforms.modrinth.ModrinthOptions import org.jetbrains.kotlin.gradle.utils.extendsFrom plugins { - idea - java - alias(libs.plugins.kotlin) + id("multiloader-loader") alias(libs.plugins.moddev) } val modId: String by project -val includeBotDep: Configuration by configurations.getting -val runtimeLib: Configuration by configurations.getting - -val minecraftVersion: String by project -val mcVersion = minecraftVersion -val parchmentMinecraft: String by project -val parchmentVersion: String by project -val neoVersion: String by project -val kotlinForgeVersion: String by project +val botLib: Configuration by configurations.getting neoForge { - version = neoVersion + version = libs.versions.neoforge.get() parchment { - minecraftVersion = parchmentMinecraft - mappingsVersion = parchmentVersion + minecraftVersion = libs.versions.parchmentMC.get() + mappingsVersion = libs.versions.parchment.get() } validateAccessTransformers = true @@ -41,7 +31,6 @@ neoForge { mods { create(modId) { sourceSet(project.sourceSets.main.get()) - sourceSet(project(":common").sourceSets.main.get()) } } @@ -63,22 +52,15 @@ sourceSets.main.get().resources.srcDir("src/generated/resources") dependencies { // Adds KFF as dependency and Kotlin libs - implementation("thedarkcolour:kotlinforforge-neoforge:$kotlinForgeVersion") - - configurations.additionalRuntimeClasspath.extendsFrom(configurations.runtimeLib) - configurations.jarJar.extendsFrom(configurations.includeBotDep) -} + implementation(libs.kff) -tasks { - // Fixes IDE runs not processing common resources - processResources { - from(project(":common").sourceSets.main.get().resources) - } + configurations.named("additionalRuntimeClasspath").extendsFrom(configurations.botLib) + configurations.jarJar.extendsFrom(configurations.botLib) } publishMods { - val minecraftVersion: String by project - val title: String by project + val minecraftVersion: String = libs.versions.minecraft.get() + val modName: String by project val version: String by project val titles: Map by extra @@ -93,7 +75,7 @@ publishMods { modLoaders.add(project.name) file.set(tasks.jar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" + displayName = "$modName $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" requires("kotlin-for-forge") } @@ -103,7 +85,7 @@ publishMods { modLoaders.add(project.name) file.set(tasks.jar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" + displayName = "$modName $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" requires("kotlin-for-forge") } diff --git a/neoforge/src/main/kotlin/dev/erdragh/astralbot/neoforge/BotMod.kt b/neoforge/src/main/kotlin/dev/erdragh/astralbot/neoforge/BotMod.kt index 98fcc39..f3a3fbc 100644 --- a/neoforge/src/main/kotlin/dev/erdragh/astralbot/neoforge/BotMod.kt +++ b/neoforge/src/main/kotlin/dev/erdragh/astralbot/neoforge/BotMod.kt @@ -26,8 +26,8 @@ import thedarkcolour.kotlinforforge.neoforge.forge.MOD_BUS @Mod("astralbot") object BotMod { init { - ModLoadingContext.get().activeContainer.registerConfig(ModConfig.Type.SERVER, AstralBotConfig.SPEC) - ModLoadingContext.get().activeContainer.registerConfig(ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text.toml") + ModLoadingContext.get().activeContainer.registerConfig(ModConfig.Type.COMMON, AstralBotConfig.SPEC, "astralbot-server.toml") + ModLoadingContext.get().activeContainer.registerConfig(ModConfig.Type.COMMON, AstralBotTextConfig.SPEC, "astralbot-text.toml") MOD_BUS.addListener(::onConfigReloaded) FORGE_BUS.addListener(::onServerStart) diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 4d4e7e8..15d0594 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -1,5 +1,5 @@ modLoader = "kotlinforforge" -loaderVersion = "${kff_loader_range}" +loaderVersion = "${kff_version_range}" license = "${license}" issueTrackerURL = "https://github.com/Erdragh/AstralBot/issues" @@ -17,14 +17,14 @@ logoFile = "icon.png" authors = "${mod_author}" description = "${description}" -[[dependencies.${mod_id}]] +[[dependencies."${mod_id}"]] modId = "neoforge" type = "required" -versionRange = "${neoforge_loader_version_range}" +versionRange = "${neoforge_range}" ordering = "NONE" side = "BOTH" -[[dependencies.${mod_id}]] +[[dependencies."${mod_id}"]] modId = "minecraft" type = "required" versionRange = "${minecraft_version_range}" diff --git a/settings.gradle.kts b/settings.gradle.kts index 621f357..91f230d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,7 +18,9 @@ plugins { dependencyResolutionManagement { versionCatalogs { - register("libs") + register("libs") { + from(files("libs.versions.toml")) + } register("jda") { from(files("gradle/jda.versions.toml")) } From 315a57bbab1c2b5656f41db02fc684d93bf17bdb Mon Sep 17 00:00:00 2001 From: Erdragh Date: Thu, 24 Oct 2024 12:32:31 +0200 Subject: [PATCH 5/6] Close webhook client on shutdown --- common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt | 1 + .../kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt index fe2f4cc..35af1f6 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/Bot.kt @@ -155,6 +155,7 @@ fun startAstralbot(server: MinecraftServer) { fun stopAstralbot() { LOGGER.info("Shutting down AstralBot") shuttingDown.set(true) + minecraftHandler?.close() if (baseDirectory != null) FAQHandler.stop() if (jda != null) { jda!!.shutdown() 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 985e14b..07951eb 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/handlers/MinecraftHandler.kt @@ -490,4 +490,8 @@ class MinecraftHandler(private val server: MinecraftServer) : ListenerAdapter() private fun useWebhooks(): Boolean { return AstralBotConfig.WEBHOOK_ENABLED.get() && webhookClient != null } + + fun close() { + webhookClient?.close() + } } \ No newline at end of file From 6061ac7d5c0635d5ee3b05638d44fb36bc525c72 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Sat, 8 Feb 2025 09:53:55 +0100 Subject: [PATCH 6/6] Improve Gradle build setup --- .gitignore | 1 + build.gradle.kts | 356 +----------------- buildSrc/build.gradle.kts | 14 + buildSrc/settings.gradle.kts | 7 + .../src/main/groovy/multiloader-common.gradle | 204 ++++++++++ .../src/main/groovy/multiloader-loader.gradle | 99 +++++ common/build.gradle.kts | 50 ++- .../astralbot/config/AstralBotConfig.kt | 4 +- ...mmon.mixins.json => astralbot.mixins.json} | 1 + fabric/build.gradle.kts | 74 ++-- ...xins.json => astralbot.fabric.mixins.json} | 1 + fabric/src/main/resources/fabric.mod.json | 8 +- forge/build.gradle.kts | 120 +++--- .../dev/erdragh/astralbot/forge/BotMod.kt | 6 +- forge/src/main/resources/META-INF/mods.toml | 10 +- ...ixins.json => astralbot.forge.mixins.json} | 1 + gradle.properties | 28 +- gradle/dcwebhooks.versions.toml | 7 + gradle/exposed.versions.toml | 7 + gradle/jda.versions.toml | 23 ++ gradle/wrapper/gradle-wrapper.properties | 2 +- libs.versions.toml | 59 +++ settings.gradle.kts | 19 +- 23 files changed, 602 insertions(+), 499 deletions(-) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/settings.gradle.kts create mode 100644 buildSrc/src/main/groovy/multiloader-common.gradle create mode 100644 buildSrc/src/main/groovy/multiloader-loader.gradle rename common/src/main/resources/{astralbot-common.mixins.json => astralbot.mixins.json} (86%) rename fabric/src/main/resources/{astralbot.mixins.json => astralbot.fabric.mixins.json} (85%) rename forge/src/main/resources/{astralbot.mixins.json => astralbot.forge.mixins.json} (85%) create mode 100644 gradle/dcwebhooks.versions.toml create mode 100644 gradle/exposed.versions.toml create mode 100644 gradle/jda.versions.toml create mode 100644 libs.versions.toml diff --git a/.gitignore b/.gitignore index f95b34b..5380871 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ faq # Minecraft **/run +**/runs # Architectury .architectury-transformer \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 9f45c9c..ba23668 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,356 +1,12 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.jetbrains.kotlin.gradle.utils.extendsFrom -import java.nio.charset.StandardCharsets -import java.text.SimpleDateFormat -import java.util.* -import dev.architectury.plugin.ArchitectPluginExtension -import net.fabricmc.loom.api.LoomGradleExtensionAPI -import net.fabricmc.loom.task.RemapJarTask - plugins { - // This is an Architectury repository, as such the relevant plugins are needed - id("architectury-plugin") version "3.4-SNAPSHOT" - id("dev.architectury.loom") version "1.7-SNAPSHOT" apply false - // The shadow plugin is used by the fabric subproject to include dependencies - // I'm temporarily using a fork of the original plugin to resolve "Unsupported java classfile major version 65" - // see: https://github.com/johnrengelman/shadow/issues/911 - id("io.github.goooler.shadow") version "8.1.8" apply false - // Since this mod/bot is written in Kotlin and expected to run on Minecraft and as such - // the JVM, the Kotlin plugin is needed - kotlin("jvm") version "2.0.10" - // For generating documentation based on comments in the code - id("org.jetbrains.dokka") version "1.9.10" - java - // For publishing the mod - id("me.modmuss50.mod-publish-plugin") version "0.5.1" -} - -val minecraftVersion: String by project - -architectury { - minecraft = minecraftVersion -} - -repositories { - mavenCentral() -} - -subprojects { - apply(plugin = "dev.architectury.loom") - apply(plugin = "architectury-plugin") - apply(plugin = "java") - apply(plugin = "kotlin") - apply(plugin = "org.jetbrains.dokka") - apply(plugin = "me.modmuss50.mod-publish-plugin") - - // Gets some values from the gradle.properties files in the - // sub- and root projects - val modLoader = project.name - val modId: String by project - val modName = rootProject.name - val modAuthor: String by project - val isCommon = modLoader == rootProject.projects.common.name - - base { - // This will be the final name of the exported JAR file - archivesName.set("$modId-$modLoader-$minecraftVersion") - } - - configure { - silentMojangMappingsLicense() - } - - extensions.configure { - toolchain.languageVersion.set(JavaLanguageVersion.of(17)) - withSourcesJar() - } - - repositories { - mavenCentral() - maven(url = "https://maven.architectury.dev/") - maven("https://repo.spongepowered.org/repository/maven-public/") { name = "Sponge / Mixin" } - maven("https://maven.blamejared.com") { name = "BlameJared Maven (JEI / CraftTweaker / Bookshelf)" } - // For the parchment mappings - maven(url = "https://maven.parchmentmc.org") - maven(url = "https://maven.resourcefulbees.com/repository/maven-public/") - maven { - name = "Kotlin for Forge" - setUrl("https://thedarkcolour.github.io/KotlinForForge/") - } - // Forge Config API port - maven { - name = "Fuzs Mod Resources" - setUrl("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") - } - } - - // Bot dependencies - val jdaVersion: String by project - val dcWebhooksVersion: String by project - val exposedVersion: String by project - val sqliteJDBCVersion: String by project - val commonmarkVersion: String by project - - // Configuration for shaded dependencies, get relocated to dev.erdragh.astralbot.shadowed - val shadowBotDep by configurations.creating { - isTransitive = true - } - // This shadowCommon configuration is used to shade the - // common project - val shadowCommon by configurations.creating { - isCanBeConsumed = false - isCanBeResolved = true - } - // Configuration for libraries that are needed at runtime - val runtimeLib by configurations.creating { - isTransitive = true - } - configurations.implementation.extendsFrom(configurations.named("shadowBotDep")) - configurations.implementation.extendsFrom(configurations.named("runtimeLib")) - - dependencies { - // Minecraft Mod dependencies - "minecraft"("::$minecraftVersion") - - @Suppress("UnstableApiUsage") - "mappings"(project.the().layered { - val parchmentVersion: String by project - - officialMojangMappings() - - parchment( - create( - group = "org.parchmentmc.data", - name = "parchment-$minecraftVersion", - version = parchmentVersion - ) - ) - }) - - runtimeLib("org.xerial:sqlite-jdbc:$sqliteJDBCVersion") - if (!isCommon) "include"("org.xerial:sqlite-jdbc:$sqliteJDBCVersion") - - runtimeLib("org.commonmark:commonmark:$commonmarkVersion") - if (!isCommon) "include"("org.commonmark:commonmark:$commonmarkVersion") - - arrayOf( - // Library used to communicate with Discord, see https://jda.wiki - "net.dv8tion:JDA:$jdaVersion", - // Library used for sending messages via Discord Webhooks - "club.minnced:discord-webhooks:$dcWebhooksVersion", - - // Library to interact with the SQLite database, - // see: https://github.com/JetBrains/Exposed - "org.jetbrains.exposed:exposed-core:$exposedVersion", - "org.jetbrains.exposed:exposed-dao:$exposedVersion", - "org.jetbrains.exposed:exposed-jdbc:$exposedVersion", - ).forEach { - implementation(it) { - exclude(module = "opus-java") - exclude(group = "org.slf4j") - } - runtimeLib(it) { - exclude(module = "opus-java") - exclude(group = "org.slf4j") - exclude(group = "org.jetbrains.kotlin") - exclude(group = "org.jetbrains.kotlinx") - } - shadowBotDep(it) { - // opus-java is for audio, which this bot doesn't need - exclude(module = "opus-java") - // Kotlin would be included as a transitive dependency - // on JDA and Exposed, but is already provided by the - // respective Kotlin implementation of the mod loaders - exclude(group = "org.jetbrains.kotlin") - exclude(group = "org.jetbrains.kotlinx") - // Minecraft already ships with a logging system - exclude(group = "org.slf4j") - } - } - } - - java { - withSourcesJar() - modularity.inferModulePath = true - } - - tasks.jar { - // Results in the not remapped jars having a -dev at the end - archiveClassifier.set("dev") - - from(rootProject.file("LICENSE")) { - rename { "${it}_$modId" } - } - - manifest { - attributes( - "Specification-Title" to modId, - "Specification-Vendor" to modAuthor, - "Specification-Version" to archiveVersion, - "Implementation-Title" to project.name, - "Implementation-Version" to archiveVersion, - "Implementation-Vendor" to modAuthor, - "Implementation-Timestamp" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(Date()), - "Timestamp" to System.currentTimeMillis(), - "Built-On-Java" to "${System.getProperty("java.vm.version")} (${System.getProperty("java.vm.vendor")})", - "Built-On-Minecraft" to minecraftVersion - ) - } - } - - tasks.processResources { - val version: String by project - val group: String by project - val fabricApiVersion: String by project - val fabricLoaderVersion: String by project - val fabricKotlinVersion: String by project - val license: String by project - val description: String by project - val credits: String by project - val title: String by project - - val expandProps = mapOf( - "version" to version, - "group" to group, //Else we target the task's group. - "minecraft_version" to minecraftVersion, - "fabric_version" to fabricApiVersion, - "fabric_loader_version" to fabricLoaderVersion, - "fabric_kotlin_version" to fabricKotlinVersion, - "mod_name" to modName, - "mod_author" to modAuthor, - "mod_id" to modId, - "license" to license, - "description" to description, - "credits" to credits, - "title" to title - ) - - filesMatching(listOf("pack.mcmeta", "*.mixins.json", "META-INF/mods.toml", "fabric.mod.json")) { - expand(expandProps) - } - inputs.properties(expandProps) - } - - if (!isCommon) { - apply(plugin = "io.github.goooler.shadow") - - configure { - platformSetupLoomIde() - } - - tasks.named("shadowJar") { - // The shadowBotDep configuration was explicitly made to be shaded in, this is where that happens - configurations.clear() - configurations = listOf(shadowBotDep, shadowCommon) - - // This transforms the service files to make relocated Exposed work (see: https://github.com/JetBrains/Exposed/issues/1353) - mergeServiceFiles() - - // Forge restricts loading certain classes for security reasons. - // Luckily, shadow can relocate them to a different package. - relocate("org.apache.commons.collections4", "dev.erdragh.shadowed.org.apache.commons.collections4") - - // Relocating Exposed somewhere different so other mods not doing that don't run into issues (e.g. Ledger) - relocate("org.jetbrains.exposed", "dev.erdragh.shadowed.org.jetbrains.exposed") - - // Relocating jackson to prevent incompatibilities with other mods also bundling it (e.g. GroovyModLoader on Forge) - relocate("com.fasterxml.jackson", "dev.erdragh.shadowed.com.fasterxml.jackson") - - // relocate discord interaction stuff to maybe allow other discord integrations mods to work - relocate("club.minnced.discord", "dev.erdragh.shadowed.club.minnced.discord") - relocate("net.dv8tion.jda", "dev.erdragh.shadowed.net.dv8tion.jda") - - // relocate dependencies of discord stuff - relocate("okhttp3", "dev.erdragh.shadowed.okhttp3") - relocate("okio", "dev.erdragh.shadowed.okio") - relocate("gnu.trove", "dev.erdragh.shadowed.gnu.trove") - relocate("com.iwebpp.crypto", "dev.erdragh.shadowed.com.iwebpp.crypto") - relocate("com.neovisionaries.ws", "dev.erdragh.shadowed.com.neovisionaries.ws") - relocate("org.json", "dev.erdragh.shadowed.org.json") - relocate("net.bytebuddy", "dev.erdragh.shadowed.net.bytebuddy") - - relocate("com.google", "dev.erdragh.shadowed.com.google") - relocate("google", "dev.erdragh.shadowed.google") - relocate("javax.annotation", "dev.erdragh.shadowed.javax.annotation") - - exclude("**/org/slf4j/**") - - exclude("**/org/jetbrains/annotations/*") - exclude("**/org/intellij/**") - } - - tasks.named("remapJar") { - inputFile.set(tasks.named("shadowJar").get().archiveFile) - dependsOn("shadowJar") - // Results in the remapped jar not having any extra bit in - // its file name, identifying it as the main distribution - archiveClassifier.set(null as String?) - } - } - - // Disables Gradle's custom module metadata from being published to maven. The - // metadata includes mapped dependencies which are not reasonably consumable by - // other mod developers. - tasks.withType { - enabled = false - } - - tasks.withType { - options.encoding = "UTF-8" - targetCompatibility = JavaVersion.VERSION_17.majorVersion - sourceCompatibility = JavaVersion.VERSION_17.majorVersion - } - - // Publishing settings - if (!isCommon) { - publishMods { - // These titles get used based on subproject name - val titles by extra { - mapOf( - "fabric" to "Fabric", - "neoforge" to "NeoForge", - "forge" to "Forge", - "quilt" to "Quilt" - ) - } - val curseforgePublish by extra { - curseforgeOptions { - accessToken = providers.environmentVariable("CURSEFORGE_TOKEN") - minecraftVersions.add(minecraftVersion) - projectId = providers.environmentVariable("CURSEFORGE_ID") - embeds("sqlite-jdbc") - } - } - val modrinthPublish by extra { - modrinthOptions { - accessToken = providers.environmentVariable("MODRINTH_TOKEN") - minecraftVersions.add(minecraftVersion) - projectId = providers.environmentVariable("MODRINTH_ID") - embeds("sqlite-jdbc") - } - } - val changelog by extra { - // Only gets the lines for the latest version from the Changelog - // file. This allows me to keep all previous changes in the file - // without having to worry about them being included on new file - // uploads. - File(rootDir, "CHANGELOG.md") - .readText(StandardCharsets.UTF_8) - .replace(Regex("[^^](#(#|\\n|.)+)|(^#.+)"), "") - .trim() - } - val type by extra { - STABLE - } - } - } -} - -kotlin { - jvmToolchain(17) + // see https://fabricmc.net/develop/ for new versions + alias(libs.plugins.loom) apply false + // see https://projects.neoforged.net/neoforged/moddevgradle for new versions + alias(libs.plugins.moddev) apply false + // so we can enable soruce download + idea } - // IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior. idea { module { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..f80c745 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("groovy-gradle-plugin") +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}") + implementation("org.jetbrains.dokka:dokka-gradle-plugin:${libs.versions.dokka.get()}") + implementation("me.modmuss50:mod-publish-plugin:${libs.versions.publish.get()}") +} + +repositories { + mavenCentral() + gradlePluginPortal() +} \ No newline at end of file diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 0000000..36adc8e --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + register("libs") { + from(files("../libs.versions.toml")) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle new file mode 100644 index 0000000..f9ab7af --- /dev/null +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -0,0 +1,204 @@ +import org.jetbrains.dokka.gradle.DokkaTaskPartial + +plugins { + id 'java-library' + id 'maven-publish' + id "org.jetbrains.kotlin.jvm" + id "org.jetbrains.dokka" +} + +base { + archivesName = "${modId}-${project.name}-${libs.versions.minecraft.get()}" +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(libs.versions.java.get()) + withSourcesJar() + withJavadocJar() +} + +kotlin { + jvmToolchain(Integer.parseInt(libs.versions.java.get())) +} + +repositories { + mavenCentral() + exclusiveContent { + forRepositories( + maven { + name = 'ParchmentMC' + url = 'https://maven.parchmentmc.org/' + }, + maven { + name = "Forge" + url = 'https://maven.minecraftforge.net' + } + ) + filter { includeGroup('org.parchmentmc.data') } + } + maven { + name = 'BlameJared' + url = 'https://maven.blamejared.com' + } + maven { + name = "kotlinforforge" + url = uri("https://thedarkcolour.github.io/KotlinForForge/") + } + maven { + name = "Sponge / Mixin" + url = "https://repo.spongepowered.org/repository/maven-public/" + } + // Forge Config API port + maven { + name = "Fuzs Mod Resources" + setUrl("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + } +} + +// Declare capabilities on the outgoing configurations. +// Read more about capabilities here: https://docs.gradle.org/current/userguide/component_capabilities.html#sec:declaring-additional-capabilities-for-a-local-component +['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant -> + configurations."$variant".outgoing { + capability("$group:${base.archivesName.get()}:$version") + capability("$group:$modId-${project.name}-${libs.versions.minecraft.get()}:$version") + capability("$group:$modId:$version") + } + publishing.publications.configureEach { + suppressPomMetadataWarningsFor(variant) + } +} + +sourcesJar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${modId}" } + } +} + +jar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${modId}" } + } + + manifest { + attributes([ + 'Specification-Title' : modName, + 'Specification-Vendor' : modAuthor, + 'Specification-Version' : project.jar.archiveVersion, + 'Implementation-Title' : project.name, + 'Implementation-Version': project.jar.archiveVersion, + 'Implementation-Vendor' : modAuthor, + 'Built-On-Minecraft' : libs.versions.minecraft.get() + ]) + } +} + +tasks.withType(DokkaTaskPartial).configureEach { + dokkaSourceSets.configureEach { + includeNonPublic = false + skipDeprecated = false + reportUndocumented = false + jdkVersion = Integer.parseInt(libs.versions.java.get()) + sourceRoots.from(sourceSets.main.allSource) + } +} + +// Prevent the default javadoc task from running, as Dokka is +// responsible for generating the docs now +tasks.named("javadoc", Javadoc) { + enabled = false +} + +// Make the javadoc jar take in the Dokka output +tasks.named("javadocJar", Jar) { + dependsOn(tasks.named("dokkaJavadoc")) + from(tasks.named("dokkaJavadoc")) +} + +processResources { + var expandProps = [ + 'version' : version, + 'group' : project.group, //Else we target the task's group. + 'minecraft_version' : libs.versions.minecraft.get(), + 'minecraft_version_range' : libs.versions.minecraftRange.get(), + 'fabric_version' : libs.versions.fabricApi.get(), + 'fabric_loader_version' : libs.versions.fabricLoader.get(), + 'flk_version' : libs.versions.flk.get(), + 'mod_name' : modName, + 'mod_author' : modAuthor, + 'mod_id' : modId, + 'license' : license, + 'description' : project.description, + 'forge_version' : libs.versions.forge.get(), + 'forge_range' : libs.versions.forgeRange.get(), + 'kff_version' : libs.versions.kff.get(), + 'kff_version_range' : libs.versions.kffRange.get(), + 'credits' : credits, + 'java_version' : libs.versions.java.get(), + 'fcapi_version' : libs.versions.fcapi.get() + ] + + filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/*mods.toml', '*.mixins.json']) { + expand expandProps + } + inputs.properties(expandProps) +} + +publishing { + publications { + register('mavenJava', MavenPublication) { + artifactId base.archivesName.get() + from components.java + } + } + repositories { + maven { + url System.getenv('local_maven_url') + } + } +} + + +configurations { + botLib { + transitive = false + } + implementation.extendsFrom(botLib) +} + +dependencies { + [ + // Library to build a connection with the sqlite database + libs.sqlite, + // Library used to parse and convert markdown + libs.commonmark, + + // Library used to communicate with Discord, see https://jda.wiki + jda.jda, + // JDA's dependencies + jda.commons.collections, + jda.trove4j, + jda.jackson.annotations, + jda.jackson.core, + jda.jackson.databind, + jda.websocket, + jda.okhttp, + jda.okio, + jda.tink, + // Library used for sending messages via Discord Webhooks + dcwebhooks.webhooks, + dcwebhooks.json, + + // Library to interact with the SQLite database, + // see: https://github.com/JetBrains/Exposed + exposed.core, + exposed.dao, + exposed.jdbc, + ].forEach { + botLib(it) { + exclude group: "org.slf4j" + exclude group: "org.jetbrains.kotlin" + exclude group: "org.jetbrains.kotlinx" + exclude module: "opus-java" + } + } +} diff --git a/buildSrc/src/main/groovy/multiloader-loader.gradle b/buildSrc/src/main/groovy/multiloader-loader.gradle new file mode 100644 index 0000000..3ef4358 --- /dev/null +++ b/buildSrc/src/main/groovy/multiloader-loader.gradle @@ -0,0 +1,99 @@ +import org.jetbrains.dokka.gradle.DokkaTask + +import java.nio.file.Files + +plugins { + id 'multiloader-common' + id "org.jetbrains.kotlin.jvm" + id "me.modmuss50.mod-publish-plugin" +} + +configurations { + commonJava { + canBeResolved = true + } + commonKotlin { + canBeResolved = true + } + commonResources { + canBeResolved = true + } +} + +dependencies { + compileOnly(project(':common')) { + capabilities { + requireCapability "$group:$modId" + } + } + commonJava project(path: ':common', configuration: 'commonJava') + commonKotlin project(path: ':common', configuration: 'commonKotlin') + commonResources project(path: ':common', configuration: 'commonResources') +} + +tasks.named('compileJava', JavaCompile) { + dependsOn(configurations.commonJava) + source(configurations.commonJava) +} + +tasks.named('compileKotlin') { + dependsOn(configurations.commonKotlin) + dependsOn(configurations.commonJava) + source(configurations.commonJava) + source(configurations.commonKotlin) +} + +processResources { + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} + +tasks.named('sourcesJar', Jar) { + dependsOn(configurations.commonJava) + from(configurations.commonJava) + dependsOn(configurations.commonKotlin) + from(configurations.commonKotlin) + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} + +// Use dokka to generate javadoc for both Java and Kotlin sources +// instead of using the builtin javadoc tools. This allows mixing +// Kotlin and Java +tasks.named("dokkaJavadoc", DokkaTask) { + dependsOn(configurations.commonJava) + dependsOn(configurations.commonKotlin) + dokkaSourceSets.configureEach { + sourceRoots.from(configurations.commonJava.singleFile, configurations.commonKotlin.singleFile) + } +} + + +// These titles get used based on subproject name +ext.titles = [ + "fabric" : "Fabric", + "neoforge" : "NeoForge", + "forge" : "Forge" +] +ext.curseforgePublish = publishMods.curseforgeOptions { + accessToken = providers.environmentVariable("CURSEFORGE_TOKEN") + minecraftVersions.add(libs.versions.minecraft.get()) + projectId = providers.environmentVariable("CURSEFORGE_ID") + embeds("sqlite-jdbc") +} +ext.modrinthPublish = publishMods.modrinthOptions { + accessToken = providers.environmentVariable("MODRINTH_TOKEN") + minecraftVersions.add(libs.versions.minecraft.get()) + projectId = providers.environmentVariable("MODRINTH_ID") + embeds("sqlite-jdbc") +} + +// Only gets the lines for the latest version from the Changelog +// file. This allows me to keep all previous changes in the file +// without having to worry about them being included on new file +// uploads. +ext.changelog = Files.readString(rootDir.toPath().resolve("CHANGELOG.md")) + .replaceAll("[^^](#(#|\\n|.)+)|(^#.+)", "") + .trim() + +ext.type = publishMods.STABLE \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 74e9fcb..d492c2f 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,14 +1,46 @@ -architectury { - val enabledPlatforms: String by rootProject - common(enabledPlatforms.split(",")) +plugins { + id("multiloader-common") + alias(libs.plugins.moddev) +} + +legacyForge { + mcpVersion = libs.versions.mcp.get() + // Automatically enable AccessTransformers if the file exists + val at = file("src/main/resources/META-INF/accesstransformer.cfg") + if (at.exists()) { + accessTransformers.from(at.absolutePath) + } + parchment { + minecraftVersion = libs.versions.parchmentMC.get() + mappingsVersion = libs.versions.parchment.get() + } } dependencies { - val fabricLoaderVersion: String by project - val forgeConfigAPIVersion: String by project - // We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies - // Do NOT use other classes from fabric loader - modImplementation("net.fabricmc:fabric-loader:${fabricLoaderVersion}") + api(libs.slf4j) + compileOnly(libs.kotlinx.coroutines) + compileOnly(libs.mixin) + + api(libs.fcapi.common) +} + +configurations { + create("commonJava") { + isCanBeResolved = false + isCanBeConsumed = true + } + create("commonKotlin") { + isCanBeResolved = false + isCanBeConsumed = true + } + create("commonResources") { + isCanBeResolved = false + isCanBeConsumed = true + } +} - api("fuzs.forgeconfigapiport:forgeconfigapiport-common:$forgeConfigAPIVersion") +artifacts { + add("commonJava", sourceSets.main.get().java.sourceDirectories.singleFile) + add("commonKotlin", sourceSets.main.get().kotlin.sourceDirectories.filter { !it.name.endsWith("java") }.singleFile) + add("commonResources", sourceSets.main.get().resources.sourceDirectories.singleFile) } \ 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 66b0194..881a77e 100644 --- a/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt +++ b/common/src/main/kotlin/dev/erdragh/astralbot/config/AstralBotConfig.kt @@ -141,9 +141,9 @@ object AstralBotConfig { DISCORD_CHANNEL = builder.comment("Channel ID where the chat messages are synced") .defineInRange("discordChannel", 0L, 0L, Long.MAX_VALUE) DISCORD_GUILD = builder.comment("Guild (server) ID where the chat messages etc. are synced") - .defineInRange("discordChannel", 0L, 0L, Long.MAX_VALUE) + .defineInRange("discordGuild", 0L, 0L, Long.MAX_VALUE) DISCORD_ROLE = builder.comment("ID of the role given to linked users") - .defineInRange("discordChannel", 0L, 0L, Long.MAX_VALUE) + .defineInRange("discordRole", 0L, 0L, Long.MAX_VALUE) CLICKABLE_MESSAGES = builder.comment("Whether to make messages sent into the Minecraft chat open the Discord chat when clicked") diff --git a/common/src/main/resources/astralbot-common.mixins.json b/common/src/main/resources/astralbot.mixins.json similarity index 86% rename from common/src/main/resources/astralbot-common.mixins.json rename to common/src/main/resources/astralbot.mixins.json index 215a460..021f3c9 100644 --- a/common/src/main/resources/astralbot-common.mixins.json +++ b/common/src/main/resources/astralbot.mixins.json @@ -2,6 +2,7 @@ "required": true, "minVersion": "0.8", "package": "dev.erdragh.astralbot.mixins", + "refmap": "${mod_id}.refmap.json", "compatibilityLevel": "JAVA_17", "server": [ "PlayerListMixin", diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 1dcb324..ba625b1 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -1,43 +1,61 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import me.modmuss50.mpp.ReleaseType import me.modmuss50.mpp.platforms.curseforge.CurseforgeOptions import me.modmuss50.mpp.platforms.modrinth.ModrinthOptions -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -architectury { - fabric() +plugins { + id("multiloader-loader") + alias(libs.plugins.loom) } -val common: Configuration by configurations.creating { - configurations.compileClasspath.get().extendsFrom(this) - configurations.runtimeClasspath.get().extendsFrom(this) - configurations["developmentFabric"].extendsFrom(this) -} +val modId: String by project + +val botLib: Configuration by configurations.getting dependencies { - common(project(":common", configuration = "namedElements")) { - isTransitive = false - } - shadowCommon(project(path = ":common", configuration = "transformProductionFabric")) { - isTransitive = false - } + minecraft(libs.minecraft) + mappings(loom.layered { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${libs.versions.parchmentMC.get()}:${libs.versions.parchment.get()}@zip") + }) + modImplementation(libs.fabricLoader) + modImplementation(libs.fabricApi) - val minecraftVersion: String by project - val fabricLoaderVersion: String by project - val fabricApiVersion: String by project - val fabricKotlinVersion: String by project - val forgeConfigAPIVersion: String by project + modImplementation(libs.flk) - modImplementation(group = "net.fabricmc", name = "fabric-loader", version = fabricLoaderVersion) - modApi(group = "net.fabricmc.fabric-api", name = "fabric-api", version = "$fabricApiVersion+$minecraftVersion") - modImplementation("net.fabricmc:fabric-language-kotlin:${fabricKotlinVersion}") + modApi(libs.fcapi.fabric) - modApi("fuzs.forgeconfigapiport:forgeconfigapiport-fabric:$forgeConfigAPIVersion") + botLib.dependencies.forEach { include(it) } +} + +loom { + val aw = project(":common").file("src/main/resources/${modId}.accesswidener") + if (aw.exists()) { + accessWidenerPath.set(aw) + } + mixin { + defaultRefmapName.set("${modId}.refmap.json") + } + runs { + named("client") { + client() + setConfigName("Fabric Client") + ideConfigGenerated(true) + mkdir("runs/server") + runDir("runs/client") + } + named("server") { + server() + setConfigName("Fabric Server") + ideConfigGenerated(true) + mkdir("runs/server") + runDir("runs/server") + } + } } publishMods { - val minecraftVersion: String by project - val title: String by project + val minecraftVersion = libs.versions.minecraft.get() + val modName: String by project val version: String by project val titles: Map by extra @@ -52,7 +70,7 @@ publishMods { modLoaders.add(project.name) file.set(tasks.remapJar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" + displayName = "$modName $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" requires("fabric-language-kotlin", "forge-config-api-port-fabric", "fabric-api") } @@ -62,7 +80,7 @@ publishMods { modLoaders.add(project.name) file.set(tasks.remapJar.get().archiveFile) additionalFiles.plus(tasks.sourcesJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" + displayName = "$modName $version ${titles[project.name]} $minecraftVersion" this.version = "$version-mc$minecraftVersion-${project.name}" requires("fabric-language-kotlin", "forge-config-api-port", "fabric-api") } diff --git a/fabric/src/main/resources/astralbot.mixins.json b/fabric/src/main/resources/astralbot.fabric.mixins.json similarity index 85% rename from fabric/src/main/resources/astralbot.mixins.json rename to fabric/src/main/resources/astralbot.fabric.mixins.json index 5dfcea1..2e68eba 100644 --- a/fabric/src/main/resources/astralbot.mixins.json +++ b/fabric/src/main/resources/astralbot.fabric.mixins.json @@ -3,6 +3,7 @@ "minVersion": "0.8", "package": "dev.erdragh.astralbot.mixins.fabric", "compatibilityLevel": "JAVA_17", + "refmap": "${mod_id}.refmap.json", "mixins": [ ], "client": [ diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 7e1d446..d162068 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -24,14 +24,14 @@ ] }, "mixins": [ - "astralbot-common.mixins.json", - "astralbot.mixins.json" + "astralbot.mixins.json", + "astralbot.fabric.mixins.json" ], "depends": { "fabric": "*", "minecraft": ">=${minecraft_version}", "java": ">=17", - "fabric-language-kotlin": ">=${fabric_kotlin_version}", - "forgeconfigapiport": ">=8.0.0" + "fabric-language-kotlin": ">=${flk_version}", + "forgeconfigapiport": ">=${fcapi_version}" } } \ No newline at end of file diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index c8fb2a8..c3ed467 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -1,85 +1,63 @@ -import me.modmuss50.mpp.ReleaseType -import me.modmuss50.mpp.platforms.curseforge.CurseforgeOptions -import me.modmuss50.mpp.platforms.modrinth.ModrinthOptions +import org.gradle.internal.extensions.stdlib.capitalized +import org.jetbrains.kotlin.gradle.utils.extendsFrom -architectury { - forge() +plugins { + id("multiloader-loader") + alias(libs.plugins.moddev) } -loom { - forge { - mixinConfig("astralbot-common.mixins.json") - mixinConfig("astralbot.mixins.json") +val modId: String by project + +mixin { + add(sourceSets.main.get(), "${modId}.refmap.json") + config("${modId}.mixins.json") + config("${modId}.forge.mixins.json") +} +tasks.jar { + manifest { + attributes["MixinConfigs"] = "${modId}.mixins.json,${modId}.forge.mixins.json" + } +} + +legacyForge { + version = libs.versions.forge.get() + // Automatically enable neoforge AccessTransformers if the file exists + val at = project(":common").file("src/main/resources/META-INF/accesstransformer.cfg") + if (at.exists()) { + accessTransformers.from(at.absolutePath) + } + parchment { + minecraftVersion = libs.versions.parchmentMC.get() + mappingsVersion = libs.versions.parchment.get() } - // This sets up data generation. At the time of writing this - // Comment, this is useless, as there are no resources to be - // generated. I want to keep it in as a reference tho. runs { - create("data") { + configureEach { + systemProperty("forge.enabledGameTestNamespaces", modId) + ideName = "Forge ${name.capitalized()} (${project.path})" // Unify the run config names with fabric + } + register("client") { + client() + } + register("data") { data() - programArgs("--all", "--mod", "astralbot") - programArgs("--output", project(":common").file("src/main/generated/resources").absolutePath) - programArgs("--existing", project(":common").file("src/main/resources").absolutePath) + } + register("server") { + server() } } -} - -val common: Configuration by configurations.creating { - configurations.compileClasspath.get().extendsFrom(this) - configurations.runtimeClasspath.get().extendsFrom(this) - configurations["developmentForge"].extendsFrom(this) -} - -val runtimeLib by configurations.getting - -dependencies { - common(project(":common", configuration = "namedElements")) { - isTransitive = false - } - shadowCommon(project(path = ":common", configuration = "transformProductionForge")) { - isTransitive = false + mods { + register(modId) { + sourceSet(sourceSets.main.get()) + } } - - val minecraftVersion: String by project - val forgeVersion: String by project - val kotlinForgeVersion: String by project - - forge(group = "net.minecraftforge", name = "forge", version = "$minecraftVersion-$forgeVersion") - // Adds KFF as dependency and Kotlin libs - implementation("thedarkcolour:kotlinforforge:$kotlinForgeVersion") - - // This *should* theoretically fix the Forge development environment not having - // access to certain classes, but I haven't gotten it to work just yet. - runtimeLib.dependencies.forEach(::forgeRuntimeLibrary) } -publishMods { - val minecraftVersion: String by project - val title: String by project - val version: String by project - - val titles: Map by extra - val curseforgePublish: Provider by extra - val modrinthPublish: Provider by extra - - changelog = extra.get("changelog") as String - type = extra.get("type") as ReleaseType +sourceSets.main.get().resources { srcDir("src/generated/resources") } - curseforge("curseForge") { - from(curseforgePublish) - modLoaders.add(project.name) - file.set(tasks.remapJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" - this.version = "$version-mc$minecraftVersion-${project.name}" - requires("kotlin-for-forge") - } +dependencies { + implementation(libs.kff) + annotationProcessor(variantOf(libs.mixin) { classifier("processor") }) - modrinth("modrinthForge") { - from(modrinthPublish) - modLoaders.add(project.name) - file.set(tasks.remapJar.get().archiveFile) - displayName = "$title $version ${titles[project.name]} $minecraftVersion" - this.version = "$version-mc$minecraftVersion-${project.name}" - requires("kotlin-for-forge") - } + configurations.named("additionalRuntimeClasspath").extendsFrom(configurations.botLib) + configurations.jarJar.extendsFrom(configurations.botLib) } \ 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 6b7189a..511b0a4 100644 --- a/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt +++ b/forge/src/main/kotlin/dev/erdragh/astralbot/forge/BotMod.kt @@ -11,8 +11,6 @@ import dev.erdragh.astralbot.startAstralbot import dev.erdragh.astralbot.stopAstralbot import dev.erdragh.astralbot.forge.event.CommandMessageEvent import net.minecraft.server.level.ServerPlayer -import thedarkcolour.kotlinforforge.forge.FORGE_BUS -import thedarkcolour.kotlinforforge.forge.MOD_BUS import net.minecraftforge.event.RegisterCommandsEvent import net.minecraftforge.event.ServerChatEvent import net.minecraftforge.event.entity.player.PlayerEvent @@ -22,9 +20,11 @@ import net.minecraftforge.fml.ModLoadingContext import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.config.ModConfig import net.minecraftforge.fml.event.config.ModConfigEvent +import thedarkcolour.kotlinforforge.forge.FORGE_BUS +import thedarkcolour.kotlinforforge.forge.MOD_BUS @Mod("astralbot") -object BotMod { +class BotMod () { init { ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotConfig.SPEC) ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, AstralBotTextConfig.SPEC, "astralbot-text.toml") diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index 3baa40f..0a40245 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -6,22 +6,22 @@ issueTrackerURL = "https://github.com/Erdragh/AstralBot/issues" [[mods]] modId = "${mod_id}" version = "${version}" -displayName = "${title}" +displayName = "${mod_name}" displayURL = "https://modrinth.com/mod/astralbot" logoFile = "icon.png" authors = "${credits}" description = "${description}" -[[dependencies.${mod_id}]] +[[dependencies."${mod_id}"]] modId = "forge" mandatory = true -versionRange = "[47,)" +versionRange = "${forge_range}" ordering = "NONE" side = "BOTH" -[[dependencies.${mod_id}]] +[[dependencies."${mod_id}"]] modId = "minecraft" mandatory = true -versionRange = "[1.20.1,1.20.2)" +versionRange = "${minecraft_version_range}" ordering = "NONE" side = "BOTH" \ No newline at end of file diff --git a/forge/src/main/resources/astralbot.mixins.json b/forge/src/main/resources/astralbot.forge.mixins.json similarity index 85% rename from forge/src/main/resources/astralbot.mixins.json rename to forge/src/main/resources/astralbot.forge.mixins.json index 4b9f0a4..52e4cf5 100644 --- a/forge/src/main/resources/astralbot.mixins.json +++ b/forge/src/main/resources/astralbot.forge.mixins.json @@ -2,6 +2,7 @@ "required": true, "minVersion": "0.8", "package": "dev.erdragh.astralbot.mixins.forge", + "refmap": "${mod_id}.refmap.json", "compatibilityLevel": "JAVA_17", "server": [ "PlayerListMixin" diff --git a/gradle.properties b/gradle.properties index 0e739ee..a4644a7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,36 +2,14 @@ kotlin.code.style=official org.gradle.jvmargs=-Xmx3G -XX:ThreadStackSize=4096 -XX:CompilerThreadStackSize=4096 # Minecraft things -enabledPlatforms=fabric,forge - -# Fabric -fabricLoaderVersion=0.16.3 -fabricApiVersion=0.91.0 -fabricKotlinVersion=1.12.1+kotlin.2.0.20 - +enabledPlatforms=fabric,neoforge version=1.5.3 group=dev.erdragh.astralbot +modName=AstralBot modId=astralbot modAuthor=Erdragh license=MIT -title=AstralBot description=Discord Bot and Minecraft Mod in one bundle. -credits=Erdragh - -minecraftVersion=1.20.1 -parchmentVersion=2023.09.03 - -forgeConfigAPIVersion=8.0.0 - -# Discord Interactions -jdaVersion=5.1.0 -dcWebhooksVersion=0.8.4 - -# Database Interactions -exposedVersion=0.54.0 -sqliteJDBCVersion=3.46.1.0 - -# Message parsing -commonmarkVersion=0.22.0 \ No newline at end of file +credits=Erdragh \ No newline at end of file diff --git a/gradle/dcwebhooks.versions.toml b/gradle/dcwebhooks.versions.toml new file mode 100644 index 0000000..9a06a7b --- /dev/null +++ b/gradle/dcwebhooks.versions.toml @@ -0,0 +1,7 @@ +[versions] +webhooks = "0.8.4" +json = "20230618" + +[libraries] +webhooks = { group = "club.minnced", name = "discord-webhooks", version.ref = "webhooks" } +json = { group = "org.json", name = "json", version.ref = "json" } \ No newline at end of file diff --git a/gradle/exposed.versions.toml b/gradle/exposed.versions.toml new file mode 100644 index 0000000..3961eee --- /dev/null +++ b/gradle/exposed.versions.toml @@ -0,0 +1,7 @@ +[versions] +exposed = "0.55.0" + +[libraries] +core = { group = "org.jetbrains.exposed", name = "exposed-core", version.ref = "exposed" } +dao = { group = "org.jetbrains.exposed", name = "exposed-dao", version.ref = "exposed" } +jdbc = { group = "org.jetbrains.exposed", name = "exposed-jdbc", version.ref = "exposed" } \ No newline at end of file diff --git a/gradle/jda.versions.toml b/gradle/jda.versions.toml new file mode 100644 index 0000000..d6967bf --- /dev/null +++ b/gradle/jda.versions.toml @@ -0,0 +1,23 @@ +[versions] +jda = "5.1.2" + +websocket = "2.14" +okhttp = "4.12.0" +okio = "3.9.1" +trove4j = "3.1.0" +commons-collections = "4.4" +jackson = "2.17.2" +tink = "1.14.1" + +[libraries] +jda = { group = "net.dv8tion", name = "JDA", version.ref = "jda" } + +commons-collections = { group = "org.apache.commons", name = "commons-collections4", version.ref = "commons-collections" } +trove4j = { group = "net.sf.trove4j", name = "core", version.ref = "trove4j" } +jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } +jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-core", version.ref = "jackson" } +jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } +websocket = { group = "com.neovisionaries", name = "nv-websocket-client", version.ref = "websocket" } +okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } +okio = { group = "com.squareup.okio", name = "okio-jvm", version.ref = "okio" } +tink = { group = "com.google.crypto.tink", name = "tink", version.ref = "tink" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a441313..cea7a79 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/libs.versions.toml b/libs.versions.toml new file mode 100644 index 0000000..59578be --- /dev/null +++ b/libs.versions.toml @@ -0,0 +1,59 @@ +[versions] +java = "17" +kotlin = "2.1.10" +moddev = "2.0.78" +loom = "1.9-SNAPSHOT" +dokka = "2.0.0" + +kotlinx-coroutines = "1.8.1" + +minecraft = "1.20.1" +minecraftRange = "[1.20.1, 1.20.2)" + +# The version of ParchmentMC that is used, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions +parchment = "2023.09.03" +parchmentMC = "1.20.1" + +forge = "1.20.1-47.3.29" +forgeRange = "[47.1, 48)" +## This is the version of minecraft that the 'common' project uses, you can find a list of all versions here +## https://projects.neoforged.net/neoforged/neoform +mcp = "1.20.1" +kff = "4.11.0" +kffRange = "[4, )" + +slf4j = "2.0.9" + +fcapi = "8.0.1" + +fabricLoader = "0.16.10" +fabricApi = "0.92.3+1.20.1" +flk = "1.13.1+kotlin.2.1.10" +publish = "0.8.4" + +sqlite = "3.49.0.0" +commonmark = "0.24.0" + +mixin = "0.8.5" + +[libraries] +minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } +fabricLoader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabricLoader" } +fabricApi = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabricApi" } +flk = { group = "net.fabricmc", name = "fabric-language-kotlin", version.ref = "flk" } +kff = { group = "thedarkcolour", name = "kotlinforforge", version.ref = "kff" } +mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" } +sqlite = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqlite" } +commonmark = { group = "org.commonmark", name = "commonmark", version.ref = "commonmark" } +fcapi-fabric = { group = "fuzs.forgeconfigapiport", name = "forgeconfigapiport-fabric", version.ref = "fcapi" } +fcapi-common = { group = "fuzs.forgeconfigapiport", name = "forgeconfigapiport-common", version.ref = "fcapi" } +parchment = { group = "org.parchmentmc.data", name = "parchment-1.20.1", version.ref = "parchment" } +slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" } +kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } + +[plugins] +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +moddev = { id = "net.neoforged.moddev.legacyforge", version.ref = "moddev" } +loom = { id = "fabric-loom", version.ref = "loom" } +publish = { id = "me.modmuss50.mod-publish-plugin", version.ref = "publish" } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 1ca0574..5c3f199 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,8 +5,8 @@ rootProject.name = "AstralBot" pluginManagement { repositories { mavenCentral() - maven(url = "https://maven.architectury.dev/") maven("https://maven.fabricmc.net/") { name = "Fabric" } + maven("https://maven.neoforged.net/releases/") { name = "NeoForge" } maven("https://repo.spongepowered.org/repository/maven-public/") { name = "Sponge Snapshots" } gradlePluginPortal() } @@ -16,4 +16,21 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } +dependencyResolutionManagement { + versionCatalogs { + register("libs") { + from(files("libs.versions.toml")) + } + register("jda") { + from(files("gradle/jda.versions.toml")) + } + register("dcwebhooks") { + from(files("gradle/dcwebhooks.versions.toml")) + } + register("exposed") { + from(files("gradle/exposed.versions.toml")) + } + } +} + include("common", "fabric", "forge") \ No newline at end of file