diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..83fcd720b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto + +*.sh text eol=lf +gradlew text eol=lf +*.bat text eol=crlf +*.ps1 text eol=crlf + +*.jar binary +*.png binary +*.jpg binary +*.gif binary \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index a47a580e3..2a86de945 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -2,23 +2,44 @@ name: Java CI with Gradle on: push: - branches: [ "master" ] + branches: + - master pull_request: - branches: [ "master" ] + branches: + - master + workflow_dispatch: permissions: contents: read + checks: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: + name: Build runs-on: ubuntu-latest + timeout-minutes: 20 + steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '21' - - name: Setup Gradle - uses: gradle/gradle-build-action@v3 - - name: Build with Gradle - run: ./gradlew build + - name: Checkout sources + uses: actions/checkout@v6 + + - name: Set up Java + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: "21" + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 + with: + cache-provider: basic + + - name: Make Gradle wrapper executable + run: chmod +x ./gradlew + + - name: Build shaded plugin + run: ./gradlew clean shadowJar --no-daemon --stacktrace \ No newline at end of file diff --git a/.gitignore b/.gitignore index bf9baa5a3..92ceca277 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ build # IntelliJ .idea +.kotlin out diff --git a/HEADER.txt b/HEADER.txt new file mode 100644 index 000000000..cd2238be4 --- /dev/null +++ b/HEADER.txt @@ -0,0 +1,8 @@ +/* + * This file is part of Guilds. + * + * Guilds is free software: you can redistribute it and/or modify + * it under the terms of the MIT License. + * + * Copyright (c) GlareMasters + */ \ No newline at end of file diff --git a/README.md b/README.md index be417739d..d4cd33c67 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,167 @@ -[![Guilds](https://i.imgur.com/KE562QO.png)](https://github.com/guilds-plugin/Guilds) +# Guilds [![Discord](https://discordapp.com/api/guilds/164280494874165248/widget.png?style=banner2)](https://helpch.at/discord) - [![Crowdin](https://badges.crowdin.net/guilds/localized.svg)](https://crowdin.com/project/guilds) -### What is Guilds? -___ -The Guilds Project was created to offer a RPG type system to servers. -It was inspired by players like you who enjoy creating a fun and exciting environment for your server. -Guilds allows players to join interactive groups of other players, forge their own communities on your server, and compete with other guilds for dominance and control. +Guilds adds RPG-style player communities to Minecraft servers. Players can create and join guilds, build shared identities, compete with other groups, manage claims and roles, and connect with common server plugins such as Vault, LuckPerms, EssentialsX, PlaceholderAPI, and WorldGuard. + +For user documentation, see the [Guilds wiki](https://wiki.helpch.at/). +For API documentation, see the [Javadocs](https://guilds-plugin.github.io/javadocs/). + +--- + +## Requirements + +Guilds now requires **Java 11 or newer** at runtime. + +This applies even when running older Minecraft versions such as 1.8.8. The plugin may support legacy Minecraft server versions, but the JVM running the server must be Java 11+. + +Recommended Java versions for local testing: + +| Minecraft / Paper version | Recommended Java | +| --- | ---: | +| 1.8.8 | 11 | +| 1.16.5 | 16 | +| 1.18.2 | 17 | +| 1.19.4 | 17 | +| 1.20.6 | 21 | +| 1.21.1 | 21 | +| 1.21.4 | 21 | +| 1.21.8 | 21 | +| 26.1.2 | 25 | + +--- + +## Runtime dependencies + +Guilds uses [Quark](https://github.com/BX-Team/Quark) to load the Kotlin runtime at plugin startup instead of shading Kotlin directly into the plugin jar. This keeps the distributed jar smaller while preserving a normal Bukkit/Spigot/Paper plugin workflow. + +The Quark loader is configured for the **Bukkit** platform so the same artifact can run on Spigot-compatible and Paper-compatible servers. + +Server admins should allow the server to download runtime dependencies from Maven Central on first startup. If outbound network access is blocked, preload or mirror the required runtime dependencies before deploying. + +--- + +## Supported integrations + +Guilds is designed to work with common server plugins and APIs: + +| Integration | Purpose | +| --- | --- | +| Vault | Economy and permission bridge | +| LuckPerms | Permission provider through Vault | +| EssentialsX | Economy and chat-related compatibility | +| PlaceholderAPI | Placeholder expansion support | +| WorldGuard | Region and claim-related hooks | +| bStats | Anonymous plugin metrics | + +Vault is required for normal operation. Economy and permission providers must be available through Vault. + +--- + +## Building from source + +Use the Gradle wrapper: + +```bash +./gradlew clean shadowJar --no-configuration-cache +``` + +The shaded plugin jar is written to: -This plugin is for Minecraft Servers! +```text +build/libs/Guilds-.jar +``` -For more information, you can check out the [wiki](https://wiki.helpch.at/)! -Looking for the javadocs? You can see them [here](https://guilds-plugin.github.io/javadocs/)! +Configuration cache is intentionally disabled for Quark-enabled builds because Quark's generated-file task is not currently configuration-cache compatible. -### Support -___ +To check dependency updates: -Looking to get support for something? Join the Discord above to get help and discuss with others! +```bash +./gradlew dependencyUpdates --no-configuration-cache --no-parallel +``` -### Contributing -___ +--- -Do you want to help the project grow and achieve new goals? You can help us out in many ways! +## Local test servers -If you'd like to support our work and buy us a coffee, you could join our [Patreon](https://www.patreon.com/GlareMasters)! We totally understand if you can't do that so we have others ways you can help us out too: +The build includes local Paper test-server tasks powered by `run-paper`. -* Are you an active user of the plugin and want to help others with it? Check out the [issues](https://github.com/guilds-plugin/Guilds/issues) page to see if anyone has questions. You could also hop in our [Discord](https://glaremasters.me/discord) and help others out there too! -* Are you a person who speaks more than one language? Check out our translations page [here](https://crowdin.com/project/guilds) and see if you can help with your language! -* Are you a person who also likes to program? If so, you could look through the open [issues](https://github.com/guilds-plugin/Guilds/issues) and see if there's anything you'd ike to PR into the project. +Examples: -### Community Made Addons -___ +```bash +./gradlew runServer1_8_8 --no-configuration-cache +./gradlew runServer1_16_5 --no-configuration-cache +./gradlew runServer1_21_8 --no-configuration-cache +./gradlew runServer26_1_2 --no-configuration-cache +``` -* [GuildClaimAddons](https://github.com/Nerumir/GuildClaimsAddon) - An alternative addon for the claiming system in the plugin +These tasks: + +- build and attach the current Guilds jar +- create a local `eula.txt` +- run the target server with the configured Java toolchain +- preload common test plugins such as Vault, LuckPerms, and EssentialsX where compatible + +Run-server tasks are intended for local smoke testing. They are interactive and should not be used as normal CI checks. + +--- + +## Development notes + +Current modernization decisions: + +- Java runtime baseline: **Java 11+** +- Java bytecode target: **Java 11** +- Kotlin runtime: loaded at startup through Quark +- Kotlin stdlib: not shaded into the jar +- Shadow: still used for the remaining implementation dependencies +- ConfigMe: pinned to `1.3.0` for legacy Paper compatibility +- Triumph GUI: pinned to `3.1.11` until GUI constructors are migrated +- HikariCP: pinned to `4.0.3` for conservative compatibility + +Before opening a pull request, run: + +```bash +./gradlew clean shadowJar --no-configuration-cache +``` + +Optional formatting/license checks: + +```bash +./gradlew spotlessCheck --no-configuration-cache +``` + +--- + +## Contributing + +Contributions are welcome. + +Good places to help: + +- bug reports and reproduction cases +- compatibility testing across Minecraft versions +- translations on [Crowdin](https://crowdin.com/project/guilds) +- documentation improvements +- pull requests for open [GitHub issues](https://github.com/guilds-plugin/Guilds/issues) + +For support or project discussion, join the Discord linked at the top of this README. + +--- + +## Community add-ons + +- [GuildClaimsAddon](https://github.com/Nerumir/GuildClaimsAddon) — alternative addon for the claiming system + +--- + +## Special thanks -## Special Thanks ![YourKit](https://www.yourkit.com/images/yklogo.png) -YourKit supports open source projects with innovative and intelligent tools -for monitoring and profiling Java and .NET applications. -YourKit is the creator of [YourKit Java Profiler](https://www.yourkit.com/java/profiler/), [YourKit .NET Profiler](https://www.yourkit.com/.net/profiler/), and [YourKit YouMonitor](https://www.yourkit.com/youmonitor/). +YourKit supports open source projects with tools for monitoring and profiling Java and .NET applications. + +- [YourKit Java Profiler](https://www.yourkit.com/java/profiler/) +- [YourKit .NET Profiler](https://www.yourkit.com/.net/profiler/) +- [YourKit YouMonitor](https://www.yourkit.com/youmonitor/) diff --git a/build.gradle.kts b/build.gradle.kts index 59ba55526..bc0bf71b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,181 +1,454 @@ -import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin -import net.kyori.indra.IndraPlugin -import net.kyori.indra.IndraPublishingPlugin -import org.jetbrains.dokka.gradle.DokkaTask -import java.net.URL +import com.diffplug.gradle.spotless.FormatExtension +import com.diffplug.gradle.spotless.SpotlessExtension +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.kyori.indra.licenser.spotless.IndraSpotlessLicenserExtension +import org.gradle.language.jvm.tasks.ProcessResources +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import xyz.jpenilla.runpaper.task.RunServer plugins { - id("java") - id("org.jetbrains.kotlin.jvm") version "2.1.0" - id("net.kyori.indra") version "3.1.3" - id("net.kyori.indra.publishing") version "3.1.3" - id("net.kyori.indra.license-header") version "3.1.3" - id("com.gradleup.shadow") version "8.3.5" - id("io.github.slimjar") version "1.3.0" - id("xyz.jpenilla.run-paper") version "2.3.1" - id("com.github.ben-manes.versions") version "0.51.0" - id("org.jetbrains.dokka") version "1.9.20" + `java-library` + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.indra) + alias(libs.plugins.indra.publishing) + alias(libs.plugins.spotless) + alias(libs.plugins.indra.licenser.spotless) + alias(libs.plugins.shadow) + alias(libs.plugins.versions) + alias(libs.plugins.dokka) + alias(libs.plugins.run.paper) + alias(libs.plugins.quark) } group = "me.glaremasters" version = "3.5.7.2-SNAPSHOT" +val pluginVersion = version.toString() + base { - archivesBaseName = "Guilds" + archivesName.set("Guilds") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + + withSourcesJar() + withJavadocJar() } -apply { - plugin() - plugin() - plugin() +kotlin { + jvmToolchain(21) } -repositories { - mavenCentral() - maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") { - content { - includeGroup("org.bukkit") - includeGroup("org.spigotmc") - } +quark { + /* + * Use Bukkit for the main SpigotMC artifact. + * Paper can run Bukkit plugins, but Spigot cannot run Paper-specific loaders. + */ + platform = "bukkit" + + repositories { + maven("https://repo.maven.apache.org/maven2/") + } +} + +dependencies { + /* + * Bundled into the final plugin jar by shadowJar. + */ + implementation(libs.acf.paper) + implementation(libs.bstats.bukkit) + implementation(libs.taskchain.bukkit) + implementation(libs.worldguardwrapper) + implementation(libs.configme) + implementation(libs.jsonconfiguration) + implementation(libs.xseries) + implementation(libs.adventure.platform.bukkit) + implementation(libs.triumph.gui) + implementation(libs.hikaricp) + implementation(libs.jdbi.core) + implementation(libs.jdbi.sqlobject) + implementation(libs.mariadb.client) + implementation(libs.quark.bukkit) + + /* + * Kotlin is compiled against locally, but downloaded and loaded at runtime + * by Quark to reduce the SpigotMC upload jar size. + */ + compileOnly(libs.kotlin.stdlib) + quark(libs.kotlin.stdlib) + + /* + * Provided by the server or by other plugins at runtime. + * These must not be bundled or relocated. + */ + compileOnly(libs.spigot.api) + compileOnly(libs.vault) + compileOnly(libs.placeholderapi) + compileOnly(libs.jsr305) + compileOnly(libs.authlib) { + isTransitive = false + } +} + +extensions.configure { + fun FormatExtension.standardOptions() { + endWithNewline() + trimTrailingWhitespace() + leadingTabsToSpaces(4) + toggleOffOn("@formatter:off", "@formatter:on") + } + + java { + target("src/**/*.java") + + targetExclude( + "src/**/me/glaremasters/guilds/scanner/ZISScanner.java", + "src/**/me/glaremasters/guilds/updater/UpdateChecker.java", + "src/**/me/glaremasters/guilds/utils/PremiumFun.java" + ) + + standardOptions() + formatAnnotations() + removeUnusedImports() } - maven("https://oss.sonatype.org/content/groups/public/") - maven("https://repo.aikar.co/content/groups/aikar/") { - content { includeGroup("co.aikar") } + + kotlin { + target("src/**/*.kt") + + standardOptions() } - maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") - maven("https://repo.codemc.org/repository/maven-public/") { - content { includeGroup("org.codemc.worldguardwrapper") } + kotlinGradle { + target("*.gradle.kts", "gradle/**/*.gradle.kts") + + standardOptions() } - maven("https://repo.glaremasters.me/repository/public/") } -dependencies { - implementation("io.github.slimjar:slimjar:1.2.7") - implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT") - implementation("org.bstats:bstats-bukkit:3.0.2") - implementation("co.aikar:taskchain-bukkit:3.7.2") - implementation("org.codemc.worldguardwrapper:worldguardwrapper:1.1.9-SNAPSHOT") - implementation("ch.jalu:configme:1.3.0") - implementation("com.dumptruckman.minecraft:JsonConfiguration:1.1") - implementation("com.github.cryptomorin:XSeries:12.1.0") - implementation("net.kyori:adventure-platform-bukkit:4.3.4") - implementation("dev.triumphteam:triumph-gui:3.1.10") - implementation("com.zaxxer:HikariCP:4.0.3") - implementation("org.jdbi:jdbi3-core:3.8.2") - implementation("org.jdbi:jdbi3-sqlobject:3.8.2") - implementation("org.mariadb.jdbc:mariadb-java-client:2.7.2") - - compileOnly("org.spigotmc:spigot-api:1.21.4-R0.1-SNAPSHOT") - compileOnly("net.milkbowl:vault:1.7") - compileOnly("me.clip:placeholderapi:2.11.6") - compileOnly("com.mojang:authlib:1.5.21") - - slim("org.jetbrains.kotlin:kotlin-stdlib") -} - -tasks.withType().configureEach { - dokkaSourceSets { - named("main") { - moduleName.set("Guilds") - - includes.from(project.files(), "Module.md") - - sourceLink { - localDirectory.set(projectDir.resolve("src")) - remoteUrl.set(URL("https://github.com/guilds-plugin/Guilds/tree/master/src")) - remoteLineSuffix.set("#L") - } - } +extensions.configure { + /* + * Create HEADER.txt at the project root. + * + * Example: + * + * /* + * * This file is part of Guilds. + * * + * * Guilds is free software: you can redistribute it and/or modify + * * it under the terms of the MIT License. + * * + * * Copyright (c) GlareMasters + * */ + */ + licenseHeaderFile(rootProject.file("HEADER.txt")) + + property("name", "Guilds") + property("organization", "GlareMasters") + property("url", "https://github.com/guilds-plugin/guilds") +} + +tasks.withType().configureEach { + compilerOptions { + javaParameters.set(true) + jvmTarget.set(JvmTarget.JVM_11) } } -tasks { - build { - dependsOn(named("shadowJar")) - dependsOn(named("slimJar")) +tasks.withType().configureEach { + options.release.set(11) + options.encoding = "UTF-8" + options.compilerArgs.addAll( + listOf( + "-parameters", + "-Xlint:-classfile" + ) + ) +} + +tasks.named("jar") { + enabled = false +} + +tasks.named("processResources") { + filteringCharset = "UTF-8" + + /* + * Configuration-cache safe: + * - compute a plain serializable value during configuration + * - declare it as an input + * - capture only this map in the CopySpec action + */ + val resourceTokens = mapOf( + "version" to pluginVersion + ) + + inputs.properties(resourceTokens) + + filesMatching("plugin.yml") { + expand(resourceTokens) } +} - indra { - mitLicense() +tasks.named("shadowJar") { + minimize() - javaVersions { - target(8) - } + archiveClassifier.set("") + archiveBaseName.set("Guilds") + archiveVersion.set(pluginVersion) - github("guilds-plugin", "guilds") { - publishing(true) - } + /* + * Shadow's default is already runtimeClasspath, but keeping this explicit makes + * the intent clear: implementation/runtime dependencies are shaded; compileOnly + * APIs are not. + */ + configurations = project.configurations.runtimeClasspath.map { listOf(it) } + + /* + * Required for libraries that use META-INF/services, such as JDBC drivers and + * libraries with service-loader based discovery. + */ + mergeServiceFiles() - publishAllTo("guilds", "https://repo.glaremasters.me/repository/guilds/") + /* + * Avoid invalid signature metadata after classes/resources are transformed. + */ + exclude( + "META-INF/*.SF", + "META-INF/*.DSA", + "META-INF/*.RSA", + "META-INF/INDEX.LIST", + "module-info.class" + ) + + /* + * Reproducible jar output. + */ + isReproducibleFileOrder = true + isPreserveFileTimestamps = false + + val relocationRoot = "me.glaremasters.guilds.libs" + + /* + * ACF + */ + relocate("co.aikar.commands", "$relocationRoot.acf.commands") { + skipStringConstants = true + } + relocate("co.aikar.locales", "$relocationRoot.acf.locales") { + skipStringConstants = true } - compileKotlin { - kotlinOptions.javaParameters = true - kotlinOptions.jvmTarget = "1.8" + /* + * TaskChain + */ + relocate("co.aikar.taskchain", "$relocationRoot.taskchain") { + skipStringConstants = true } - compileJava { - options.compilerArgs = listOf("-parameters") + /* + * bStats + */ + relocate("org.bstats", "$relocationRoot.bstats") { + skipStringConstants = true } - runServer { - minecraftVersion("1.21.1") + /* + * WorldGuardWrapper. + * + * Do not relocate WorldGuard, WorldEdit, Bukkit, or Spigot APIs themselves. + * Only relocate the wrapper library. + */ + relocate("org.codemc.worldguardwrapper", "$relocationRoot.worldguardwrapper") { + skipStringConstants = true + } + + /* + * Config libraries + */ + relocate("ch.jalu.configme", "$relocationRoot.configme") { + skipStringConstants = true + } + relocate("com.dumptruckman.minecraft", "$relocationRoot.jsonconfiguration") { + skipStringConstants = true } - license { - header.set(resources.text.fromFile(rootProject.file("LICENSE"))) - exclude("me/glaremasters/guilds/scanner/ZISScanner.java") - exclude("me/glaremasters/guilds/updater/UpdateChecker.java") - exclude("me/glaremasters/guilds/utils/PremiumFun.java") + /* + * XSeries + */ + relocate("com.cryptomorin.xseries", "$relocationRoot.xseries") { + skipStringConstants = true } - shadowJar { - fun relocates(vararg dependencies: String) { - dependencies.forEach { - val split = it.split(".") - val name = split.last() - relocate(it, "me.glaremasters.guilds.libs.$name") - } - } + /* + * Adventure platform and Kyori internals. + * + * This is safe when Adventure is used internally by the plugin. + * If your public API exposes Adventure Component types to other plugins, + * do not relocate net.kyori.adventure. + */ + relocate("net.kyori.adventure", "$relocationRoot.adventure") { + skipStringConstants = true + } + relocate("net.kyori.examination", "$relocationRoot.examination") { + skipStringConstants = true + } + relocate("net.kyori.option", "$relocationRoot.kyori.option") { + skipStringConstants = true + } - relocates( - "io.github.slimjar" - ) + /* + * Triumph GUI + */ + relocate("dev.triumphteam.gui", "$relocationRoot.triumph.gui") { + skipStringConstants = true + } + + /* + * Database stack + */ + relocate("com.zaxxer.hikari", "$relocationRoot.hikari") { + skipStringConstants = true + } + relocate("org.jdbi", "$relocationRoot.jdbi") { + skipStringConstants = true + } + relocate("org.mariadb.jdbc", "$relocationRoot.mariadb") { + skipStringConstants = true + } + + /* + * Common transitive libraries pulled by the database/config stack. + * These are intentionally narrow to avoid relocating server/plugin APIs. + */ + relocate("org.antlr", "$relocationRoot.antlr") { + skipStringConstants = true + } + relocate("org.checkerframework", "$relocationRoot.checkerframework") { + skipStringConstants = true + } + relocate("org.intellij.lang.annotations", "$relocationRoot.intellij.annotations") { + skipStringConstants = true + } + relocate("org.jetbrains.annotations", "$relocationRoot.jetbrains.annotations") { + skipStringConstants = true + } +} + +tasks.named("assemble") { + dependsOn(tasks.named("shadowJar")) +} + +tasks.named("build") { + dependsOn(tasks.named("shadowJar")) +} + +tasks.named("check") { + dependsOn(tasks.named("spotlessCheck")) +} - minimize() +indra { + mitLicense() - archiveClassifier.set(null as String?) - archiveFileName.set("Guilds-${project.version}.jar") - destinationDirectory.set(rootProject.tasks.shadowJar.get().destinationDirectory.get()) + javaVersions { + target(11) } - slimJar { - fun relocates(vararg dependencies: String) { - dependencies.forEach { - val split = it.split(".") - val name = split.last() - relocate(it, "me.glaremasters.guilds.libs.$name") - } + github("guilds-plugin", "guilds") { + publishing(true) + } + + publishAllTo("guilds", "https://repo.glaremasters.me/repository/guilds/") +} + +val javaToolchains = extensions.getByType() + +data class MinecraftRunTarget( + val minecraftVersion: String, + val javaVersion: Int, + val directoryName: String = minecraftVersion +) + +val supportedMinecraftVersions = listOf( + MinecraftRunTarget("1.8.8", 11), + MinecraftRunTarget("1.16.5", 16), + MinecraftRunTarget("1.18.2", 17), + MinecraftRunTarget("1.19.4", 17), + MinecraftRunTarget("1.20.6", 21), + MinecraftRunTarget("1.21.1", 21), + MinecraftRunTarget("1.21.4", 21), + MinecraftRunTarget("1.21.8", 21), + MinecraftRunTarget("26.1.2", 25) +) + +fun RunServer.configureGuildsRunServer(target: MinecraftRunTarget) { + minecraftVersion(target.minecraftVersion) + runDirectory.set(layout.projectDirectory.dir("run/${target.directoryName}")) + + javaLauncher.set( + javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(target.javaVersion)) } + ) - relocates( - "org.bstats", - "co.aikar.commands", - "co.aikar.locales", - "co.aikar.taskchain", - "ch.jalu.configme", - "com.zaxxer.hikari", - "org.jdbi", - "org.mariadb.jdbc", - "dev.triumphteam.gui", - "net.kyori", - "com.cryptomorin.xseries", - "kotlin" - ) + pluginJars.from(tasks.named("shadowJar").flatMap { it.archiveFile }) + dependsOn(tasks.named("shadowJar")) + + downloadPlugins { + /* + * EssentialsX: + * Hangar marks this release as an external download, so run-task's + * Hangar downloader returns 404. Use GitHub Releases instead. + */ + url("https://ci.ender.zone/job/EssentialsX/lastSuccessfulBuild/artifact/jars/EssentialsX-2.22.0-dev+112-5baf239.jar") + + /* + * LuckPerms: + * Official Bukkit loader URL. + */ + url("https://download.luckperms.net/1638/bukkit/loader/LuckPerms-Bukkit-5.5.50.jar") + + /* + * Vault: + * No clean native Hangar source; use pinned release jar. + */ + url("https://github.com/MilkBowl/Vault/releases/download/1.7.3/Vault.jar") } - processResources { - expand("version" to rootProject.version) + doFirst { + val serverDir = runDirectory.get().asFile + serverDir.mkdirs() + + serverDir.resolve("eula.txt").writeText( + """ + # Generated by Gradle run-paper for local Guilds development. + # By changing this setting to TRUE you are indicating your agreement to the Minecraft EULA. + # https://aka.ms/MinecraftEULA + eula=true + """.trimIndent() + System.lineSeparator() + ) } } + +tasks { + runServer { + configureGuildsRunServer( + supportedMinecraftVersions.last().copy(directoryName = "latest") + ) + } + + supportedMinecraftVersions.forEach { target -> + val taskSuffix = target.minecraftVersion.replace(".", "_") + + register("runServer$taskSuffix") { + group = "run paper" + description = + "Runs a Paper test server for Minecraft ${target.minecraftVersion} using Java ${target.javaVersion}." + + configureGuildsRunServer(target) + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index e110e410f..f31d5df0d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,8 @@ -org.gradle.jvmargs='-Dfile.encoding=UTF-8' +org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configuration-cache=false + +kotlin.code.style=official +kotlin.incremental=true +kotlin.stdlib.default.dependency=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..6427a9997 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,64 @@ +[versions] +kotlin = "2.1.0" +indra = "4.0.0" +shadow = "9.4.1" +run-paper = "3.0.2" +versions-plugin = "0.54.0" +dokka = "2.2.0" +spotless = "8.5.1" +jsr305 = "3.0.2" +quark = "1.3.0" + +minecraft-spigot-api = "26.1.2-R0.1-SNAPSHOT" + +acf = "0.5.1-SNAPSHOT" +bstats = "3.2.1" +taskchain = "3.7.2" +worldguardwrapper = "1.1.9-SNAPSHOT" +configme = "1.3.0" +jsonconfiguration = "1.1" +xseries = "13.7.0" +adventure-platform-bukkit = "4.4.1" +# 3.1.13 changes GUI constructor compatibility; current GUI classes still extend old constructors. +triumph-gui = "3.1.11" +hikaricp = "4.0.3" +jdbi = "3.53.0" +mariadb = "3.5.8" +vault = "1.7" +placeholderapi = "2.12.2" +authlib = "1.5.21" + +[libraries] +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } +acf-paper = { module = "co.aikar:acf-paper", version.ref = "acf" } +bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } +taskchain-bukkit = { module = "co.aikar:taskchain-bukkit", version.ref = "taskchain" } +worldguardwrapper = { module = "org.codemc.worldguardwrapper:worldguardwrapper", version.ref = "worldguardwrapper" } +configme = { module = "ch.jalu:configme", version.ref = "configme" } +jsonconfiguration = { module = "com.dumptruckman.minecraft:JsonConfiguration", version.ref = "jsonconfiguration" } +xseries = { module = "com.github.cryptomorin:XSeries", version.ref = "xseries" } +adventure-platform-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform-bukkit" } +triumph-gui = { module = "dev.triumphteam:triumph-gui", version.ref = "triumph-gui" } +hikaricp = { module = "com.zaxxer:HikariCP", version.ref = "hikaricp" } +jdbi-core = { module = "org.jdbi:jdbi3-core", version.ref = "jdbi" } +jdbi-sqlobject = { module = "org.jdbi:jdbi3-sqlobject", version.ref = "jdbi" } +mariadb-client = { module = "org.mariadb.jdbc:mariadb-java-client", version.ref = "mariadb" } + +spigot-api = { module = "org.spigotmc:spigot-api", version.ref = "minecraft-spigot-api" } +vault = { module = "net.milkbowl:vault", version.ref = "vault" } +placeholderapi = { module = "me.clip:placeholderapi", version.ref = "placeholderapi" } +authlib = { module = "com.mojang:authlib", version.ref = "authlib" } +jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" } +quark-bukkit = { module = "org.bxteam.quark:bukkit", version.ref = "quark" } + +[plugins] +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +indra = { id = "net.kyori.indra", version.ref = "indra" } +indra-publishing = { id = "net.kyori.indra.publishing", version.ref = "indra" } +indra-licenser-spotless = { id = "net.kyori.indra.licenser.spotless", version.ref = "indra" } +shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } +run-paper = { id = "xyz.jpenilla.run-paper", version.ref = "run-paper" } +versions = { id = "com.github.ben-manes.versions", version.ref = "versions-plugin" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } +quark = { id = "org.bxteam.quark", version.ref = "quark" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..5dd3c0121 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-9.5.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..b740cf133 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/settings.gradle.kts b/settings.gradle.kts index efa889075..6f192eb17 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,65 @@ -/* - * This file was generated by the Gradle 'init' task. - */ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} -rootProject.name = "Guilds" +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + + repositories { + mavenCentral() + + maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") { + content { + includeGroup("org.bukkit") + includeGroup("org.spigotmc") + } + } + + maven("https://oss.sonatype.org/content/groups/public/") + + maven("https://repo.aikar.co/content/groups/aikar/") { + content { + includeGroup("co.aikar") + } + } + + maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") { + content { + includeGroup("me.clip") + } + } + + maven("https://repo.codemc.org/repository/maven-public/") { + content { + includeGroup("org.codemc.worldguardwrapper") + } + } + + maven("https://repo.glaremasters.me/repository/public/") { + name = "glaremasters" + + metadataSources { + mavenPom() + artifact() + ignoreGradleMetadataRedirection() + } + } + + maven("https://repo.bxteam.org/releases") { + name = "bxteam-releases" + + content { + includeGroup("org.bxteam.quark") + } + } + } +} + +rootProject.name = "Guilds" \ No newline at end of file diff --git a/src/main/java/me/glaremasters/guilds/Guilds.java b/src/main/java/me/glaremasters/guilds/Guilds.java index 924b0411c..5a7b9f036 100644 --- a/src/main/java/me/glaremasters/guilds/Guilds.java +++ b/src/main/java/me/glaremasters/guilds/Guilds.java @@ -27,12 +27,8 @@ import co.aikar.taskchain.BukkitTaskChainFactory; import co.aikar.taskchain.TaskChain; import co.aikar.taskchain.TaskChainFactory; -import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import io.github.slimjar.app.builder.ApplicationBuilder; -import io.github.slimjar.resolver.data.Repository; -import io.github.slimjar.resolver.mirrors.SimpleMirrorSelector; import me.glaremasters.guilds.acf.ACFHandler; import me.glaremasters.guilds.actions.ActionHandler; import me.glaremasters.guilds.api.GuildsAPI; @@ -70,16 +66,9 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; +import org.bxteam.quark.bukkit.BukkitLibraryManager; -import java.io.File; import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.security.NoSuchAlgorithmException; -import java.time.Duration; -import java.time.Instant; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Stream; public final class Guilds extends JavaPlugin { @@ -101,6 +90,7 @@ public final class Guilds extends JavaPlugin { private Permission permissions; private BukkitAudiences adventure; private ChatListener chatListener; + private BukkitLibraryManager libraryManager; public static Gson getGson() { return gson; @@ -112,27 +102,8 @@ public static GuildsAPI getApi() { @Override public void onLoad() { - final Logger logger = getLogger(); - final File dependencyDirectory = new File(getDataFolder(), "Libraries"); - logger.log(Level.INFO, "Loading Libraries..."); - logger.log(Level.INFO, "Note: This might take a few minutes on first run. Kindly ensure internet connectivity."); - final Instant startInstant = Instant.now(); - try { - ApplicationBuilder - .appending("Guilds") - .downloadDirectoryPath(dependencyDirectory.toPath()) - .internalRepositories(Lists.newArrayList( - new Repository(new URL("https://repo.glaremasters.me/repository/public/")), - new Repository(new URL(SimpleMirrorSelector.DEFAULT_CENTRAL_MIRROR_URL)))) - .build(); - final Instant endInstant = Instant.now(); - final long timeTaken = Duration.between(startInstant, endInstant).toMillis(); - final double timeTakenSeconds = timeTaken / 1000.0; - logger.log(Level.INFO, "Loaded libraries in {0} seconds", timeTakenSeconds); - } catch (IOException | ReflectiveOperationException | URISyntaxException | NoSuchAlgorithmException exception) { - logger.log(Level.SEVERE, "Unable to load dependencies... Please ensure an active Internet connection on first run!"); - exception.printStackTrace(); - } + libraryManager = new BukkitLibraryManager(this); + libraryManager.loadFromGradle(); } @Override