mirror of
https://github.com/CCBlueX/LiquidBounce.git
synced 2025-09-04 08:16:18 +00:00
refactor(gradle): rewrite with kts (#6175)
This commit is contained in:
440
build.gradle
440
build.gradle
@@ -1,440 +0,0 @@
|
||||
/*
|
||||
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
|
||||
*
|
||||
* Copyright (c) 2015 - 2025 CCBlueX
|
||||
*
|
||||
* LiquidBounce is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LiquidBounce is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
def getContributors(repoOwner, repoName) {
|
||||
HttpURLConnection connection = null
|
||||
|
||||
try {
|
||||
String githubToken = System.getenv("GITHUB_TOKEN")
|
||||
|
||||
connection = "https://api.github.com/repos/${repoOwner}/${repoName}/contributors?per_page=100".toURL().openConnection().with {
|
||||
it as HttpURLConnection
|
||||
}.tap {
|
||||
requestMethod = "GET"
|
||||
connectTimeout = 5000
|
||||
readTimeout = 5000
|
||||
setRequestProperty("User-Agent", "LiquidBounce-App")
|
||||
setRequestProperty("X-GitHub-Api-Version", "2022-11-28")
|
||||
setRequestProperty("Accept", "application/vnd.github+json")
|
||||
|
||||
if (githubToken?.trim()) {
|
||||
setRequestProperty("Authorization", "Bearer ${githubToken}")
|
||||
}
|
||||
}
|
||||
|
||||
def responseCode = connection.responseCode
|
||||
|
||||
if (responseCode in 200..299) {
|
||||
String responseText = connection.inputStream.withReader { it.text }
|
||||
try {
|
||||
def contributors = new JsonSlurper().parseText(responseText)
|
||||
.collect { it["login"] }
|
||||
.findAll { it && !(it as String).contains("[bot]") }
|
||||
|
||||
return contributors
|
||||
} catch (Exception parseError) {
|
||||
logger.log(LogLevel.ERROR, "Failed to parse GitHub API response", parseError)
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
String errorDetails = connection.errorStream?.withReader { it.text } ?: "No error details"
|
||||
logger.log(LogLevel.ERROR, "GitHub API request failed (HTTP ${responseCode}): ${errorDetails}")
|
||||
return []
|
||||
}
|
||||
} catch (Exception globalError) {
|
||||
logger.log(LogLevel.ERROR, "Failed to fetch contributors: ${globalError.message}", globalError)
|
||||
return []
|
||||
} finally {
|
||||
connection?.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
plugins {
|
||||
id "fabric-loom"
|
||||
id "org.jetbrains.kotlin.jvm"
|
||||
id "com.gorylenko.gradle-git-properties" version "2.5.0"
|
||||
id "io.gitlab.arturbosch.detekt" version "1.23.6"
|
||||
id "com.github.node-gradle.node" version "7.1.0"
|
||||
id "org.jetbrains.dokka" version "1.9.10"
|
||||
}
|
||||
|
||||
base {
|
||||
archivesBaseName = project.archives_base_name
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
}
|
||||
|
||||
// These libs are included by the game or other required mods
|
||||
final excludeProvidedLibs = {
|
||||
exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
|
||||
|
||||
exclude group: "com.google.code.gson", module: "gson"
|
||||
exclude group: "net.java.dev.jna", module: "jna"
|
||||
exclude group: "commons-codec", module: "commons-codec"
|
||||
exclude group: "commons-io", module: "commons-io"
|
||||
exclude group: "org.apache.commons", module: "commons-compress"
|
||||
exclude group: "org.apache.commons", module: "commons-lang3"
|
||||
exclude group: "org.apache.logging.log4j", module: "log4j-core"
|
||||
exclude group: "org.apache.logging.log4j", module: "log4j-api"
|
||||
exclude group: "org.apache.logging.log4j", module: "log4j-slf4j-impl"
|
||||
exclude group: "org.slf4j", module: "slf4j-api"
|
||||
exclude group: "com.mojang", module: "authlib"
|
||||
|
||||
exclude group: "io.netty", module: "netty-all"
|
||||
exclude group: "io.netty", module: "netty-buffer"
|
||||
exclude group: "io.netty", module: "netty-codec"
|
||||
exclude group: "io.netty", module: "netty-common"
|
||||
exclude group: "io.netty", module: "netty-handler"
|
||||
exclude group: "io.netty", module: "netty-resolver"
|
||||
exclude group: "io.netty", module: "netty-transport"
|
||||
exclude group: "io.netty", module: "netty-transport-native-unix-common"
|
||||
}
|
||||
|
||||
configurations {
|
||||
includeDependency excludeProvidedLibs
|
||||
includeModDependency excludeProvidedLibs
|
||||
|
||||
include.extendsFrom includeModDependency
|
||||
modImplementation.extendsFrom includeModDependency
|
||||
modCompileOnlyApi.extendsFrom includeModDependency
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url "https://maven.ccbluex.net/releases" }
|
||||
maven { url = "https://maven.fabricmc.net/" }
|
||||
maven {
|
||||
name = "Jitpack"
|
||||
url = "https://jitpack.io"
|
||||
}
|
||||
maven {
|
||||
name = "TerraformersMC"
|
||||
url = "https://maven.terraformersmc.com/"
|
||||
}
|
||||
maven {
|
||||
name = "ViaVersion"
|
||||
url = "https://repo.viaversion.com/"
|
||||
}
|
||||
maven {
|
||||
name = "modrinth"
|
||||
url = "https://api.modrinth.com/maven"
|
||||
}
|
||||
maven {
|
||||
name = "OpenCollab Snapshots"
|
||||
url = "https://repo.opencollab.dev/maven-snapshots/"
|
||||
}
|
||||
maven {
|
||||
name = "Lenni0451"
|
||||
url = "https://maven.lenni0451.net/everything"
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/liquidbounce.accesswidener")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Minecraft
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
|
||||
// Fabric
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
modImplementation "net.fabricmc:fabric-language-kotlin:${project.fabric_kotlin_version}"
|
||||
|
||||
// Mod menu
|
||||
modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}"
|
||||
|
||||
// Recommended mods (on IDE)
|
||||
modImplementation "maven.modrinth:sodium:${project.sodium_version}"
|
||||
modImplementation "maven.modrinth:lithium:${project.lithium_version}"
|
||||
|
||||
// ViaFabricPlus
|
||||
modImplementation "com.viaversion:viafabricplus-api:${project.viafabricplus_version}"
|
||||
modRuntimeOnly "com.viaversion:viafabricplus:${project.viafabricplus_version}"
|
||||
|
||||
// Minecraft Authlib
|
||||
includeDependency "com.github.CCBlueX:mc-authlib:${project.mc_authlib_version}"
|
||||
|
||||
// JCEF Support
|
||||
includeModDependency "com.github.CCBlueX:mcef:${project.mcef_version}"
|
||||
includeDependency "net.ccbluex:netty-httpserver:2.2.1"
|
||||
|
||||
// Discord RPC Support
|
||||
includeDependency "com.github.CCBlueX:DiscordIPC:4.0.0"
|
||||
|
||||
// ScriptAPI
|
||||
includeDependency "net.fabricmc:tiny-mappings-parser:0.3.0+build.17"
|
||||
includeDependency "org.graalvm.polyglot:polyglot:$polyglot_version"
|
||||
includeDependency "org.graalvm.polyglot:js-community:$polyglot_version"
|
||||
includeDependency "org.graalvm.polyglot:tools-community:$polyglot_version"
|
||||
// includeDependency "org.graalvm.polyglot:python-community:$polyglot_version"
|
||||
// includeDependency "org.graalvm.polyglot:wasm-community:$polyglot_version"
|
||||
// includeDependency "org.graalvm.polyglot:java-community:$polyglot_version"
|
||||
// includeDependency "org.graalvm.polyglot:ruby-community:$polyglot_version"
|
||||
// includeDependency "org.graalvm.polyglot:llvm-native-community:$polyglot_version"
|
||||
|
||||
// Machine Learning
|
||||
includeDependency "ai.djl:api:${djl_version}"
|
||||
includeDependency "ai.djl.pytorch:pytorch-engine:${djl_version}"
|
||||
// runtimeOnly "ai.djl.mxnet:mxnet-engine:${djl_version}"
|
||||
// runtimeOnly "ai.djl.tensorflow:tensorflow-engine:${djl_version}"
|
||||
|
||||
// HTTP library
|
||||
includeDependency "com.squareup.okhttp3:okhttp:5.0.0-alpha.16"
|
||||
|
||||
// SOCKS5 Proxy Support
|
||||
includeDependency "io.netty:netty-handler-proxy:4.1.97.Final"
|
||||
|
||||
// Update Checker
|
||||
includeDependency "com.vdurmont:semver4j:3.1.0"
|
||||
|
||||
// Name Protect
|
||||
includeDependency "org.ahocorasick:ahocorasick:0.6.3"
|
||||
|
||||
// Test libraries
|
||||
testImplementation "org.junit.jupiter:junit-jupiter:5.13.0"
|
||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher"
|
||||
|
||||
// Fix nullable annotations
|
||||
compileOnly "com.google.code.findbugs:jsr305:3.0.2"
|
||||
|
||||
afterEvaluate {
|
||||
configurations.includeDependency.incoming.resolutionResult.allDependencies.each {
|
||||
dependencies.include(dependencies.implementation(dependencies.compileOnlyApi(it.requested.toString()) {
|
||||
transitive = false
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
String contributors = JsonOutput.prettyPrint(JsonOutput.toJson(getContributors("CCBlueX", "LiquidBounce")))
|
||||
|
||||
inputs.property "version", project.version
|
||||
|
||||
inputs.property "minecraft_version", minecraft_version
|
||||
inputs.property "fabric_version", fabric_version
|
||||
inputs.property "loader_version", loader_version
|
||||
inputs.property "min_loader_version", min_loader_version
|
||||
inputs.property "fabric_kotlin_version", fabric_kotlin_version
|
||||
inputs.property "viafabricplus_version", viafabricplus_version
|
||||
inputs.property "contributors", contributors
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand([
|
||||
version : project.version,
|
||||
minecraft_version : minecraft_version,
|
||||
fabric_version : fabric_version,
|
||||
loader_version : loader_version,
|
||||
min_loader_version : min_loader_version,
|
||||
contributors : contributors,
|
||||
fabric_kotlin_version: fabric_kotlin_version,
|
||||
viafabricplus_version: viafabricplus_version
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// The following code will include the theme into the build
|
||||
|
||||
tasks.register("npmInstallTheme", NpmTask) {
|
||||
workingDir = file("src-theme")
|
||||
args = ["i"]
|
||||
doLast {
|
||||
println "Successfully installed dependencies for theme"
|
||||
}
|
||||
|
||||
inputs.files("src-theme/package.json", "src-theme/package-lock.json")
|
||||
outputs.dir("src-theme/node_modules")
|
||||
}
|
||||
|
||||
tasks.register("buildTheme", NpmTask) {
|
||||
dependsOn "npmInstallTheme"
|
||||
workingDir = file("src-theme")
|
||||
args = ["run", "build"]
|
||||
doLast {
|
||||
println "Successfully build theme"
|
||||
}
|
||||
|
||||
inputs.files(
|
||||
"src-theme/package.json",
|
||||
"src-theme/package-lock.json",
|
||||
"src-theme/bundle.cjs",
|
||||
"src-theme/rollup.config.js"
|
||||
)
|
||||
inputs.dir("src-theme/src")
|
||||
outputs.dir("src-theme/dist")
|
||||
}
|
||||
|
||||
tasks.register("bundleTheme", NodeTask) {
|
||||
dependsOn "buildTheme"
|
||||
workingDir = file("src-theme")
|
||||
script = file("src-theme/bundle.cjs")
|
||||
doLast {
|
||||
println "Successfully attached theme to build"
|
||||
}
|
||||
|
||||
// Incremental stuff
|
||||
inputs.files(
|
||||
"src-theme/package.json",
|
||||
"src-theme/package-lock.json",
|
||||
"src-theme/bundle.cjs",
|
||||
"src-theme/rollup.config.js"
|
||||
)
|
||||
inputs.dir("src-theme/src")
|
||||
inputs.dir("src-theme/public")
|
||||
inputs.dir("src-theme/dist")
|
||||
outputs.files("src-theme/resources/assets/liquidbounce/default_theme.zip")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources {
|
||||
srcDirs "src-theme/resources"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources.dependsOn bundleTheme
|
||||
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
it.options.encoding = "UTF-8"
|
||||
|
||||
// Minecraft 1.20.5 upwards uses Java 17.
|
||||
it.options.release = 21
|
||||
}
|
||||
|
||||
tasks.withType(Test).configureEach {
|
||||
useJUnitPlatform()
|
||||
dependsOn(tasks.named("genSources"))
|
||||
}
|
||||
|
||||
detekt {
|
||||
config.setFrom(file("${rootProject.projectDir}/config/detekt/detekt.yml"))
|
||||
buildUponDefaultConfig = true
|
||||
baseline = file("${rootProject.projectDir}/config/detekt/baseline.xml")
|
||||
}
|
||||
|
||||
task detektProjectBaseline(type: io.gitlab.arturbosch.detekt.DetektCreateBaselineTask) {
|
||||
description = "Overrides current baseline."
|
||||
ignoreFailures.set(true)
|
||||
parallel.set(true)
|
||||
buildUponDefaultConfig.set(true)
|
||||
setSource(files(rootDir))
|
||||
config.setFrom(files("$rootDir/config/detekt/detekt.yml"))
|
||||
baseline.set(file("$rootDir/config/detekt/baseline.xml"))
|
||||
include("**/*.kt")
|
||||
include("**/*.kts")
|
||||
exclude("**/resources/**")
|
||||
exclude("**/build/**")
|
||||
}
|
||||
|
||||
tasks.register("verifyI18nJsonKeys") {
|
||||
def baselineFileName = "en_us.json"
|
||||
|
||||
group = "verification"
|
||||
description = "Compare i18n JSON files with ${baselineFileName} as the baseline and report missing keys."
|
||||
|
||||
def i18nDir = file("src/main/resources/resources/liquidbounce/lang")
|
||||
|
||||
doLast {
|
||||
if (!i18nDir.exists() || !i18nDir.isDirectory()) {
|
||||
throw new GradleException("The specified directory ${i18nDir} does not exist or is not a directory.")
|
||||
}
|
||||
|
||||
def baselineFile = new File(i18nDir, baselineFileName)
|
||||
if (!baselineFile.exists()) {
|
||||
throw new GradleException("Baseline file ${baselineFileName} not found in ${i18nDir}.")
|
||||
}
|
||||
|
||||
def baseline = new JsonSlurper().parse(baselineFile)
|
||||
|
||||
i18nDir.eachFile { file ->
|
||||
if (file.name.endsWith(".json") && file.name != baselineFileName) {
|
||||
def currentFile = new JsonSlurper().parse(file)
|
||||
|
||||
def missingKeys = baseline.keySet() - currentFile.keySet()
|
||||
|
||||
if (missingKeys.isEmpty()) {
|
||||
println "${file.name} is complete. No missing keys."
|
||||
} else {
|
||||
def limitedMissingKeys = missingKeys.take(5)
|
||||
def output = limitedMissingKeys.join(', ')
|
||||
if (missingKeys.size() > 5) {
|
||||
output += ", ..."
|
||||
}
|
||||
println "${file.name} is missing the following keys (${missingKeys.size()}): ${output}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||
// if it is present.
|
||||
// If you remove this line, sources will not be generated.
|
||||
withSourcesJar()
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
compilerOptions {
|
||||
suppressWarnings = true
|
||||
jvmTarget = JvmTarget.JVM_21
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
// Rename the project"s license file to LICENSE_<project_name> to avoid conflicts
|
||||
from("LICENSE") {
|
||||
rename {
|
||||
"${it}_${project.archives_base_name}"
|
||||
}
|
||||
}
|
||||
|
||||
from(configurations.mappings.collect { zipTree(it) }) {
|
||||
include "mappings/mappings.tiny"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("copyZipInclude", Copy) {
|
||||
from "zip_include/"
|
||||
into "build/libs/zip"
|
||||
}
|
||||
|
||||
sourcesJar.dependsOn bundleTheme
|
||||
build.dependsOn copyZipInclude
|
404
build.gradle.kts
Normal file
404
build.gradle.kts
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
|
||||
*
|
||||
* Copyright (c) 2015 - 2025 CCBlueX
|
||||
*
|
||||
* LiquidBounce is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LiquidBounce is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import com.github.gradle.node.npm.task.NpmTask
|
||||
import com.github.gradle.node.task.NodeTask
|
||||
import groovy.json.JsonOutput
|
||||
import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
|
||||
|
||||
plugins {
|
||||
id("fabric-loom")
|
||||
kotlin("jvm")
|
||||
id("com.gorylenko.gradle-git-properties") version "2.5.0"
|
||||
id("io.gitlab.arturbosch.detekt") version "1.23.6"
|
||||
id("com.github.node-gradle.node") version "7.1.0"
|
||||
id("org.jetbrains.dokka") version "1.9.10"
|
||||
}
|
||||
|
||||
val archives_base_name: String by project
|
||||
val mod_version: String by project
|
||||
val maven_group: String by project
|
||||
|
||||
val minecraft_version: String by project
|
||||
val fabric_version: String by project
|
||||
val loader_version: String by project
|
||||
val min_loader_version: String by project
|
||||
val fabric_kotlin_version: String by project
|
||||
val viafabricplus_version: String by project
|
||||
|
||||
base {
|
||||
archivesName = archives_base_name
|
||||
version = mod_version
|
||||
group = maven_group
|
||||
}
|
||||
|
||||
/** Includes non-mod dependency recursively in the JAR file */
|
||||
val includeDependency: Configuration by configurations.creating
|
||||
|
||||
/** Includes mod in the JAR file */
|
||||
val includeModDependency: Configuration by configurations.creating
|
||||
|
||||
/**
|
||||
* Provided by:
|
||||
* - Minecraft
|
||||
* - Mod dependencies
|
||||
*/
|
||||
fun Configuration.excludeProvidedLibs() = apply {
|
||||
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
|
||||
|
||||
exclude(group = "com.google.code.gson", module = "gson")
|
||||
exclude(group = "net.java.dev.jna", module = "jna")
|
||||
exclude(group = "commons-codec", module = "commons-codec")
|
||||
exclude(group = "commons-io", module = "commons-io")
|
||||
exclude(group = "org.apache.commons", module = "commons-compress")
|
||||
exclude(group = "org.apache.commons", module = "commons-lang3")
|
||||
exclude(group = "org.apache.logging.log4j", module = "log4j-core")
|
||||
exclude(group = "org.apache.logging.log4j", module = "log4j-api")
|
||||
exclude(group = "org.apache.logging.log4j", module = "log4j-slf4j-impl")
|
||||
exclude(group = "org.slf4j", module = "slf4j-api")
|
||||
exclude(group = "com.mojang", module = "authlib")
|
||||
|
||||
// Note: from Netty HTTP Server, not all components are used
|
||||
exclude(group = "io.netty", module = "netty-all")
|
||||
|
||||
exclude(group = "io.netty", module = "netty-buffer")
|
||||
exclude(group = "io.netty", module = "netty-codec")
|
||||
exclude(group = "io.netty", module = "netty-common")
|
||||
exclude(group = "io.netty", module = "netty-handler")
|
||||
exclude(group = "io.netty", module = "netty-resolver")
|
||||
exclude(group = "io.netty", module = "netty-transport")
|
||||
exclude(group = "io.netty", module = "netty-transport-native-unix-common")
|
||||
}
|
||||
|
||||
includeDependency.excludeProvidedLibs()
|
||||
includeModDependency.excludeProvidedLibs()
|
||||
|
||||
configurations.include.get().extendsFrom(includeModDependency)
|
||||
configurations.modApi.get().extendsFrom(includeModDependency)
|
||||
configurations.modCompileOnlyApi.get().extendsFrom(includeModDependency)
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven {
|
||||
name = "CCBlueX"
|
||||
url = uri("https://maven.ccbluex.net/releases")
|
||||
}
|
||||
maven {
|
||||
name = "Fabric"
|
||||
url = uri("https://maven.fabricmc.net/")
|
||||
}
|
||||
maven {
|
||||
name = "Jitpack"
|
||||
url = uri("https://jitpack.io")
|
||||
}
|
||||
maven {
|
||||
name = "TerraformersMC"
|
||||
url = uri("https://maven.terraformersmc.com/")
|
||||
}
|
||||
maven {
|
||||
name = "ViaVersion"
|
||||
url = uri("https://repo.viaversion.com/")
|
||||
}
|
||||
maven {
|
||||
name = "modrinth"
|
||||
url = uri("https://api.modrinth.com/maven")
|
||||
}
|
||||
maven {
|
||||
name = "OpenCollab Snapshots"
|
||||
url = uri("https://repo.opencollab.dev/maven-snapshots/")
|
||||
}
|
||||
maven {
|
||||
name = "Lenni0451"
|
||||
url = uri("https://maven.lenni0451.net/everything")
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/liquidbounce.accesswidener")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Minecraft
|
||||
minecraft("com.mojang:minecraft:${minecraft_version}")
|
||||
mappings("net.fabricmc:yarn:${project.property("yarn_mappings")}:v2")
|
||||
|
||||
// Fabric
|
||||
modApi("net.fabricmc:fabric-loader:${loader_version}")
|
||||
modApi("net.fabricmc.fabric-api:fabric-api:${fabric_version}")
|
||||
modApi("net.fabricmc:fabric-language-kotlin:${fabric_kotlin_version}")
|
||||
|
||||
// Mod menu
|
||||
modApi("com.terraformersmc:modmenu:${project.property("mod_menu_version")}")
|
||||
|
||||
// Recommended mods (on IDE)
|
||||
modApi("maven.modrinth:sodium:${project.property("sodium_version")}")
|
||||
modApi("maven.modrinth:lithium:${project.property("lithium_version")}")
|
||||
|
||||
// ViaFabricPlus
|
||||
modApi("com.viaversion:viafabricplus-api:${viafabricplus_version}")
|
||||
modRuntimeOnly("com.viaversion:viafabricplus:${viafabricplus_version}")
|
||||
|
||||
// Minecraft Authlib
|
||||
includeDependency("com.github.CCBlueX:mc-authlib:${project.property("mc_authlib_version")}")
|
||||
|
||||
// JCEF Support
|
||||
includeModDependency("com.github.CCBlueX:mcef:${project.property("mcef_version")}")
|
||||
includeDependency("net.ccbluex:netty-httpserver:2.2.1")
|
||||
|
||||
// Discord RPC Support
|
||||
includeDependency("com.github.CCBlueX:DiscordIPC:4.0.0")
|
||||
|
||||
// ScriptAPI
|
||||
includeDependency("net.fabricmc:tiny-mappings-parser:0.3.0+build.17")
|
||||
includeDependency("org.graalvm.polyglot:polyglot:${project.property("polyglot_version")}")
|
||||
includeDependency("org.graalvm.polyglot:js-community:${project.property("polyglot_version")}")
|
||||
includeDependency("org.graalvm.polyglot:tools-community:${project.property("polyglot_version")}")
|
||||
// includeDependency("org.graalvm.polyglot:python-community:${project.property("polyglot_version")}")
|
||||
// includeDependency("org.graalvm.polyglot:wasm-community:${project.property("polyglot_version")}")
|
||||
// includeDependency("org.graalvm.polyglot:java-community:${project.property("polyglot_version")}")
|
||||
// includeDependency("org.graalvm.polyglot:ruby-community:${project.property("polyglot_version")}")
|
||||
// includeDependency("org.graalvm.polyglot:llvm-native-community:${project.property("polyglot_version")}")
|
||||
|
||||
// Machine Learning
|
||||
includeDependency("ai.djl:api:${project.property("djl_version")}")
|
||||
includeDependency("ai.djl.pytorch:pytorch-engine:${project.property("djl_version")}")
|
||||
// runtimeOnly("ai.djl.mxnet:mxnet-engine:${project.property("djl_version")}")
|
||||
// runtimeOnly("ai.djl.tensorflow:tensorflow-engine:${project.property("djl_version")}")
|
||||
|
||||
// HTTP library
|
||||
includeDependency("com.squareup.okhttp3:okhttp:5.0.0-alpha.16")
|
||||
|
||||
// SOCKS5 & HTTP Proxy Support
|
||||
includeDependency("io.netty:netty-handler-proxy:4.1.97.Final")
|
||||
|
||||
// Update Checker
|
||||
includeDependency("com.vdurmont:semver4j:3.1.0")
|
||||
|
||||
// Name Protect
|
||||
includeDependency("org.ahocorasick:ahocorasick:0.6.3")
|
||||
|
||||
// Test libraries
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.13.0")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
||||
// Fix nullable annotations
|
||||
compileOnly("com.google.code.findbugs:jsr305:3.0.2")
|
||||
|
||||
afterEvaluate {
|
||||
includeDependency.incoming.resolutionResult.allDependencies.forEach {
|
||||
val compileOnlyApiDependency = dependencies.compileOnlyApi(it.requested.toString()) {
|
||||
isTransitive = false
|
||||
}
|
||||
val apiDependency = dependencies.api(compileOnlyApiDependency)!!
|
||||
|
||||
dependencies.include(apiDependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
dependsOn("bundleTheme")
|
||||
|
||||
val contributors = JsonOutput.prettyPrint(
|
||||
JsonOutput.toJson(getContributors("CCBlueX", "LiquidBounce"))
|
||||
)
|
||||
|
||||
inputs.property("version", mod_version)
|
||||
|
||||
inputs.property("minecraft_version", minecraft_version)
|
||||
inputs.property("fabric_version", fabric_version)
|
||||
inputs.property("loader_version", loader_version)
|
||||
inputs.property("min_loader_version", min_loader_version)
|
||||
inputs.property("fabric_kotlin_version", fabric_kotlin_version)
|
||||
inputs.property("viafabricplus_version", viafabricplus_version)
|
||||
inputs.property("contributors", contributors)
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand(
|
||||
mapOf(
|
||||
"version" to mod_version,
|
||||
"minecraft_version" to minecraft_version,
|
||||
"fabric_version" to fabric_version,
|
||||
"loader_version" to loader_version,
|
||||
"min_loader_version" to min_loader_version,
|
||||
"contributors" to contributors,
|
||||
"fabric_kotlin_version" to fabric_kotlin_version,
|
||||
"viafabricplus_version" to viafabricplus_version,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// The following code will include the theme into the build
|
||||
|
||||
tasks.register<NpmTask>("npmInstallTheme") {
|
||||
workingDir = file("src-theme")
|
||||
args.set(listOf("i"))
|
||||
doLast {
|
||||
logger.info("Successfully installed dependencies for theme")
|
||||
}
|
||||
inputs.files("src-theme/package.json", "src-theme/package-lock.json")
|
||||
outputs.dir("src-theme/node_modules")
|
||||
}
|
||||
|
||||
tasks.register<NpmTask>("buildTheme") {
|
||||
dependsOn("npmInstallTheme")
|
||||
workingDir = file("src-theme")
|
||||
args.set(listOf("run", "build"))
|
||||
doLast {
|
||||
logger.info("Successfully build theme")
|
||||
}
|
||||
|
||||
inputs.files(
|
||||
"src-theme/package.json",
|
||||
"src-theme/package-lock.json",
|
||||
"src-theme/bundle.cjs",
|
||||
"src-theme/rollup.config.js"
|
||||
)
|
||||
inputs.dir("src-theme/src")
|
||||
outputs.dir("src-theme/dist")
|
||||
}
|
||||
|
||||
tasks.register<NodeTask>("bundleTheme") {
|
||||
dependsOn("buildTheme")
|
||||
workingDir = file("src-theme")
|
||||
script = file("src-theme/bundle.cjs")
|
||||
doLast {
|
||||
logger.info("Successfully attached theme to build")
|
||||
}
|
||||
|
||||
// Incremental stuff
|
||||
inputs.files(
|
||||
"src-theme/package.json",
|
||||
"src-theme/package-lock.json",
|
||||
"src-theme/bundle.cjs",
|
||||
"src-theme/rollup.config.js"
|
||||
)
|
||||
inputs.dir("src-theme/src")
|
||||
inputs.dir("src-theme/public")
|
||||
inputs.dir("src-theme/dist")
|
||||
outputs.files("src-theme/resources/assets/liquidbounce/default_theme.zip")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources {
|
||||
srcDirs("src-theme/resources")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||
// this fixes some edge cases with special characters not displaying correctly
|
||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||
// If Javadoc is generated, this must be specified in that task too.
|
||||
options.encoding = "UTF-8"
|
||||
|
||||
// Minecraft 1.21.1 upwards uses Java 21.
|
||||
options.release = 21
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
dependsOn("genSources")
|
||||
}
|
||||
|
||||
// Detekt check
|
||||
|
||||
detekt {
|
||||
config.setFrom(file("${rootProject.projectDir}/config/detekt/detekt.yml"))
|
||||
buildUponDefaultConfig = true
|
||||
baseline = file("${rootProject.projectDir}/config/detekt/baseline.xml")
|
||||
}
|
||||
|
||||
tasks.register<DetektCreateBaselineTask>("detektProjectBaseline") {
|
||||
description = "Overrides current baseline."
|
||||
ignoreFailures.set(true)
|
||||
parallel.set(true)
|
||||
buildUponDefaultConfig.set(true)
|
||||
setSource(files(rootDir))
|
||||
config.setFrom(files("$rootDir/config/detekt/detekt.yml"))
|
||||
baseline.set(file("$rootDir/config/detekt/baseline.xml"))
|
||||
include("**/*.kt")
|
||||
include("**/*.kts")
|
||||
exclude("**/resources/**")
|
||||
exclude("**/build/**")
|
||||
}
|
||||
|
||||
// i18n check
|
||||
|
||||
tasks.register<CompareJsonKeysTask>("verifyI18nJsonKeys") {
|
||||
val baselineFileName = "en_us.json"
|
||||
|
||||
group = "verification"
|
||||
description = "Compare i18n JSON files with $baselineFileName as the baseline and report missing keys."
|
||||
|
||||
val languageFolder = file("src/main/resources/resources/liquidbounce/lang")
|
||||
baselineFile.set(languageFolder.resolve(baselineFileName))
|
||||
files.from(languageFolder.listFiles().filter { it.extension.equals("json", ignoreCase = true) })
|
||||
consoleOutputCount.set(5)
|
||||
}
|
||||
|
||||
java {
|
||||
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||
// if it is present.
|
||||
// If you remove this line, sources will not be generated.
|
||||
withSourcesJar()
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
suppressWarnings = true
|
||||
jvmToolchain(21)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
// Rename the project's license file to LICENSE_<project_name> to avoid conflicts
|
||||
from("LICENSE") {
|
||||
rename {
|
||||
"${it}_${archives_base_name}"
|
||||
}
|
||||
}
|
||||
|
||||
from(files(project.configurations.mappings.get().map(::zipTree))) {
|
||||
include("mappings/mappings.tiny")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Copy>("copyZipInclude") {
|
||||
from("zip_include/")
|
||||
into("build/libs/zip")
|
||||
}
|
||||
|
||||
tasks.named("sourcesJar") {
|
||||
dependsOn("bundleTheme")
|
||||
}
|
||||
|
||||
tasks.named("build") {
|
||||
dependsOn("copyZipInclude")
|
||||
}
|
3
buildSrc/.gitignore
vendored
Normal file
3
buildSrc/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/build/
|
||||
/.gradle/
|
||||
/.kotlin/
|
21
buildSrc/build.gradle.kts
Normal file
21
buildSrc/build.gradle.kts
Normal file
@@ -0,0 +1,21 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
group = "net.ccbluex"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
}
|
112
buildSrc/src/main/kotlin/extensions.kt
Normal file
112
buildSrc/src/main/kotlin/extensions.kt
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
|
||||
*
|
||||
* Copyright (c) 2015 - 2025 CCBlueX
|
||||
*
|
||||
* LiquidBounce is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LiquidBounce is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import groovy.json.JsonSlurper
|
||||
import org.gradle.api.Task
|
||||
import java.net.URI
|
||||
import java.net.http.HttpClient
|
||||
import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.regex.Pattern
|
||||
|
||||
private val httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(5))
|
||||
.executor(Executors.newVirtualThreadPerTaskExecutor())
|
||||
.build()
|
||||
|
||||
private inline val HttpResponse<*>.isSuccessful get() = statusCode() in 200..299
|
||||
|
||||
/**
|
||||
* [API Docs](https://docs.github.com/zh/rest/collaborators/collaborators?apiVersion=2022-11-28)
|
||||
*/
|
||||
fun Task.getContributors(repoOwner: String, repoName: String): List<String> = try {
|
||||
val githubToken: String? = System.getenv("GITHUB_TOKEN")
|
||||
|
||||
fun HttpRequest.Builder.generalSettings() = this
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.header("User-Agent", "LiquidBounce-App")
|
||||
.header("X-GitHub-Api-Version", "2022-11-28")
|
||||
.header("Accept", "application/vnd.github+json")
|
||||
.apply {
|
||||
if (!githubToken.isNullOrBlank())
|
||||
header("Authorization", "Bearer $githubToken")
|
||||
}
|
||||
|
||||
fun HttpClient.fetchLastPage(baseUrl: String, perPage: Int): Int {
|
||||
val request = HttpRequest.newBuilder()
|
||||
.uri(URI("$baseUrl?per_page=$perPage"))
|
||||
.HEAD()
|
||||
.generalSettings()
|
||||
.build()
|
||||
|
||||
val response = send(request, HttpResponse.BodyHandlers.discarding())
|
||||
|
||||
return if (response.isSuccessful) {
|
||||
val linkHeader = response.headers().firstValue("link").orElse("")
|
||||
val pattern = Pattern.compile("&page=(\\d+)>; rel=\"last\"")
|
||||
val matcher = pattern.matcher(linkHeader)
|
||||
return if (matcher.find()) matcher.group(1).toInt() else 1
|
||||
} else {
|
||||
logger.error("HEAD request to ${response.uri()} failed with status: ${response.statusCode()}")
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
val baseUrl = "https://api.github.com/repos/${repoOwner}/${repoName}/contributors"
|
||||
|
||||
val perPage = 100 // Maximum is 100
|
||||
val maxPage = httpClient.fetchLastPage(baseUrl, perPage)
|
||||
|
||||
(1..maxPage).map { page ->
|
||||
val request = HttpRequest.newBuilder()
|
||||
.uri(URI("$baseUrl?per_page=$perPage&page=$page"))
|
||||
.GET()
|
||||
.generalSettings()
|
||||
.build()
|
||||
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream())
|
||||
.thenApply { response ->
|
||||
if (response.isSuccessful) {
|
||||
try {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
response.body().use { inputStream ->
|
||||
(JsonSlurper().parse(inputStream) as List<Map<String, Any?>>)
|
||||
.mapNotNull {
|
||||
if (it["type"] == "User") it["login"] as String else null
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("Failed to parse GitHub API response for $repoOwner:$repoName", e)
|
||||
emptyList()
|
||||
}
|
||||
} else {
|
||||
logger.error("Failed to get GitHub API response for $repoOwner:$repoName (HTTP ${response.statusCode()}): ${response.body().bufferedReader().readText()}")
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
}.flatMapTo(ArrayList(perPage * maxPage)) {
|
||||
it.get()
|
||||
}.also {
|
||||
logger.info("Successfully collected ${it.size} contributors")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("Failed to fetch contributors of $repoOwner:$repoName", e)
|
||||
emptyList()
|
||||
}
|
92
buildSrc/src/main/kotlin/tasks.kt
Normal file
92
buildSrc/src/main/kotlin/tasks.kt
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
|
||||
*
|
||||
* Copyright (c) 2015 - 2025 CCBlueX
|
||||
*
|
||||
* LiquidBounce is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LiquidBounce is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import groovy.json.JsonSlurper
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
abstract class CompareJsonKeysTask : DefaultTask() {
|
||||
|
||||
/**
|
||||
* Baseline file
|
||||
*/
|
||||
@get:InputFile
|
||||
abstract val baselineFile: RegularFileProperty
|
||||
|
||||
/**
|
||||
* Files to check
|
||||
*/
|
||||
@get:InputFiles
|
||||
abstract val files: ConfigurableFileCollection
|
||||
|
||||
/**
|
||||
* Logger output limitation of missing keys
|
||||
*/
|
||||
@get:Input
|
||||
abstract val consoleOutputCount: Property<Int>
|
||||
|
||||
init {
|
||||
consoleOutputCount.convention(Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val baselineFile = baselineFile.orNull?.asFile
|
||||
|
||||
if (baselineFile == null || !baselineFile.exists()) {
|
||||
throw GradleException("Baseline file $baselineFile not found")
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun File.readJsonObject() = inputStream().use(JsonSlurper()::parse) as Map<String, String>
|
||||
|
||||
val baseline = baselineFile.readJsonObject()
|
||||
|
||||
val outputCount = consoleOutputCount.get().coerceAtLeast(1)
|
||||
|
||||
for (file in files.files) {
|
||||
if (file == baselineFile) {
|
||||
continue
|
||||
}
|
||||
|
||||
val currentFile = file.readJsonObject()
|
||||
|
||||
val missingKeys = baseline.keys - currentFile.keys
|
||||
|
||||
if (missingKeys.isEmpty()) {
|
||||
logger.info("${file.name} is complete. No missing keys.")
|
||||
} else {
|
||||
val output = missingKeys.joinToString(
|
||||
separator = ", ",
|
||||
limit = outputCount,
|
||||
truncated = "..."
|
||||
)
|
||||
logger.warn("${file.name} is missing the following keys (${missingKeys.size}): $output")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -17,7 +17,18 @@
|
||||
# along with LiquidBounce. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
kotlin.code.style=official
|
||||
org.gradle.jvmargs=-Xms1024m -Xmx4096m
|
||||
kotlin.incremental=true
|
||||
kotlin.caching.enabled=true
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
|
||||
# Gradle settings
|
||||
org.gradle.daemon=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
#org.gradle.configuration-cache=true
|
||||
# ZGC from JDK 21
|
||||
org.gradle.jvmargs=-Xms1024m -Xmx4096m -XX:+UseZGC
|
||||
|
||||
# Fabric Properties
|
||||
# Check these on https://fabricmc.net/versions.html
|
||||
minecraft_version=1.21.4
|
||||
|
@@ -20,15 +20,19 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
name = "Fabric"
|
||||
url = uri("https://maven.fabricmc.net/")
|
||||
}
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'fabric-loom' version loom_version
|
||||
id 'org.jetbrains.kotlin.jvm' version kotlin_version
|
||||
val loom_version: String by settings
|
||||
val kotlin_version: String by settings
|
||||
id("fabric-loom") version loom_version
|
||||
kotlin("jvm") version kotlin_version
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rootProject.name = "LiquidBounce"
|
Reference in New Issue
Block a user