From e0bc37ab6e125797ad158849c492daddbb04ec69 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Sun, 3 Dec 2023 21:55:09 +0100 Subject: [PATCH 01/14] fix(build): Remove generate accessor import --- buildSrc/src/main/kotlin/internal/Accessors.kt | 8 ++++++++ buildSrc/src/main/kotlin/internal/libs.kt | 13 ++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 buildSrc/src/main/kotlin/internal/Accessors.kt diff --git a/buildSrc/src/main/kotlin/internal/Accessors.kt b/buildSrc/src/main/kotlin/internal/Accessors.kt new file mode 100644 index 0000000..60ed9bf --- /dev/null +++ b/buildSrc/src/main/kotlin/internal/Accessors.kt @@ -0,0 +1,8 @@ +package internal + +import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByName + +internal val Project.versionCatalogs: VersionCatalogsExtension + get() = extensions.getByName("versionCatalogs") diff --git a/buildSrc/src/main/kotlin/internal/libs.kt b/buildSrc/src/main/kotlin/internal/libs.kt index 87bb80b..5794663 100644 --- a/buildSrc/src/main/kotlin/internal/libs.kt +++ b/buildSrc/src/main/kotlin/internal/libs.kt @@ -1,6 +1,5 @@ package internal -import gradle.kotlin.dsl.accessors._1f737d11fad22b9b058419dfc437a798.versionCatalogs import org.gradle.api.Project import org.gradle.api.artifacts.MinimalExternalModuleDependency import org.gradle.api.provider.Provider @@ -14,24 +13,24 @@ internal object libs { context(Project) val junit_bom - get() = get("junit-bom") + get() = lib("junit-bom") context(Project) val junit_jupiter - get() = get("junit-jupiter") + get() = lib("junit-jupiter") context(Project) val junit_jupiter_params - get() = get("junit-jupiter-params") + get() = lib("junit-jupiter-params") context(Project) val kotest_assertions - get() = get("kotest-assertions") + get() = lib("kotest-assertions") context(Project) val mockk - get() = get("mockk") + get() = lib("mockk") - private fun Project.get(alias: String): Provider = + private fun Project.lib(alias: String): Provider = versionCatalogs.named("libs").findLibrary(alias).get() } From 2028b333a02baf0c724c27be3a40089f219c6d66 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Tue, 8 Apr 2025 15:38:09 +0200 Subject: [PATCH 02/14] build: Gradle 8.13 --- CHANGELOG.md | 2 +- buildSrc/build.gradle.kts | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 43705 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 8 +++++--- gradlew.bat | 22 ++++++++++++---------- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e55bcc5..e4293bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ Since now, it is possible to change Mimic config using commands in two ways: - Update required Java 1.8 → 16 - Update Kotlin 1.6.20 → 1.9.20 - Replace ACF with CommandAPI -- Update Gradle 7.4.2 → 8.5 +- Update Gradle 7.4.2 → 8.13 - Update dependencies - Migrate to version catalogs diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 64fcc2b..033be48 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } kotlin { - jvmToolchain(16) + jvmToolchain(17) compilerOptions { freeCompilerArgs.add("-Xcontext-receivers") } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..9bbc975c742b298b441bfb90dbc124400a3751b9 100644 GIT binary patch literal 43705 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 DHx0+F literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e09..37f853b 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.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..faf9300 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 +# ############################################################################## # @@ -55,7 +57,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/. @@ -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 @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..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 ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From 2ddeef452f154d8449651b83b8dd4e186c5421f3 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Tue, 8 Apr 2025 15:54:53 +0200 Subject: [PATCH 03/14] build: Update MMOItems and MMOCore dependencies --- gradle/libs.versions.toml | 6 +++--- mimic-bukkit/build.gradle.kts | 4 ++++ .../src/main/kotlin/impl/mmocore/MmoCoreLevelSystem.kt | 7 +++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c6ff5b1..71d8c70 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,9 +17,9 @@ commandapi-kotlin = { module = "dev.jorel:commandapi-bukkit-kotlin", version.ref rpgplugins-skillapi = "com.sucy:SkillAPI:3.102" rpgplugins-battlelevels = "me.robin:BattleLevels:6.9.1" -rpgplugins-mmocore = "net.Indyuce:MMOCore:1.9.2" -rpgplugins-mmoitems = "net.Indyuce:MMOItems:6.7.2" -rpgplugins-mythiclib = "io.lumine:MythicLib-dist:1.4" +rpgplugins-mmocore = "net.Indyuce:MMOCore-API:1.12.1-SNAPSHOT" +rpgplugins-mmoitems = "net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT" +rpgplugins-mythiclib = "io.lumine:MythicLib-dist:1.6.2-SNAPSHOT" rpgplugins-heroes = "com.herocraftonline.heroes:Heroes:1.9.30-RELEASE" # Test dependencies diff --git a/mimic-bukkit/build.gradle.kts b/mimic-bukkit/build.gradle.kts index 9622f60..394a7a9 100644 --- a/mimic-bukkit/build.gradle.kts +++ b/mimic-bukkit/build.gradle.kts @@ -31,6 +31,10 @@ repositories { maven(url = "https://mvn.lumine.io/repository/maven-public/") { content { includeModule("me.robin", "BattleLevels") + } + } + maven("https://nexus.phoenixdevt.fr/repository/maven-public/") { + content { includeGroup("net.Indyuce") includeModule("io.lumine", "MythicLib-dist") } diff --git a/mimic-bukkit/src/main/kotlin/impl/mmocore/MmoCoreLevelSystem.kt b/mimic-bukkit/src/main/kotlin/impl/mmocore/MmoCoreLevelSystem.kt index 95b65b0..48c9f43 100644 --- a/mimic-bukkit/src/main/kotlin/impl/mmocore/MmoCoreLevelSystem.kt +++ b/mimic-bukkit/src/main/kotlin/impl/mmocore/MmoCoreLevelSystem.kt @@ -5,7 +5,6 @@ import net.Indyuce.mmocore.experience.EXPSource import org.bukkit.entity.Player import ru.endlesscode.mimic.level.BukkitLevelSystem import ru.endlesscode.mimic.level.ExpLevelConverter -import kotlin.math.roundToInt /** Implementation of LevelSystem using MMOCore. */ public class MmoCoreLevelSystem private constructor( @@ -22,9 +21,9 @@ public class MmoCoreLevelSystem private constructor( } override var exp: Double - get() = playerData.experience.toDouble() + get() = playerData.experience set(value) { - playerData.experience = value.roundToInt() + playerData.experience = value } override val totalExpToNextLevel: Double @@ -39,7 +38,7 @@ public class MmoCoreLevelSystem private constructor( } override fun giveExp(expAmount: Double) { - playerData.giveExperience(expAmount.roundToInt(), EXPSource.OTHER) + playerData.giveExperience(expAmount, EXPSource.OTHER) } private val playerData: PlayerData From 788695d5a0bc7ef2190cf5859a923bd6e568a5c7 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Sat, 19 Apr 2025 13:45:53 +0200 Subject: [PATCH 04/14] build: Update BukkitGradle to 1.0.0 --- .run/Run Server [mimic-bukkit].run.xml | 20 ++++++++++++++++++++ buildSrc/build.gradle.kts | 1 - buildSrc/settings.gradle.kts | 2 ++ buildSrc/src/main/kotlin/commons.gradle.kts | 9 --------- gradle/libs.versions.toml | 4 ++-- mimic-bukkit/build.gradle.kts | 18 ++++++++++++++---- mimic-bukkit/libs/QuantumRPG-5.10.2.jar | Bin 1146236 -> 1135757 bytes mimic-bukkit/src/main/resources/plugin.yml | 8 -------- 8 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 .run/Run Server [mimic-bukkit].run.xml delete mode 100644 mimic-bukkit/src/main/resources/plugin.yml diff --git a/.run/Run Server [mimic-bukkit].run.xml b/.run/Run Server [mimic-bukkit].run.xml new file mode 100644 index 0000000..8ece5bf --- /dev/null +++ b/.run/Run Server [mimic-bukkit].run.xml @@ -0,0 +1,20 @@ + + + + + + false + true + false + false + + + \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 033be48..e63e03f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -15,7 +15,6 @@ dependencies { implementation(kotlin("serialization", version = kotlinVersion)) implementation(libs.dokka) implementation(libs.kotlinx.binaryCompatibilityValidator) - implementation(libs.gradleDownloadTask) } repositories { diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index b5a0fab..105225c6 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -5,3 +5,5 @@ dependencyResolutionManagement { } } } + +rootProject.name = "buildSrc" diff --git a/buildSrc/src/main/kotlin/commons.gradle.kts b/buildSrc/src/main/kotlin/commons.gradle.kts index d3886bd..f692c07 100644 --- a/buildSrc/src/main/kotlin/commons.gradle.kts +++ b/buildSrc/src/main/kotlin/commons.gradle.kts @@ -31,15 +31,6 @@ kotlin { } } -// TODO: Remove after fix in BukkitGradle -// https://github.com/EndlessCodeGroup/BukkitGradle/issues/62 -afterEvaluate { - java { - sourceCompatibility = JavaVersion.VERSION_16 - targetCompatibility = JavaVersion.VERSION_16 - } -} - dependencies { implementation(kotlin("stdlib-jdk8")) testingDependencies() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71d8c70..6682b53 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ kotlin = "1.9.20" commandapi = "9.2.0" junit = "5.10.1" +bukkitgradle = "1.0.0" [libraries] @@ -32,11 +33,10 @@ mockk = "io.mockk:mockk:1.13.8" # Build dependencies dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.10" kotlinx-binaryCompatibilityValidator = "org.jetbrains.kotlinx:binary-compatibility-validator:0.13.2" -gradleDownloadTask = "de.undercouch:gradle-download-task:5.5.0" [plugins] -bukkitgradle = "ru.endlesscode.bukkitgradle:0.10.1" +bukkitgradle = { id = "ru.endlesscode.bukkitgradle", version.ref="bukkitgradle" } shadow = "com.github.johnrengelman.shadow:8.1.1" versions = "com.github.ben-manes.versions:0.50.0" diff --git a/mimic-bukkit/build.gradle.kts b/mimic-bukkit/build.gradle.kts index 394a7a9..76a64e8 100644 --- a/mimic-bukkit/build.gradle.kts +++ b/mimic-bukkit/build.gradle.kts @@ -12,16 +12,26 @@ plugins { description = "Bukkit plugin with implementations of Mimic APIs" bukkit { - meta { + apiVersion = "1.16.5" + + plugin { name = "Mimic" main = "ru.endlesscode.mimic.MimicPlugin" - apiVersion = "1.13" authors = listOf("osipxd", "EndlessCodeGroup") - url = "https://github.com/EndlessCodeGroup/Mimic" + website = "https://github.com/EndlessCodeGroup/Mimic" + loadBefore = listOf( + "SkillAPI", + "BattleLevels", + "CustomItems", + "MMOCore", + "MMOItems", + "Heroes", + "QuantumRPG", + ) } server { - setCore("paper") + version = "1.21.5" eula = true } } diff --git a/mimic-bukkit/libs/QuantumRPG-5.10.2.jar b/mimic-bukkit/libs/QuantumRPG-5.10.2.jar index acf19fc51a0ea5722ab2dbf9b39bfc7ad7e56c77..21e823450c9545f0aafbbeb21f48bcbfbcf2223c 100644 GIT binary patch delta 40382 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 diff --git a/mimic-bukkit/src/main/resources/plugin.yml b/mimic-bukkit/src/main/resources/plugin.yml deleted file mode 100644 index fe49753..0000000 --- a/mimic-bukkit/src/main/resources/plugin.yml +++ /dev/null @@ -1,8 +0,0 @@ -loadbefore: - - SkillAPI - - BattleLevels - - CustomItems - - MMOCore - - MMOItems - - Heroes - - QuantumRPG From 049747fe825bb4314c6a52f08ccad261c1537129 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Sun, 20 Apr 2025 00:19:28 +0200 Subject: [PATCH 05/14] feat: Make CommandAPI optional dependency --- CHANGELOG.md | 5 +- gradle/libs.versions.toml | 4 +- mimic-bukkit/build.gradle.kts | 12 +++-- mimic-bukkit/src/main/kotlin/MimicPlugin.kt | 23 ++------- .../src/main/kotlin/command/MimicCommands.kt | 49 +++++++++++++++++++ 5 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 mimic-bukkit/src/main/kotlin/command/MimicCommands.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index e4293bc..16e7e64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ### Added command `/mimic config` -Since now, it is possible to change Mimic config using commands in two ways: +> [!NOTE] +> This feature requires the CommandAPI plugin to be installed. + +Now it is possible to change Mimic config using commands in two ways: 1. Using interactive config `/mimic config`. Every option in the output is interactive, so you can change it just by mouse click. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6682b53..993a90b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] kotlin = "1.9.20" -commandapi = "9.2.0" +commandapi = "9.7.0" junit = "5.10.1" bukkitgradle = "1.0.0" @@ -13,7 +13,7 @@ annotations = "org.jetbrains:annotations:24.1.0" serialization-hocon = "org.jetbrains.kotlinx:kotlinx-serialization-hocon:1.6.1" adventure = "net.kyori:adventure-platform-bukkit:4.3.1" -commandapi = { module = "dev.jorel:commandapi-bukkit-shade", version.ref = "commandapi" } +commandapi = { module = "dev.jorel:commandapi-bukkit-core", version.ref = "commandapi" } commandapi-kotlin = { module = "dev.jorel:commandapi-bukkit-kotlin", version.ref = "commandapi" } rpgplugins-skillapi = "com.sucy:SkillAPI:3.102" diff --git a/mimic-bukkit/build.gradle.kts b/mimic-bukkit/build.gradle.kts index 76a64e8..4c135af 100644 --- a/mimic-bukkit/build.gradle.kts +++ b/mimic-bukkit/build.gradle.kts @@ -19,6 +19,7 @@ bukkit { main = "ru.endlesscode.mimic.MimicPlugin" authors = listOf("osipxd", "EndlessCodeGroup") website = "https://github.com/EndlessCodeGroup/Mimic" + softDepend = listOf("CommandAPI") loadBefore = listOf( "SkillAPI", "BattleLevels", @@ -36,6 +37,12 @@ bukkit { } } +tasks.runServer { + downloadPlugins { + github("CommandAPI", "CommandAPI", "10.0.0", "CommandAPI-10.0.0.jar") + } +} + repositories { maven(url = "https://gitlab.com/endlesscodegroup/mvn-repo/raw/master/") maven(url = "https://mvn.lumine.io/repository/maven-public/") { @@ -64,10 +71,10 @@ dependencies { implementation(libs.bstats) implementation(libs.serialization.hocon) - implementation(libs.commandapi) - implementation(libs.commandapi.kotlin) implementation(libs.adventure) + compileOnly(libs.commandapi) + compileOnly(libs.commandapi.kotlin) compileOnly(libs.bundles.rpgplugins) { isTransitive = false } // From libs/ directory @@ -94,7 +101,6 @@ tasks.shadowJar { relocate("kotlin", "$shadePackage.kotlin") relocate("org.bstats", "$shadePackage.bstats") relocate("com.typesafe.config", "$shadePackage.hocon") - relocate("dev.jorel.commandapi", "$shadePackage.commandapi") relocate("net.kyori.adventure", "$shadePackage.adventure") relocate("net.kyori.examination", "$shadePackage.examination") diff --git a/mimic-bukkit/src/main/kotlin/MimicPlugin.kt b/mimic-bukkit/src/main/kotlin/MimicPlugin.kt index a4e6773..1c71582 100644 --- a/mimic-bukkit/src/main/kotlin/MimicPlugin.kt +++ b/mimic-bukkit/src/main/kotlin/MimicPlugin.kt @@ -19,9 +19,6 @@ package ru.endlesscode.mimic -import dev.jorel.commandapi.CommandAPI -import dev.jorel.commandapi.CommandAPIBukkitConfig -import net.kyori.adventure.platform.bukkit.BukkitAudiences import org.bstats.bukkit.Metrics import org.bstats.charts.AdvancedPie import org.bstats.charts.SimplePie @@ -32,7 +29,7 @@ import org.bukkit.plugin.java.JavaPlugin import ru.endlesscode.mimic.bukkit.loadAll import ru.endlesscode.mimic.bukkit.register import ru.endlesscode.mimic.classes.BukkitClassSystem -import ru.endlesscode.mimic.command.registerCommand +import ru.endlesscode.mimic.command.MimicCommands import ru.endlesscode.mimic.config.MimicConfig import ru.endlesscode.mimic.impl.battlelevels.BattleLevelsLevelSystem import ru.endlesscode.mimic.impl.customitems.CustomItemsRegistry @@ -64,30 +61,21 @@ public class MimicPlugin : JavaPlugin() { private val config: MimicConfig by lazy { MimicConfig(this) } private val mimic: Mimic by lazy { MimicImpl(servicesManager, config) } - private var audiences: BukkitAudiences? = null + private val commands: MimicCommands by lazy { MimicCommands() } private inline val servicesManager get() = server.servicesManager private inline val pluginManager get() = server.pluginManager override fun onLoad() { Log.init(logger, debug = !isReleased) - CommandAPI.onLoad(CommandAPIBukkitConfig(this)) servicesManager.register(mimic, this) hookDefaultServices() } override fun onEnable() { - CommandAPI.onEnable() - audiences = BukkitAudiences.create(this) - if (isReleased) initMetrics() - registerCommand( - mimic = mimic, - config = config, - pluginFullName = description.fullName, - audiences = checkNotNull(audiences), - ) + commands.register(this, mimic, config) pluginManager.registerEvents(ServicesRegistrationListener(servicesManager, mimic), this) } @@ -193,9 +181,6 @@ public class MimicPlugin : JavaPlugin() { } override fun onDisable() { - CommandAPI.unregister("mimic") - CommandAPI.onDisable() - audiences?.close() - audiences = null + commands.unregister() } } diff --git a/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt new file mode 100644 index 0000000..59e2b89 --- /dev/null +++ b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt @@ -0,0 +1,49 @@ +package ru.endlesscode.mimic.command + +import dev.jorel.commandapi.CommandAPI +import net.kyori.adventure.platform.bukkit.BukkitAudiences +import org.bukkit.plugin.java.JavaPlugin +import ru.endlesscode.mimic.Mimic +import ru.endlesscode.mimic.config.MimicConfig +import ru.endlesscode.mimic.internal.Log + +internal class MimicCommands { + + private var registered = false + private var audiences: BukkitAudiences? = null + + fun register( + plugin: JavaPlugin, + mimic: Mimic, + config: MimicConfig, + ) { + val commandApiPlugin = plugin.server.pluginManager.getPlugin("CommandAPI") + if (commandApiPlugin == null) { + Log.w("CommandAPI not found. Mimic commands won't be registered.") + Log.w("Consider installing CommandAPI: https://docs.commandapi.dev/") + return + } else if (!commandApiPlugin.isEnabled) { + Log.w("CommandAPI loaded, but not enabled. Mimic commands won't be registered.") + return + } + + registered = true + audiences = BukkitAudiences.create(plugin) + + registerCommand( + mimic = mimic, + config = config, + pluginFullName = plugin.description.fullName, + audiences = checkNotNull(audiences), + ) + } + + fun unregister() { + if (registered) { + CommandAPI.unregister("mimic") + audiences?.close() + audiences = null + } + } + +} \ No newline at end of file From 18745f1e2c22755e33e82df7c06f742dd16d029e Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Sun, 20 Apr 2025 12:12:44 +0200 Subject: [PATCH 06/14] build: Update Kotlin to 2.1.20 --- CHANGELOG.md | 2 +- buildSrc/src/main/kotlin/commons.gradle.kts | 4 +--- gradle/libs.versions.toml | 6 +++--- mimic-bukkit/api/mimic-bukkit.api | 1 - 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16e7e64..b20e4c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ Now it is possible to change Mimic config using commands in two ways: ### Housekeeping - Update required Java 1.8 → 16 -- Update Kotlin 1.6.20 → 1.9.20 +- Update Kotlin 1.6.20 → 2.1.20 - Replace ACF with CommandAPI - Update Gradle 7.4.2 → 8.13 - Update dependencies diff --git a/buildSrc/src/main/kotlin/commons.gradle.kts b/buildSrc/src/main/kotlin/commons.gradle.kts index f692c07..3b53002 100644 --- a/buildSrc/src/main/kotlin/commons.gradle.kts +++ b/buildSrc/src/main/kotlin/commons.gradle.kts @@ -25,14 +25,12 @@ kotlin { apiVersion = KotlinVersion.KOTLIN_1_9 languageVersion = KotlinVersion.KOTLIN_1_9 freeCompilerArgs.add("-Xjvm-default=all") - optIn.add("kotlin.RequiresOptIn") allWarningsAsErrors = System.getProperty("warningsAsErrors") == "true" - javaParameters = true } } dependencies { - implementation(kotlin("stdlib-jdk8")) + implementation(kotlin("stdlib")) testingDependencies() } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 993a90b..b5c76b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "1.9.20" +kotlin = "2.1.20" commandapi = "9.7.0" junit = "5.10.1" bukkitgradle = "1.0.0" @@ -10,7 +10,7 @@ bukkitgradle = "1.0.0" spigot-api = "org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT" bstats = "org.bstats:bstats-bukkit:3.0.2" annotations = "org.jetbrains:annotations:24.1.0" -serialization-hocon = "org.jetbrains.kotlinx:kotlinx-serialization-hocon:1.6.1" +serialization-hocon = "org.jetbrains.kotlinx:kotlinx-serialization-hocon:1.8.1" adventure = "net.kyori:adventure-platform-bukkit:4.3.1" commandapi = { module = "dev.jorel:commandapi-bukkit-core", version.ref = "commandapi" } @@ -32,7 +32,7 @@ mockk = "io.mockk:mockk:1.13.8" # Build dependencies dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.10" -kotlinx-binaryCompatibilityValidator = "org.jetbrains.kotlinx:binary-compatibility-validator:0.13.2" +kotlinx-binaryCompatibilityValidator = "org.jetbrains.kotlinx:binary-compatibility-validator:0.17.0" [plugins] diff --git a/mimic-bukkit/api/mimic-bukkit.api b/mimic-bukkit/api/mimic-bukkit.api index 51d172e..49c3223 100644 --- a/mimic-bukkit/api/mimic-bukkit.api +++ b/mimic-bukkit/api/mimic-bukkit.api @@ -312,7 +312,6 @@ public final class ru/endlesscode/mimic/impl/vanilla/ItemMetaPayload$$serializer public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; } public final class ru/endlesscode/mimic/impl/vanilla/ItemMetaPayload$Companion { From c5d8f7f60604711e36a6fe5888e8b8bce1d9108b Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Sun, 20 Apr 2025 12:25:04 +0200 Subject: [PATCH 07/14] build: Use version.ref for all entries in libs.versions.toml --- gradle/libs.versions.toml | 56 ++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b5c76b1..01dae96 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,44 +1,64 @@ [versions] kotlin = "2.1.20" +kotlinx-binaryCompatibilityValidator = "0.17.0" +kotlinx-serialization = "1.8.1" +dokka = "1.9.10" +annotations = "26.0.2" + commandapi = "9.7.0" +adventure = "4.3.1" +bstats = "3.1.0" + +skillapi = "3.102" +battlelevels = "6.9.1" +mmocore = "1.12.1-SNAPSHOT" +mmoitems = "6.9.5-SNAPSHOT" +mythiclib = "1.6.2-SNAPSHOT" +heroes = "1.9.30-RELEASE" + junit = "5.10.1" -bukkitgradle = "1.0.0" +kotest = "5.8.0" +mockk = "1.13.8" + +gradlePlugin-bukkitgradle = "1.0.0" +gradlePlugin-shadow = "8.1.1" +gradlePlugin-versions = "0.50.0" [libraries] spigot-api = "org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT" -bstats = "org.bstats:bstats-bukkit:3.0.2" -annotations = "org.jetbrains:annotations:24.1.0" -serialization-hocon = "org.jetbrains.kotlinx:kotlinx-serialization-hocon:1.8.1" -adventure = "net.kyori:adventure-platform-bukkit:4.3.1" +serialization-hocon = { module = "org.jetbrains.kotlinx:kotlinx-serialization-hocon", version.ref = "kotlinx-serialization" } +annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" } commandapi = { module = "dev.jorel:commandapi-bukkit-core", version.ref = "commandapi" } commandapi-kotlin = { module = "dev.jorel:commandapi-bukkit-kotlin", version.ref = "commandapi" } +adventure = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure" } +bstats = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } -rpgplugins-skillapi = "com.sucy:SkillAPI:3.102" -rpgplugins-battlelevels = "me.robin:BattleLevels:6.9.1" -rpgplugins-mmocore = "net.Indyuce:MMOCore-API:1.12.1-SNAPSHOT" -rpgplugins-mmoitems = "net.Indyuce:MMOItems-API:6.9.5-SNAPSHOT" -rpgplugins-mythiclib = "io.lumine:MythicLib-dist:1.6.2-SNAPSHOT" -rpgplugins-heroes = "com.herocraftonline.heroes:Heroes:1.9.30-RELEASE" +rpgplugins-skillapi = { module = "com.sucy:SkillAPI", version.ref = "skillapi" } +rpgplugins-battlelevels = { module = "me.robin:BattleLevels", version.ref = "battlelevels" } +rpgplugins-mmocore = { module = "net.Indyuce:MMOCore-API", version.ref = "mmocore" } +rpgplugins-mmoitems = { module = "net.Indyuce:MMOItems-API", version.ref = "mmoitems" } +rpgplugins-mythiclib = { module = "io.lumine:MythicLib-dist", version.ref = "mythiclib" } +rpgplugins-heroes = { module = "com.herocraftonline.heroes:Heroes", version.ref = "heroes" } # Test dependencies junit-bom = { module = "org.junit:junit-bom", version.ref = "junit" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } -kotest-assertions = "io.kotest:kotest-assertions-core:5.8.0" -mockk = "io.mockk:mockk:1.13.8" +kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" } +mockk = { module = "io.mockk:mockk", version.ref = "mockk" } # Build dependencies -dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.10" -kotlinx-binaryCompatibilityValidator = "org.jetbrains.kotlinx:binary-compatibility-validator:0.17.0" +dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" } +kotlinx-binaryCompatibilityValidator = { module = "org.jetbrains.kotlinx:binary-compatibility-validator", version.ref = "kotlinx-binaryCompatibilityValidator" } [plugins] -bukkitgradle = { id = "ru.endlesscode.bukkitgradle", version.ref="bukkitgradle" } -shadow = "com.github.johnrengelman.shadow:8.1.1" -versions = "com.github.ben-manes.versions:0.50.0" +bukkitgradle = { id = "ru.endlesscode.bukkitgradle", version.ref = "gradlePlugin-bukkitgradle" } +shadow = { id = "com.github.johnrengelman.shadow", version.ref = "gradlePlugin-shadow" } +versions = { id = "com.github.ben-manes.versions", version.ref = "gradlePlugin-versions" } [bundles] From ca0404a8fa8e28044e88a214b84a0328c395b250 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Tue, 22 Apr 2025 22:26:47 +0200 Subject: [PATCH 08/14] chore: Java 16 -> 17 --- .github/workflows/main.yml | 4 ++-- .github/workflows/publish.yml | 2 +- CHANGELOG.md | 2 +- buildSrc/src/main/kotlin/commons.gradle.kts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b5b1c7a..d5da9f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: - name: Setup Java uses: actions/setup-java@v3 with: - java-version: 16 + java-version: 17 distribution: temurin - name: Run Check uses: eskatos/gradle-command-action@v2 @@ -37,7 +37,7 @@ jobs: - name: Setup Java uses: actions/setup-java@v3 with: - java-version: 16 + java-version: 17 distribution: temurin - name: Generate docs uses: eskatos/gradle-command-action@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5c4facd..e3db56a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Java uses: actions/setup-java@v3 with: - java-version: 16 + java-version: 17 distribution: temurin - name: Assemble Plugin diff --git a/CHANGELOG.md b/CHANGELOG.md index b20e4c3..05876ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ Now it is possible to change Mimic config using commands in two ways: ### Housekeeping -- Update required Java 1.8 → 16 +- Update required Java 1.8 → 17 - Update Kotlin 1.6.20 → 2.1.20 - Replace ACF with CommandAPI - Update Gradle 7.4.2 → 8.13 diff --git a/buildSrc/src/main/kotlin/commons.gradle.kts b/buildSrc/src/main/kotlin/commons.gradle.kts index 3b53002..8452406 100644 --- a/buildSrc/src/main/kotlin/commons.gradle.kts +++ b/buildSrc/src/main/kotlin/commons.gradle.kts @@ -18,7 +18,7 @@ tasks.test { } kotlin { - jvmToolchain(16) + jvmToolchain(17) explicitApi() compilerOptions { From a0473cbda95a37d1798098e138a94a3ba9ddbadf Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Sun, 20 Apr 2025 00:15:46 +0200 Subject: [PATCH 09/14] feat: Migrate to Paper API 1.20+ --- CHANGELOG.md | 9 ++ gradle/libs.versions.toml | 5 +- mimic-bukkit-api/build.gradle.kts | 4 +- mimic-bukkit/build.gradle.kts | 21 +++-- mimic-bukkit/src/main/kotlin/MimicPlugin.kt | 2 +- .../kotlin/ServicesRegistrationListener.kt | 2 +- .../src/main/kotlin/command/ConfigCommand.kt | 4 +- .../src/main/kotlin/command/MainCommand.kt | 10 +-- .../src/main/kotlin/command/MimicCommands.kt | 14 +-- .../impl/mimic/SafeBukkitItemsRegistry.kt | 2 +- .../impl/vanilla/MinecraftItemsRegistry.kt | 2 +- .../src/main/kotlin/internal/Compat.kt | 2 +- .../src/main/kotlin/internal/Configuration.kt | 5 +- mimic-bukkit/src/main/kotlin/internal/Log.kt | 22 +++-- .../src/main/kotlin/internal/Serializers.kt | 9 +- .../src/test/kotlin/BukkitTestBase.kt | 38 +++++--- .../impl/mimic/MimicItemsRegistryTest.kt | 27 ++++-- .../vanilla/MinecraftItemsRegistryTest.kt | 86 ------------------- 18 files changed, 111 insertions(+), 153 deletions(-) delete mode 100644 mimic-bukkit/src/test/kotlin/impl/vanilla/MinecraftItemsRegistryTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 05876ba..c3f215a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ## [Unreleased] +### Paper-first + +Keeping the plugin compatible both with Paper and Spigot consumes a lot of time. +Now, Mimic is Paper-first as it is the most popular platform. +This means that compatibility with Spigot is not guaranteed. + +To reduce the maintenance burden, support for versions older than 1.20 has been dropped. +Java 17 is required. + ### Added command `/mimic config` > [!NOTE] diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 01dae96..0192ccd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] +paper = "1.20-R0.1-SNAPSHOT" kotlin = "2.1.20" kotlinx-binaryCompatibilityValidator = "0.17.0" kotlinx-serialization = "1.8.1" @@ -7,7 +8,6 @@ dokka = "1.9.10" annotations = "26.0.2" commandapi = "9.7.0" -adventure = "4.3.1" bstats = "3.1.0" skillapi = "3.102" @@ -27,13 +27,12 @@ gradlePlugin-versions = "0.50.0" [libraries] -spigot-api = "org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT" +paperApi = { module = "io.papermc.paper:paper-api", version.ref = "paper" } serialization-hocon = { module = "org.jetbrains.kotlinx:kotlinx-serialization-hocon", version.ref = "kotlinx-serialization" } annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" } commandapi = { module = "dev.jorel:commandapi-bukkit-core", version.ref = "commandapi" } commandapi-kotlin = { module = "dev.jorel:commandapi-bukkit-kotlin", version.ref = "commandapi" } -adventure = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure" } bstats = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } rpgplugins-skillapi = { module = "com.sucy:SkillAPI", version.ref = "skillapi" } diff --git a/mimic-bukkit-api/build.gradle.kts b/mimic-bukkit-api/build.gradle.kts index 0528f11..04aca80 100644 --- a/mimic-bukkit-api/build.gradle.kts +++ b/mimic-bukkit-api/build.gradle.kts @@ -6,11 +6,11 @@ plugins { description = "Abstraction API for Bukkit RPG plugins" repositories { - maven(url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots") + maven("https://repo.papermc.io/repository/maven-public/") } dependencies { api(projects.mimicApi) compileOnly(libs.annotations) - compileOnly(libs.spigot.api) { isTransitive = false } + compileOnly(libs.paperApi) } diff --git a/mimic-bukkit/build.gradle.kts b/mimic-bukkit/build.gradle.kts index 4c135af..ca85928 100644 --- a/mimic-bukkit/build.gradle.kts +++ b/mimic-bukkit/build.gradle.kts @@ -1,5 +1,6 @@ import ru.endlesscode.bukkitgradle.dependencies.aikar import ru.endlesscode.bukkitgradle.dependencies.codemc +import ru.endlesscode.bukkitgradle.dependencies.papermc plugins { commons @@ -9,10 +10,10 @@ plugins { kotlin("plugin.serialization") } -description = "Bukkit plugin with implementations of Mimic APIs" +description = "Bukkit plugin implementing Mimic APIs" bukkit { - apiVersion = "1.16.5" + apiVersion = "1.20" plugin { name = "Mimic" @@ -44,6 +45,7 @@ tasks.runServer { } repositories { + papermc() maven(url = "https://gitlab.com/endlesscodegroup/mvn-repo/raw/master/") maven(url = "https://mvn.lumine.io/repository/maven-public/") { content { @@ -66,12 +68,11 @@ repositories { dependencies { api(projects.mimicBukkitApi) - compileOnly(libs.spigot.api) { isTransitive = false } + compileOnly(libs.paperApi) compileOnly(libs.annotations) implementation(libs.bstats) implementation(libs.serialization.hocon) - implementation(libs.adventure) compileOnly(libs.commandapi) compileOnly(libs.commandapi.kotlin) @@ -80,9 +81,9 @@ dependencies { // From libs/ directory compileOnly(":CustomItemsAPI") compileOnly(":QuantumRPG:5.10.2") - compileOnly(":NexEngine:2.0.3") // Do not update NexEngine. QuantumRpgWrapper cannot compile with higher version + compileOnly(":NexEngine:2.0.3") // Do not update NexEngine. QuantumRpgWrapper cannot compile with a higher version - testImplementation(libs.spigot.api) + testImplementation(libs.paperApi) testImplementation(libs.rpgplugins.skillapi) } @@ -92,6 +93,12 @@ kotlin { } } +tasks.test { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(17) + } +} + tasks.shadowJar { dependencies { exclude(dependency("org.jetbrains:annotations:.*")) @@ -101,8 +108,6 @@ tasks.shadowJar { relocate("kotlin", "$shadePackage.kotlin") relocate("org.bstats", "$shadePackage.bstats") relocate("com.typesafe.config", "$shadePackage.hocon") - relocate("net.kyori.adventure", "$shadePackage.adventure") - relocate("net.kyori.examination", "$shadePackage.examination") exclude("META-INF/*.kotlin_module") exclude("META-INF/com.android.tools/**") diff --git a/mimic-bukkit/src/main/kotlin/MimicPlugin.kt b/mimic-bukkit/src/main/kotlin/MimicPlugin.kt index 1c71582..047e905 100644 --- a/mimic-bukkit/src/main/kotlin/MimicPlugin.kt +++ b/mimic-bukkit/src/main/kotlin/MimicPlugin.kt @@ -57,7 +57,7 @@ import ru.endlesscode.mimic.util.checkClassesLoaded /** Main class of the plugin. */ public class MimicPlugin : JavaPlugin() { - private val isReleased = !description.version.endsWith("-SNAPSHOT") + private val isReleased = !pluginMeta.version.endsWith("-SNAPSHOT") private val config: MimicConfig by lazy { MimicConfig(this) } private val mimic: Mimic by lazy { MimicImpl(servicesManager, config) } diff --git a/mimic-bukkit/src/main/kotlin/ServicesRegistrationListener.kt b/mimic-bukkit/src/main/kotlin/ServicesRegistrationListener.kt index b26183b..eb83d7f 100644 --- a/mimic-bukkit/src/main/kotlin/ServicesRegistrationListener.kt +++ b/mimic-bukkit/src/main/kotlin/ServicesRegistrationListener.kt @@ -26,7 +26,7 @@ internal class ServicesRegistrationListener( Log.w( """ Service ${serviceClass.name} with id '${service.id}' registered in deprecated way. - Please ask the ${plugin.name} authors (${plugin.description.authors.joinToString()}) to migrate + Please ask the ${plugin.name} authors (${plugin.pluginMeta.authors.joinToString()}) to migrate to the new service registration API introduced in Mimic v0.7: https://github.com/EndlessCodeGroup/Mimic/releases/tag/v0.7 """.trimIndent() diff --git a/mimic-bukkit/src/main/kotlin/command/ConfigCommand.kt b/mimic-bukkit/src/main/kotlin/command/ConfigCommand.kt index 4cc1234..eb8cb83 100644 --- a/mimic-bukkit/src/main/kotlin/command/ConfigCommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/ConfigCommand.kt @@ -6,7 +6,6 @@ import dev.jorel.commandapi.kotlindsl.anyExecutor import dev.jorel.commandapi.kotlindsl.multiLiteralArgument import dev.jorel.commandapi.kotlindsl.stringArgument import dev.jorel.commandapi.kotlindsl.subcommand -import net.kyori.adventure.platform.bukkit.BukkitAudiences import org.bukkit.command.CommandSender import ru.endlesscode.mimic.ExperimentalMimicApi import ru.endlesscode.mimic.Mimic @@ -24,11 +23,10 @@ import ru.endlesscode.mimic.config.MimicConfig internal fun CommandAPICommand.configSubcommand( mimic: Mimic, config: MimicConfig, - audiences: BukkitAudiences, ) = subcommand("config") { val showConfig = { sender: CommandSender -> val message = buildConfigMessage(mimic, config) - audiences.sender(sender).sendMessage(message) + sender.sendMessage(message) } withShortDescription("Show Mimic config") diff --git a/mimic-bukkit/src/main/kotlin/command/MainCommand.kt b/mimic-bukkit/src/main/kotlin/command/MainCommand.kt index c81b204..05741c5 100644 --- a/mimic-bukkit/src/main/kotlin/command/MainCommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/MainCommand.kt @@ -2,7 +2,6 @@ package ru.endlesscode.mimic.command import dev.jorel.commandapi.executors.CommandExecutor import dev.jorel.commandapi.kotlindsl.commandAPICommand -import net.kyori.adventure.platform.bukkit.BukkitAudiences import net.kyori.adventure.text.format.NamedTextColor import ru.endlesscode.mimic.Mimic import ru.endlesscode.mimic.config.MimicConfig @@ -16,20 +15,19 @@ internal fun registerCommand( mimic: Mimic, config: MimicConfig, pluginFullName: String, - audiences: BukkitAudiences, ) = commandAPICommand("mimic") { withPermission("mimic.admin") withShortDescription("Show info about Mimic") - executes(infoExecutor(audiences, pluginFullName)) + executes(infoExecutor(pluginFullName)) - configSubcommand(mimic, config, audiences) + configSubcommand(mimic, config) levelSystemSubcommand(mimic) classSystemSubcommand(mimic) inventorySubcommand(mimic) itemsSubcommand(mimic.getItemsRegistry()) } -private fun infoExecutor(audiences: BukkitAudiences, pluginFullName: String) = CommandExecutor { sender, _ -> +private fun infoExecutor(pluginFullName: String) = CommandExecutor { sender, _ -> val message = buildTextComponent { appendLine(pluginFullName, NamedTextColor.GREEN) color(NamedTextColor.GRAY) @@ -37,7 +35,7 @@ private fun infoExecutor(audiences: BukkitAudiences, pluginFullName: String) = C append(createClickableCommand()) append(" to see or change configs") } - audiences.sender(sender).sendMessage(message) + sender.sendMessage(message) } private fun createClickableCommand() = buildTextComponent { diff --git a/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt index 59e2b89..33209dc 100644 --- a/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt +++ b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt @@ -1,7 +1,6 @@ package ru.endlesscode.mimic.command import dev.jorel.commandapi.CommandAPI -import net.kyori.adventure.platform.bukkit.BukkitAudiences import org.bukkit.plugin.java.JavaPlugin import ru.endlesscode.mimic.Mimic import ru.endlesscode.mimic.config.MimicConfig @@ -10,7 +9,6 @@ import ru.endlesscode.mimic.internal.Log internal class MimicCommands { private var registered = false - private var audiences: BukkitAudiences? = null fun register( plugin: JavaPlugin, @@ -28,22 +26,14 @@ internal class MimicCommands { } registered = true - audiences = BukkitAudiences.create(plugin) - registerCommand( mimic = mimic, config = config, - pluginFullName = plugin.description.fullName, - audiences = checkNotNull(audiences), + pluginFullName = plugin.pluginMeta.displayName, ) } fun unregister() { - if (registered) { - CommandAPI.unregister("mimic") - audiences?.close() - audiences = null - } + if (registered) CommandAPI.unregister("mimic") } - } \ No newline at end of file diff --git a/mimic-bukkit/src/main/kotlin/impl/mimic/SafeBukkitItemsRegistry.kt b/mimic-bukkit/src/main/kotlin/impl/mimic/SafeBukkitItemsRegistry.kt index 6f5918c..eac91e1 100644 --- a/mimic-bukkit/src/main/kotlin/impl/mimic/SafeBukkitItemsRegistry.kt +++ b/mimic-bukkit/src/main/kotlin/impl/mimic/SafeBukkitItemsRegistry.kt @@ -71,5 +71,5 @@ private fun logImplementationError(provider: ItemsRegistryProvider, throwable: T Log.w(throwable, "Error in ItemsRegistry '${provider.registry.id}' " + "implemented via ${provider.plugin}. " + - "Please, report it to ${provider.plugin.description.authors.joinToString()}.") + "Please, report it to ${provider.plugin.pluginMeta.authors.joinToString()}.") } diff --git a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt index 9b8b8bc..b3514d0 100644 --- a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt +++ b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt @@ -37,7 +37,7 @@ public class MinecraftItemsRegistry : BukkitItemsRegistry { override val id: String = ID override val knownIds: List by lazy { - Material.values().asSequence() + Material.entries.asSequence() .filter { it.isItem } .map { it.name.lowercase() } .toList() diff --git a/mimic-bukkit/src/main/kotlin/internal/Compat.kt b/mimic-bukkit/src/main/kotlin/internal/Compat.kt index c922d68..a621292 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Compat.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Compat.kt @@ -10,7 +10,7 @@ internal inline fun callCompat( if (key !in notSupportedCalls) { try { return block() - } catch (_: NoSuchMethodError) { + } catch (_: IncompatibleClassChangeError) { notSupportedCalls.add(key) } } diff --git a/mimic-bukkit/src/main/kotlin/internal/Configuration.kt b/mimic-bukkit/src/main/kotlin/internal/Configuration.kt index d9d68e8..5126173 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Configuration.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Configuration.kt @@ -3,8 +3,8 @@ package ru.endlesscode.mimic.internal import org.bukkit.configuration.Configuration import org.bukkit.configuration.file.FileConfigurationOptions -@Suppress("DEPRECATION") -internal fun FileConfigurationOptions.setHeader(vararg lines: String?) { +@Suppress("DEPRECATION") // Changed in 1.18.1 +internal fun FileConfigurationOptions.setHeader(vararg lines: String) { callCompat( "FileConfigurationOptions.setHeader", block = { setHeader(lines.asList()) }, @@ -17,6 +17,7 @@ internal fun Configuration.applyDefaults() { for (key in defaults.getKeys(true)) set(key, get(key)) } +// Added in 1.18.1 internal fun Configuration.setComments(path: String, vararg comments: String?) { callCompat( "Configuration.setComments", diff --git a/mimic-bukkit/src/main/kotlin/internal/Log.kt b/mimic-bukkit/src/main/kotlin/internal/Log.kt index 799ed0c..ca80240 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Log.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Log.kt @@ -26,13 +26,20 @@ internal object Log { private const val DEBUG_TAG = "[DEBUG]" - private var logger: Logger? = null + private var logger: SimpleLogger? = null private var debug = false /** * Initializes Log with the given logger and specified debug mode. */ fun init(logger: Logger, debug: Boolean = false) { + init(logger::log, debug) + } + + /** + * Initializes Log with the given logger and specified debug mode. + */ + fun init(logger: SimpleLogger, debug: Boolean = false) { this.logger = logger this.debug = debug } @@ -41,14 +48,14 @@ internal object Log { * Write info message to log. */ fun i(message: String) { - logger?.info(message) + logger?.log(Level.INFO, message) } /** * Writes warning messages to log. */ fun w(message: String) { - logger?.warning(message) + logger?.log(Level.WARNING, message) } /** @@ -65,7 +72,7 @@ internal object Log { */ fun d(message: String) { if (debug) { - logger?.info("$DEBUG_TAG $message") + logger?.log(Level.INFO, "$DEBUG_TAG $message") } } @@ -88,7 +95,12 @@ internal object Log { if (debug) { logger?.log(Level.FINE, "$DEBUG_TAG Yay! Long-awaited exception!", throwable) } else if (!quiet) { - logger?.warning("Error occurred. Enable debug mode to see it.") + logger?.log(Level.WARNING, "Error occurred. Enable debug mode to see it.") } } } + +internal fun interface SimpleLogger { + fun log(level: Level, message: String) = log(level, message, null) + fun log(level: Level, message: String?, throwable: Throwable?) +} diff --git a/mimic-bukkit/src/main/kotlin/internal/Serializers.kt b/mimic-bukkit/src/main/kotlin/internal/Serializers.kt index 98d107e..a93b4a5 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Serializers.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Serializers.kt @@ -26,20 +26,21 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import org.bukkit.Registry import org.bukkit.enchantments.Enchantment import org.bukkit.inventory.ItemFlag internal object EnchantmentSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Enchantment", PrimitiveKind.STRING) + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("org.bukkit.enchantments.Enchantment", PrimitiveKind.STRING) override fun deserialize(decoder: Decoder): Enchantment { val value = decoder.decodeString() val key = namespacedKeyOf(value.replace(" ", "_").lowercase()) ?: throw SerializationException("$value is not a valid key for enchantment, " + "only latin letters, digits and symbol _ are allowed") - return Enchantment.getByKey(key) + return Registry.ENCHANTMENT[key] ?: throw SerializationException("$value is not a valid key for enchantment, " + - "must be one of: [${Enchantment.values().joinToString { it.key.toString() }}]") + "must be one of: [${Registry.ENCHANTMENT.joinToString { it.key.toString() }}]") } override fun serialize(encoder: Encoder, value: Enchantment) = encoder.encodeString(value.key.toString()) @@ -51,7 +52,7 @@ internal object ItemFlagsSerializer : KSerializer { override fun deserialize(decoder: Decoder): ItemFlag { val value = decoder.decodeString() return enumValueOrNull(value.uppercase()) - ?: throw SerializationException("$value is not a valid ItemFlag, must be one of ${ItemFlag.values()}") + ?: throw SerializationException("$value is not a valid ItemFlag, must be one of ${ItemFlag.entries}") } override fun serialize(encoder: Encoder, value: ItemFlag) = encoder.encodeString(value.name) diff --git a/mimic-bukkit/src/test/kotlin/BukkitTestBase.kt b/mimic-bukkit/src/test/kotlin/BukkitTestBase.kt index 393e26e..7e81196 100644 --- a/mimic-bukkit/src/test/kotlin/BukkitTestBase.kt +++ b/mimic-bukkit/src/test/kotlin/BukkitTestBase.kt @@ -21,41 +21,59 @@ package ru.endlesscode.mimic import io.mockk.every import io.mockk.mockk -import io.mockk.mockkStatic import org.bukkit.Bukkit import org.bukkit.Server import org.bukkit.entity.Player import org.bukkit.plugin.Plugin import org.bukkit.plugin.ServicesManager import org.bukkit.plugin.SimpleServicesManager +import ru.endlesscode.mimic.internal.Log import java.util.* /** Base for all Bukkit-related tests. */ +@Suppress("UnstableApiUsage") open class BukkitTestBase { - protected val server: Server = mockServer() protected val plugin: Plugin = mockPlugin(server) protected val player: Player = mockPlayer() protected val servicesManager: ServicesManager = server.servicesManager init { - mockBukkit() - } + Log.init({ level, message, throwable -> + println("$level: $message") + throwable?.printStackTrace() + }) - private fun mockServer(): Server = mockk { - every { pluginManager } returns mockk(relaxUnitFun = true) - every { servicesManager } returns SimpleServicesManager() + mockBukkit() } private fun mockPlugin(mockServer: Server): Plugin = mockk { every { server } returns mockServer + every { pluginMeta } returns mockk { + every { authors } returns listOf("Plugin Author") + } } private fun mockPlayer(): Player = mockk(relaxUnitFun = true) { every { uniqueId } returns UUID.randomUUID() } - private fun mockBukkit() { - mockkStatic(Bukkit::class) - every { Bukkit.getServer() } returns server + private companion object { + val server: Server = mockServer() + + private fun mockServer(): Server = mockk { + every { name } returns "MockServer" + every { version } returns "0.0.0" + every { bukkitVersion } returns "0.0.0" + + every { pluginManager } returns mockk(relaxUnitFun = true) + every { servicesManager } returns SimpleServicesManager() + every { isPrimaryThread } returns true + every { logger } returns mockk(relaxUnitFun = true) + } + + fun mockBukkit() { + @Suppress("SENSELESS_COMPARISON") // The annotation lies about nullability + if (Bukkit.getServer() == null) Bukkit.setServer(server) + } } } diff --git a/mimic-bukkit/src/test/kotlin/impl/mimic/MimicItemsRegistryTest.kt b/mimic-bukkit/src/test/kotlin/impl/mimic/MimicItemsRegistryTest.kt index 9c13c25..7e68685 100644 --- a/mimic-bukkit/src/test/kotlin/impl/mimic/MimicItemsRegistryTest.kt +++ b/mimic-bukkit/src/test/kotlin/impl/mimic/MimicItemsRegistryTest.kt @@ -32,7 +32,6 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource import org.junit.jupiter.params.provider.ValueSource import ru.endlesscode.mimic.BukkitTestBase -import ru.endlesscode.mimic.impl.vanilla.MinecraftItemsRegistry import ru.endlesscode.mimic.items.BukkitItemsRegistry import kotlin.test.Test @@ -42,19 +41,19 @@ internal class MimicItemsRegistryTest : BukkitTestBase() { private val itemsService: BukkitItemsRegistry = MimicItemsRegistry(servicesManager) init { - servicesManager.register(BukkitItemsRegistry::class.java, MinecraftItemsRegistry(), plugin, Lowest) + servicesManager.register(BukkitItemsRegistry::class.java, TestItemRegistry(), plugin, Lowest) servicesManager.register(BukkitItemsRegistry::class.java, itemsService, plugin, Highest) } @ParameterizedTest - @ValueSource(strings = ["acacia_boat", "minecraft:acacia_boat"]) + @ValueSource(strings = ["acacia_boat", "test:acacia_boat"]) fun `when check is same item - should return true`(itemId: String) { val item = ItemStack(Material.ACACIA_BOAT) itemsService.isSameItem(item, itemId).shouldBeTrue() } @ParameterizedTest - @ValueSource(strings = ["acacia_boat", "minecraft:acacia_boat"]) + @ValueSource(strings = ["acacia_boat", "test:acacia_boat"]) fun `when get item - should return item stack`(itemId: String) { val item = itemsService.getItem(itemId).shouldNotBeNull() @@ -65,7 +64,7 @@ internal class MimicItemsRegistryTest : BukkitTestBase() { } @ParameterizedTest - @ValueSource(strings = ["ns:acacia_boat", "minecraft:unknown", "42"]) + @ValueSource(strings = ["ns:acacia_boat", "test:unknown", "42"]) fun `when get unknown item - should return null`(itemId: String) { itemsService.getItem(itemId).shouldBeNull() } @@ -73,14 +72,14 @@ internal class MimicItemsRegistryTest : BukkitTestBase() { @Test fun `when get id - should return id`() { val item = ItemStack(Material.ACACIA_BOAT) - itemsService.getItemId(item) shouldBe "minecraft:acacia_boat" + itemsService.getItemId(item) shouldBe "test:acacia_boat" } @ParameterizedTest @CsvSource( "air, true", "ns:air, false", - "minecraft:air, true", + "test:air, true", "unknown, false", "gold_sword, false", "golden_sword, true", @@ -89,3 +88,17 @@ internal class MimicItemsRegistryTest : BukkitTestBase() { itemsService.isItemExists(itemId) shouldBe shouldExist } } + +private class TestItemRegistry : BukkitItemsRegistry { + override val id = "test" + override val knownIds = Material.entries.map { it.name.lowercase() } + + override fun isItemExists(itemId: String): Boolean = itemId in knownIds + + override fun getItemId(item: ItemStack): String = item.type.name.lowercase() + + override fun getItem(itemId: String, payload: Any?, amount: Int): ItemStack { + val material = Material.valueOf(itemId.uppercase()) + return ItemStack(material, amount) + } +} diff --git a/mimic-bukkit/src/test/kotlin/impl/vanilla/MinecraftItemsRegistryTest.kt b/mimic-bukkit/src/test/kotlin/impl/vanilla/MinecraftItemsRegistryTest.kt deleted file mode 100644 index cb7c4b8..0000000 --- a/mimic-bukkit/src/test/kotlin/impl/vanilla/MinecraftItemsRegistryTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of BukkitMimic. - * Copyright (C) 2020 Osip Fatkullin - * Copyright (C) 2020 EndlessCode Group and contributors - * - * BukkitMimic 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. - * - * BukkitMimic 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 BukkitMimic. If not, see . - */ - -package ru.endlesscode.mimic.impl.vanilla - -import io.kotest.assertions.assertSoftly -import io.kotest.matchers.nulls.shouldBeNull -import io.kotest.matchers.nulls.shouldNotBeNull -import io.kotest.matchers.shouldBe -import org.bukkit.Material -import org.bukkit.inventory.ItemStack -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.CsvSource -import ru.endlesscode.mimic.items.BukkitItemsRegistry -import kotlin.test.Test - -class MinecraftItemsRegistryTest { - - // SUT - private val itemsService: BukkitItemsRegistry = MinecraftItemsRegistry() - - @Test - fun `when get item - should return item stack`() { - val item = itemsService.getItem("acacia_boat").shouldNotBeNull() - - assertSoftly { - item.type shouldBe Material.ACACIA_BOAT - item.amount shouldBe 1 - } - } - - @Test - fun `when get unknown item - should return null`() { - itemsService.getItem("super_duper_item").shouldBeNull() - } - - @ParameterizedTest - @CsvSource( - "cobblestone, 0, 1", - "cobblestone, 32, 32", - "cobblestone, 65, 64", - "acacia_boat, 2, 1" - ) - fun `when get item with amount - should return item stack with right amount`( - itemId: String, - amount: Int, - realAmount: Int - ) { - itemsService.getItem(itemId, amount) - .shouldNotBeNull() - .amount shouldBe realAmount - } - - @Test - fun `when get id - should return id`() { - val item = ItemStack(Material.ACACIA_BOAT) - itemsService.getItemId(item) shouldBe "acacia_boat" - } - - @ParameterizedTest - @CsvSource( - "air, true", - "unknown, false", - "gold_sword, false", - "golden_sword, true" - ) - fun `when check is item exists`(itemId: String, shouldExist: Boolean) { - itemsService.isItemExists(itemId) shouldBe shouldExist - } -} From 39855782bb019a391739937e6aec1a5783237e33 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Tue, 22 Apr 2025 23:00:14 +0200 Subject: [PATCH 10/14] feat: Add fallback /mimic command --- .../src/main/kotlin/command/ConfigMessage.kt | 12 +++--- .../main/kotlin/command/FallbackCommand.kt | 41 +++++++++++++++++++ .../src/main/kotlin/command/MainCommand.kt | 15 ++++--- .../src/main/kotlin/command/MimicCommands.kt | 9 ++++ .../src/main/kotlin/internal/TextComponent.kt | 4 +- 5 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 mimic-bukkit/src/main/kotlin/command/FallbackCommand.kt diff --git a/mimic-bukkit/src/main/kotlin/command/ConfigMessage.kt b/mimic-bukkit/src/main/kotlin/command/ConfigMessage.kt index 2b87c7f..ffcd005 100644 --- a/mimic-bukkit/src/main/kotlin/command/ConfigMessage.kt +++ b/mimic-bukkit/src/main/kotlin/command/ConfigMessage.kt @@ -12,10 +12,10 @@ import ru.endlesscode.mimic.config.StringSetConfigProperty import ru.endlesscode.mimic.internal.append import ru.endlesscode.mimic.internal.appendClickable import ru.endlesscode.mimic.internal.appendLine -import ru.endlesscode.mimic.internal.buildTextComponent +import ru.endlesscode.mimic.internal.text @OptIn(ExperimentalMimicApi::class) -internal fun buildConfigMessage(mimic: Mimic, config: MimicConfig): TextComponent = buildTextComponent { +internal fun buildConfigMessage(mimic: Mimic, config: MimicConfig): TextComponent = text { appendLine("----[ Mimic Config ]----") appendSelectablePropertyConfig( property = MimicConfig.LEVEL_SYSTEM, @@ -53,7 +53,7 @@ private fun TextComponent.Builder.appendSelectablePropertyConfig( availableOptions, hint = "Click to select", color = NamedTextColor.GRAY, - resolveCommand = { "/mimic config ${property.path} $it" }, + resolveCommand = { "/$COMMAND_NAME config ${property.path} $it" }, ) } @@ -76,14 +76,14 @@ private fun TextComponent.Builder.appendSetPropertyConfig( hint = "Click to add", color = NamedTextColor.GRAY, nonClickableOptions = permanentOptions, - resolveCommand = { "/mimic config ${property.path} add $it" }, + resolveCommand = { "/$COMMAND_NAME config ${property.path} add $it" }, ) appendLine() appendPropertyPath(property) append("[") appendSelectableOptions(values, hint = "Click to remove") { - "/mimic config ${property.path} remove $it" + "/$COMMAND_NAME config ${property.path} remove $it" } append("]") } @@ -103,7 +103,7 @@ private fun TextComponent.Builder.appendSelectableOptions( resolveCommand: (String) -> String, ) = append( options.mapIndexed { index, option -> - buildTextComponent { + text { color(color) if (index != 0) append(", ") if (option !in nonClickableOptions) { diff --git a/mimic-bukkit/src/main/kotlin/command/FallbackCommand.kt b/mimic-bukkit/src/main/kotlin/command/FallbackCommand.kt new file mode 100644 index 0000000..c393b01 --- /dev/null +++ b/mimic-bukkit/src/main/kotlin/command/FallbackCommand.kt @@ -0,0 +1,41 @@ +package ru.endlesscode.mimic.command + +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.event.ClickEvent +import net.kyori.adventure.text.event.HoverEvent +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextDecoration +import org.bukkit.command.CommandSender +import org.bukkit.command.defaults.BukkitCommand +import ru.endlesscode.mimic.internal.append +import ru.endlesscode.mimic.internal.appendLine +import ru.endlesscode.mimic.internal.text + +internal class FallbackCommand( + private val pluginFullName: String +) : BukkitCommand( + COMMAND_NAME, + COMMAND_INFO_DESCRIPTION, + "/$COMMAND_NAME", + emptyList(), +) { + + override fun execute(sender: CommandSender, commandLabel: String, args: Array?): Boolean { + val message = text { + appendLine(pluginFullName, NamedTextColor.GREEN) + color(NamedTextColor.GRAY) + append("Install ") + append(commandApiLink()) + append(" to unlock all Mimic commands.") + } + sender.sendMessage(message) + return true + } + + private fun commandApiLink() = text { + color(NamedTextColor.YELLOW) + append("CommandAPI", TextDecoration.UNDERLINED) + hoverEvent(HoverEvent.showText(Component.text("Open CommandAPI website"))) + clickEvent(ClickEvent.openUrl("https://docs.commandapi.dev/user-setup/install")) + } +} diff --git a/mimic-bukkit/src/main/kotlin/command/MainCommand.kt b/mimic-bukkit/src/main/kotlin/command/MainCommand.kt index 05741c5..d767346 100644 --- a/mimic-bukkit/src/main/kotlin/command/MainCommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/MainCommand.kt @@ -8,16 +8,19 @@ import ru.endlesscode.mimic.config.MimicConfig import ru.endlesscode.mimic.internal.append import ru.endlesscode.mimic.internal.appendClickable import ru.endlesscode.mimic.internal.appendLine -import ru.endlesscode.mimic.internal.buildTextComponent +import ru.endlesscode.mimic.internal.text + +internal const val COMMAND_NAME = "mimic" +internal const val COMMAND_INFO_DESCRIPTION = "Show info about Mimic" /** Registers command '/mimic' and all subcommands. */ internal fun registerCommand( mimic: Mimic, config: MimicConfig, pluginFullName: String, -) = commandAPICommand("mimic") { +) = commandAPICommand(COMMAND_NAME) { withPermission("mimic.admin") - withShortDescription("Show info about Mimic") + withShortDescription(COMMAND_INFO_DESCRIPTION) executes(infoExecutor(pluginFullName)) configSubcommand(mimic, config) @@ -28,7 +31,7 @@ internal fun registerCommand( } private fun infoExecutor(pluginFullName: String) = CommandExecutor { sender, _ -> - val message = buildTextComponent { + val message = text { appendLine(pluginFullName, NamedTextColor.GREEN) color(NamedTextColor.GRAY) append("Use ") @@ -38,9 +41,9 @@ private fun infoExecutor(pluginFullName: String) = CommandExecutor { sender, _ - sender.sendMessage(message) } -private fun createClickableCommand() = buildTextComponent { +private fun createClickableCommand() = text { color(NamedTextColor.YELLOW) appendClickable(CONFIG_COMMAND, "Click to execute", CONFIG_COMMAND) } -private const val CONFIG_COMMAND = "/mimic config" +private const val CONFIG_COMMAND = "/$COMMAND_NAME config" diff --git a/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt index 33209dc..d9d4146 100644 --- a/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt +++ b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt @@ -19,9 +19,11 @@ internal class MimicCommands { if (commandApiPlugin == null) { Log.w("CommandAPI not found. Mimic commands won't be registered.") Log.w("Consider installing CommandAPI: https://docs.commandapi.dev/") + registerFallbackCommand(plugin) return } else if (!commandApiPlugin.isEnabled) { Log.w("CommandAPI loaded, but not enabled. Mimic commands won't be registered.") + registerFallbackCommand(plugin) return } @@ -33,6 +35,13 @@ internal class MimicCommands { ) } + private fun registerFallbackCommand(plugin: JavaPlugin) { + plugin.server.commandMap.register( + plugin.name.lowercase(), + FallbackCommand(plugin.pluginMeta.displayName), + ) + } + fun unregister() { if (registered) CommandAPI.unregister("mimic") } diff --git a/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt b/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt index 519bb22..d4a8ab1 100644 --- a/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt +++ b/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt @@ -7,7 +7,9 @@ import net.kyori.adventure.text.event.HoverEvent import net.kyori.adventure.text.format.TextColor import net.kyori.adventure.text.format.TextDecoration -internal fun buildTextComponent(builder: TextComponent.Builder.() -> Unit): TextComponent = Component.text(builder) +// See: https://github.com/KyoriPowered/adventure/tree/main/4/extra-kotlin + +internal fun text(builder: TextComponent.Builder.() -> Unit): TextComponent = Component.text(builder) internal fun TextComponent.Builder.appendLine( text: String, From 07a44a5f5e746fa4c548503c15062c9b9e36b6f2 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Tue, 22 Apr 2025 23:37:45 +0200 Subject: [PATCH 11/14] feat: Support MiniMessage in ItemMetaPayload --- mimic-bukkit/api/mimic-bukkit.api | 12 +++--- .../kotlin/impl/vanilla/ItemMetaPayload.kt | 16 ++++---- .../impl/vanilla/MinecraftItemsRegistry.kt | 5 +-- .../src/main/kotlin/internal/Colors.kt | 4 -- .../src/main/kotlin/internal/Serializers.kt | 40 ++++++++++++++++--- .../impl/vanilla/ItemMetaPayloadTest.kt | 9 +++-- 6 files changed, 54 insertions(+), 32 deletions(-) diff --git a/mimic-bukkit/api/mimic-bukkit.api b/mimic-bukkit/api/mimic-bukkit.api index 49c3223..b44f686 100644 --- a/mimic-bukkit/api/mimic-bukkit.api +++ b/mimic-bukkit/api/mimic-bukkit.api @@ -279,24 +279,24 @@ public final class ru/endlesscode/mimic/impl/skillapi/SkillApiLevelSystem$Compan public final class ru/endlesscode/mimic/impl/vanilla/ItemMetaPayload { public static final field Companion Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload$Companion; public fun ()V - public fun (Ljava/lang/String;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;)V - public synthetic fun (Ljava/lang/String;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; + public fun (Lnet/kyori/adventure/text/Component;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;)V + public synthetic fun (Lnet/kyori/adventure/text/Component;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lnet/kyori/adventure/text/Component; public final fun component2 ()Ljava/util/List; public final fun component3 ()Z public final fun component4 ()I public final fun component5 ()Ljava/lang/Integer; public final fun component6 ()Ljava/util/Map; public final fun component7 ()Ljava/util/Set; - public final fun copy (Ljava/lang/String;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;)Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload; - public static synthetic fun copy$default (Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload;Ljava/lang/String;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;ILjava/lang/Object;)Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload; + public final fun copy (Lnet/kyori/adventure/text/Component;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;)Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload; + public static synthetic fun copy$default (Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload;Lnet/kyori/adventure/text/Component;Ljava/util/List;ZILjava/lang/Integer;Ljava/util/Map;Ljava/util/Set;ILjava/lang/Object;)Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload; public fun equals (Ljava/lang/Object;)Z public final fun getCustomModelData ()Ljava/lang/Integer; public final fun getDamage ()I public final fun getEnchantments ()Ljava/util/Map; public final fun getFlags ()Ljava/util/Set; public final fun getLore ()Ljava/util/List; - public final fun getName ()Ljava/lang/String; + public final fun getName ()Lnet/kyori/adventure/text/Component; public fun hashCode ()I public final fun isUnbreakable ()Z public static final fun of (Ljava/lang/Object;)Lru/endlesscode/mimic/impl/vanilla/ItemMetaPayload; diff --git a/mimic-bukkit/src/main/kotlin/impl/vanilla/ItemMetaPayload.kt b/mimic-bukkit/src/main/kotlin/impl/vanilla/ItemMetaPayload.kt index a3944b6..a5fac67 100644 --- a/mimic-bukkit/src/main/kotlin/impl/vanilla/ItemMetaPayload.kt +++ b/mimic-bukkit/src/main/kotlin/impl/vanilla/ItemMetaPayload.kt @@ -17,7 +17,7 @@ * along with BukkitMimic. If not, see . */ -@file:UseSerializers(EnchantmentSerializer::class, ItemFlagsSerializer::class) +@file:UseSerializers(EnchantmentSerializer::class, ItemFlagsSerializer::class, MiniMessageComponentSerializer::class) package ru.endlesscode.mimic.impl.vanilla @@ -26,18 +26,16 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers import kotlinx.serialization.hocon.decodeFromConfig +import net.kyori.adventure.text.Component import org.bukkit.enchantments.Enchantment import org.bukkit.inventory.ItemFlag -import ru.endlesscode.mimic.internal.DI -import ru.endlesscode.mimic.internal.EnchantmentSerializer -import ru.endlesscode.mimic.internal.ItemFlagsSerializer -import ru.endlesscode.mimic.internal.Log +import ru.endlesscode.mimic.internal.* /** * Payload to configure item's [ItemMeta][org.bukkit.inventory.meta.ItemMeta]. * - * @property name Item name. You can specify colors using symbol `&`. - * @property lore Item lore. You can specify colors using symbol `&`. + * @property name Item name. Supports MiniMessage formatting. + * @property lore Item lore. Supports MiniMessage formatting. * @property isUnbreakable Is item unbreakable. Affects only items that have durability (like weapons or tools). * @property damage Damage to item durability. Affects only items that have durability (like weapons or tools). * @property customModelData A value used to override item model. @@ -48,8 +46,8 @@ import ru.endlesscode.mimic.internal.Log */ @Serializable public data class ItemMetaPayload( - val name: String? = null, - val lore: List? = null, + val name: Component? = null, + val lore: List? = null, @SerialName("unbreakable") val isUnbreakable: Boolean = false, val damage: Int = 0, diff --git a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt index b3514d0..caa12ad 100644 --- a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt +++ b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt @@ -25,7 +25,6 @@ import org.bukkit.inventory.meta.Damageable import org.bukkit.inventory.meta.ItemMeta import ru.endlesscode.mimic.internal.Log import ru.endlesscode.mimic.internal.callCompat -import ru.endlesscode.mimic.internal.colorized import ru.endlesscode.mimic.items.BukkitItemsRegistry /** @@ -68,8 +67,8 @@ public class MinecraftItemsRegistry : BukkitItemsRegistry { private fun ItemMeta.applyPayload(payload: ItemMetaPayload): ItemMeta { // Apply text options - setDisplayName(payload.name?.colorized()) - lore = payload.lore?.colorized() + displayName(payload.name) + lore(payload.lore) // Apply damage and custom model data isUnbreakable = payload.isUnbreakable diff --git a/mimic-bukkit/src/main/kotlin/internal/Colors.kt b/mimic-bukkit/src/main/kotlin/internal/Colors.kt index 1b3d082..c0be1bc 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Colors.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Colors.kt @@ -21,8 +21,4 @@ package ru.endlesscode.mimic.internal import org.bukkit.ChatColor -internal fun List.colorized(): List = map { it.colorized() } - -internal fun String.colorized(): String = ChatColor.translateAlternateColorCodes('&', this) - internal fun String.stripColor(): String = checkNotNull(ChatColor.stripColor(this)) diff --git a/mimic-bukkit/src/main/kotlin/internal/Serializers.kt b/mimic-bukkit/src/main/kotlin/internal/Serializers.kt index a93b4a5..922ea66 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Serializers.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Serializers.kt @@ -26,28 +26,39 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.minimessage.MiniMessage import org.bukkit.Registry import org.bukkit.enchantments.Enchantment import org.bukkit.inventory.ItemFlag internal object EnchantmentSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("org.bukkit.enchantments.Enchantment", PrimitiveKind.STRING) + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor( + "org.bukkit.enchantments.Enchantment", + PrimitiveKind.STRING + ) override fun deserialize(decoder: Decoder): Enchantment { val value = decoder.decodeString() val key = namespacedKeyOf(value.replace(" ", "_").lowercase()) - ?: throw SerializationException("$value is not a valid key for enchantment, " + - "only latin letters, digits and symbol _ are allowed") + ?: throw SerializationException( + "$value is not a valid key for enchantment, only latin letters, digits and symbol _ are allowed" + ) return Registry.ENCHANTMENT[key] - ?: throw SerializationException("$value is not a valid key for enchantment, " + - "must be one of: [${Registry.ENCHANTMENT.joinToString { it.key.toString() }}]") + ?: throw SerializationException( + "$value is not a valid key for enchantment, " + + "must be one of: [${Registry.ENCHANTMENT.joinToString { it.key.toString() }}]" + ) } override fun serialize(encoder: Encoder, value: Enchantment) = encoder.encodeString(value.key.toString()) } internal object ItemFlagsSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ItemFlag", PrimitiveKind.STRING) + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor( + "org.bukkit.inventory.ItemFlag", + PrimitiveKind.STRING, + ) override fun deserialize(decoder: Decoder): ItemFlag { val value = decoder.decodeString() @@ -57,3 +68,20 @@ internal object ItemFlagsSerializer : KSerializer { override fun serialize(encoder: Encoder, value: ItemFlag) = encoder.encodeString(value.name) } + +internal object MiniMessageComponentSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor( + "net.kyori.adventure.text.Component", + PrimitiveKind.STRING, + ) + + private val mm = MiniMessage.miniMessage() + + override fun deserialize(decoder: Decoder): Component { + return mm.deserialize(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: Component) { + encoder.encodeString(mm.serialize(value)) + } +} diff --git a/mimic-bukkit/src/test/kotlin/impl/vanilla/ItemMetaPayloadTest.kt b/mimic-bukkit/src/test/kotlin/impl/vanilla/ItemMetaPayloadTest.kt index 7ce060c..aabfeb9 100644 --- a/mimic-bukkit/src/test/kotlin/impl/vanilla/ItemMetaPayloadTest.kt +++ b/mimic-bukkit/src/test/kotlin/impl/vanilla/ItemMetaPayloadTest.kt @@ -21,6 +21,7 @@ package ru.endlesscode.mimic.impl.vanilla import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe +import net.kyori.adventure.text.Component.text import org.bukkit.inventory.ItemFlag import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments @@ -55,8 +56,8 @@ internal class ItemMetaPayloadTest { @JvmStatic fun validData(): Stream = Stream.of( // Simple cases - arguments("{name: Name}", ItemMetaPayload(name = "Name")), - arguments("name=Name", ItemMetaPayload(name = "Name")), + arguments("{name: Name}", ItemMetaPayload(name = text("Name"))), + arguments("name=Name", ItemMetaPayload(name = text("Name"))), arguments( """ name = Name, @@ -67,8 +68,8 @@ internal class ItemMetaPayloadTest { flags = [HIDE_ATTRIBUTES, HIDE_DYE] """, ItemMetaPayload( - name = "Name", - lore = listOf("Line1", "Line2"), + name = text("Name"), + lore = listOf(text("Line1"), text("Line2")), isUnbreakable = true, damage = 42, customModelData = 24, From 44a6b40ae957fb4028353d81ddba11ca67ade877 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Wed, 23 Apr 2025 00:12:39 +0200 Subject: [PATCH 12/14] chore: Use components instead of legacy colors --- .../kotlin/command/ClassSystemSubcommand.kt | 43 ++++++++++++----- .../kotlin/command/InventorySubcommand.kt | 17 ++++--- .../main/kotlin/command/ItemsSubcommand.kt | 48 +++++++++++-------- .../kotlin/command/LevelSystemSubcommand.kt | 27 +++++++---- .../{commandUtils.kt => textUserInterface.kt} | 24 +++++----- .../src/main/kotlin/internal/Colors.kt | 3 ++ .../src/main/kotlin/internal/TextComponent.kt | 2 +- .../main/kotlin/items/WrappedItemsRegistry.kt | 4 +- 8 files changed, 107 insertions(+), 61 deletions(-) rename mimic-bukkit/src/main/kotlin/command/{commandUtils.kt => textUserInterface.kt} (56%) diff --git a/mimic-bukkit/src/main/kotlin/command/ClassSystemSubcommand.kt b/mimic-bukkit/src/main/kotlin/command/ClassSystemSubcommand.kt index a287277..22f00ea 100644 --- a/mimic-bukkit/src/main/kotlin/command/ClassSystemSubcommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/ClassSystemSubcommand.kt @@ -23,7 +23,12 @@ import dev.jorel.commandapi.executors.PlayerCommandExecutor import dev.jorel.commandapi.kotlindsl.greedyStringArgument import dev.jorel.commandapi.kotlindsl.playerArgument import dev.jorel.commandapi.kotlindsl.subcommand +import net.kyori.adventure.text.TextComponent +import net.kyori.adventure.text.format.NamedTextColor import ru.endlesscode.mimic.Mimic +import ru.endlesscode.mimic.internal.append +import ru.endlesscode.mimic.internal.appendLine +import ru.endlesscode.mimic.internal.text /** * Commands to deal with class systems. @@ -51,11 +56,15 @@ private fun infoCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { player, val target = args.getOrDefaultUnchecked(TARGET, player) val provider = mimic.getClassSystemProvider() val system = provider.getSystem(target) - player.send( - "&3System: &7${provider.id}", - "&3Classes: &7${system.classes}", - "&3Primary: &7${system.primaryClass}", - ) + + val message = text { + appendStats( + "System" to provider.id, + "Classes" to system.classes.toString(), + "Primary" to system.primaryClass.toString(), + ) + } + player.sendMessage(message) } private fun checkCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { player, args -> @@ -65,14 +74,26 @@ private fun checkCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { player, val system = mimic.getClassSystem(target) val hasAllClasses = system.hasAllClasses(classes) val hasAnyOfClasses = system.hasAnyOfClasses(classes) - target.send( - "&6Player '${target.name}':", - "&6- has any of: ${hasAnyOfClasses.toChatMessage()}", - "&6- has all: ${hasAllClasses.toChatMessage()}", - ) + + val message = text { + color(NamedTextColor.GOLD) + appendLine("Player '${target.name}':") + append("- has any of: ") + appendStatus(hasAnyOfClasses) + appendLine() + append("- has all: ") + appendStatus(hasAllClasses) + } + target.sendMessage(message) } -private fun Boolean.toChatMessage(): String = if (this) "&ayes" else "&cno" +private fun TextComponent.Builder.appendStatus(status: Boolean) { + if (status) { + append("yes", NamedTextColor.GREEN) + } else { + append("no", NamedTextColor.RED) + } +} private const val TARGET = "target" private const val CLASSES = "classes" diff --git a/mimic-bukkit/src/main/kotlin/command/InventorySubcommand.kt b/mimic-bukkit/src/main/kotlin/command/InventorySubcommand.kt index 01eb240..2ed4e83 100644 --- a/mimic-bukkit/src/main/kotlin/command/InventorySubcommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/InventorySubcommand.kt @@ -6,6 +6,7 @@ import dev.jorel.commandapi.kotlindsl.playerExecutor import dev.jorel.commandapi.kotlindsl.subcommand import ru.endlesscode.mimic.ExperimentalMimicApi import ru.endlesscode.mimic.Mimic +import ru.endlesscode.mimic.internal.text /** * Commands to deal with inventory provider. @@ -24,12 +25,16 @@ internal fun CommandAPICommand.inventorySubcommand(mimic: Mimic) = subcommand("i val target = args.getOrDefaultUnchecked(TARGET, sender) val provider = mimic.getPlayerInventoryProvider() val inventory = provider.getSystem(target) - sender.send( - "&3Inventory provider: &7${provider.id}", - "&3Count of Equipped: &7%d".format(inventory.equippedItems.size), - "&3Count of Stored: &7%d".format(inventory.storedItems.size), - "&3Total Count: &7%d".format(inventory.items.size), - ) + + val message = text { + appendStats( + "Inventory provider" to provider.id, + "Count of Equipped" to inventory.equippedItems.size.toString(), + "Count of Stored" to inventory.storedItems.size.toString(), + "Total Count" to inventory.items.size.toString(), + ) + } + sender.sendMessage(message) } } } diff --git a/mimic-bukkit/src/main/kotlin/command/ItemsSubcommand.kt b/mimic-bukkit/src/main/kotlin/command/ItemsSubcommand.kt index af6d31e..487090a 100644 --- a/mimic-bukkit/src/main/kotlin/command/ItemsSubcommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/ItemsSubcommand.kt @@ -23,9 +23,14 @@ import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.arguments.ArgumentSuggestions import dev.jorel.commandapi.executors.CommandExecutor import dev.jorel.commandapi.kotlindsl.* +import net.kyori.adventure.text.format.NamedTextColor import org.bukkit.entity.Player import ru.endlesscode.mimic.impl.mimic.MimicItemsRegistry +import ru.endlesscode.mimic.internal.append +import ru.endlesscode.mimic.internal.appendLine +import ru.endlesscode.mimic.internal.text import ru.endlesscode.mimic.items.BukkitItemsRegistry +import ru.endlesscode.mimic.items.unwrap /** * Commands to deal with items registries @@ -59,7 +64,7 @@ internal fun CommandAPICommand.itemsSubcommand(itemsRegistry: BukkitItemsRegistr playerExecutor { sender, args -> val item: String by args val isSame = itemsRegistry.isSameItem(sender.inventory.itemInMainHand, item) - sender.send("&6Item in hand and '$item' %s same.".format(if (isSame) "are" else "aren't")) + sender.sendMessage(successText("Item in hand and '$item' %s same.".format(if (isSame) "are" else "aren't"))) } } @@ -67,7 +72,7 @@ internal fun CommandAPICommand.itemsSubcommand(itemsRegistry: BukkitItemsRegistr withShortDescription("Prints ID of item in hand") playerExecutor { sender, _ -> val id = itemsRegistry.getItemId(sender.inventory.itemInMainHand) - sender.send("&6Id of item in hand is '$id'") + sender.sendMessage(successText("Id of item in hand is '$id'")) } } @@ -77,31 +82,35 @@ internal fun CommandAPICommand.itemsSubcommand(itemsRegistry: BukkitItemsRegistr anyExecutor { sender, args -> val item: String by args val itemExists = itemsRegistry.isItemExists(item) - sender.send("&6Item with id '$item'%s exists".format(if (itemExists) "" else " isn't")) + sender.sendMessage(successText("Item with id '$item'%s exists".format(if (itemExists) "" else " isn't"))) } } } // We can use only greedy string if we need to allow colons because it requires quoting in non-greedy strings. // https://github.com/Mojang/brigadier/blob/cf754c4ef654160dca946889c11941634c5db3d5/src/main/java/com/mojang/brigadier/StringReader.java#L169 -private fun CommandAPICommand.itemArgument(itemsRegistry: BukkitItemsRegistry) = greedyStringArgument(ITEM) { - replaceSuggestions(ArgumentSuggestions.stringCollection { itemsRegistry.knownIds }) +private fun CommandAPICommand.itemArgument(itemRegistry: BukkitItemsRegistry) = greedyStringArgument(ITEM) { + replaceSuggestions(ArgumentSuggestions.stringCollection { itemRegistry.knownIds }) } -private fun infoExecutor(itemsRegistry: BukkitItemsRegistry) = CommandExecutor { sender, _ -> - val registries = (itemsRegistry as? MimicItemsRegistry)?.providers - .orEmpty() - .map { it.provider } - .map { " &f${it.id}: &7${it.knownIds.size}" } +private fun infoExecutor(itemRegistry: BukkitItemsRegistry) = CommandExecutor { sender, _ -> + val providers = (itemRegistry.unwrap() as? MimicItemsRegistry)?.providers.orEmpty().map { it.provider } - sender.send( - "&3Items Service: &7${itemsRegistry.id}", - "&3Known IDs amount: &7${itemsRegistry.knownIds.size}" - ) - sender.send(registries) + val message = text { + appendStats( + "Item Registry" to itemRegistry.id, + "Known IDs amount" to itemRegistry.knownIds.size.toString(), + ) + + for (provider in providers) { + append(" ${provider.id}: ", NamedTextColor.WHITE) + appendLine(provider.knownIds.size.toString(), NamedTextColor.GRAY) + } + } + sender.sendMessage(message) } -private fun giveExecutor(itemsRegistry: BukkitItemsRegistry) = CommandExecutor { sender, args -> +private fun giveExecutor(itemRegistry: BukkitItemsRegistry) = CommandExecutor { sender, args -> val target: Player by args val amount = args.getOrDefaultUnchecked(AMOUNT, 1) // We can use only one greedy string at the end, so we read item and its payload from the same argument @@ -109,16 +118,15 @@ private fun giveExecutor(itemsRegistry: BukkitItemsRegistry) = CommandExecutor { val item = itemParts.first() val payload = itemParts.getOrNull(1) - val itemStack = itemsRegistry.getItem(item, payload, amount) + val itemStack = itemRegistry.getItem(item, payload, amount) if (itemStack != null) { target.inventory.addItem(itemStack) - sender.send("&6Gave ${itemStack.amount} [$item] to ${target.name}.") + sender.sendMessage(successText("Gave ${itemStack.amount} [$item] to ${target.name}.")) } else { - sender.send("&cUnknown item '$item'.") + sender.sendMessage(errorText("Unknown item '$item'")) } } private const val TARGET = "target" private const val ITEM = "item" private const val AMOUNT = "amount" -private const val PAYLOAD = "payload" diff --git a/mimic-bukkit/src/main/kotlin/command/LevelSystemSubcommand.kt b/mimic-bukkit/src/main/kotlin/command/LevelSystemSubcommand.kt index ed2a4e2..3c6e036 100644 --- a/mimic-bukkit/src/main/kotlin/command/LevelSystemSubcommand.kt +++ b/mimic-bukkit/src/main/kotlin/command/LevelSystemSubcommand.kt @@ -24,9 +24,11 @@ import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.arguments.ArgumentSuggestions import dev.jorel.commandapi.executors.PlayerCommandExecutor import dev.jorel.commandapi.kotlindsl.* +import net.kyori.adventure.text.TextComponent import org.bukkit.command.CommandSender import ru.endlesscode.mimic.Mimic import ru.endlesscode.mimic.internal.Log +import ru.endlesscode.mimic.internal.text import ru.endlesscode.mimic.level.BukkitLevelSystem import kotlin.math.roundToInt @@ -97,12 +99,17 @@ private fun infoCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { sender, val target = args.getOrDefaultUnchecked(TARGET, sender) val provider = mimic.getLevelSystemProvider() val system = provider.getSystem(target) - sender.send( - "&3System: &7${provider.id}", - "&3Level: &7%.2f".format(system.level + system.fractionalExp), - "&3Exp: &7%.1f &8| &3To next level: &7%.1f".format(system.exp, system.expToNextLevel), - "&3Total exp: &7%.1f".format(system.totalExp) - ) + + val message = text { + appendStats( + "System" to provider.id, + "Level" to "%.2f".format(system.level + system.fractionalExp), + "Exp" to "%.1f".format(system.exp), + "Exp to next level" to "%.1f".format(system.expToNextLevel), + "Total exp" to "%.1f".format(system.totalExp) + ) + } + target.sendMessage(message) } private fun setCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { sender, args -> @@ -159,7 +166,7 @@ private inline fun catchUnsupported(block: () -> Unit) { } private fun BukkitLevelSystem.printNewStats(sender: CommandSender) { - sender.send("&6New ${player.name}'s stats: $level LVL, %.1f XP".format(exp)) + sender.sendMessage(successText("New ${player.name}'s stats: $level LVL, %.1f XP".format(exp))) } private fun hasCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { sender, args -> @@ -167,9 +174,9 @@ private fun hasCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { sender, a val type = args.getOrDefaultRaw(TYPE, TYPE_LVL) val target = args.getOrDefaultUnchecked(TARGET, sender) - fun buildMessage(has: Boolean, valueType: String): String { + fun buildMessage(has: Boolean, valueType: String): TextComponent { val hasOrNot = if (has) "has" else "has not" - return "&6${target.name} $hasOrNot $amount $valueType." + return successText("${target.name} $hasOrNot $amount $valueType.") } val system = mimic.getLevelSystem(target) @@ -179,7 +186,7 @@ private fun hasCommandExecutor(mimic: Mimic) = PlayerCommandExecutor { sender, a TYPE_TOTAL -> buildMessage(system.hasExpTotal(amount), "total experience") else -> error("Unexpected type: $type") } - sender.send(message) + sender.sendMessage(message) } private const val TARGET = "target" diff --git a/mimic-bukkit/src/main/kotlin/command/commandUtils.kt b/mimic-bukkit/src/main/kotlin/command/textUserInterface.kt similarity index 56% rename from mimic-bukkit/src/main/kotlin/command/commandUtils.kt rename to mimic-bukkit/src/main/kotlin/command/textUserInterface.kt index 91e03c5..3d752ee 100644 --- a/mimic-bukkit/src/main/kotlin/command/commandUtils.kt +++ b/mimic-bukkit/src/main/kotlin/command/textUserInterface.kt @@ -18,19 +18,19 @@ */ package ru.endlesscode.mimic.command -import org.bukkit.ChatColor -import org.bukkit.command.CommandSender +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.TextComponent +import net.kyori.adventure.text.format.NamedTextColor +import ru.endlesscode.mimic.internal.append +import ru.endlesscode.mimic.internal.appendLine -internal fun CommandSender.send(vararg messages: String) { - for (message in messages) { - sendMessage(message.colored()) - } -} +internal fun successText(text: String) = Component.text(text, NamedTextColor.GOLD) +internal fun errorText(text: String) = Component.text(text, NamedTextColor.RED) -internal fun CommandSender.send(messages: Collection) { - for (message in messages) { - sendMessage(message.colored()) +internal fun TextComponent.Builder.appendStats(vararg stats: Pair) { + for ((key, value) in stats) { + append("$key: ", NamedTextColor.DARK_AQUA) + append(value, NamedTextColor.GRAY) + appendLine() } } - -private fun String.colored(): String = ChatColor.translateAlternateColorCodes('&', this) diff --git a/mimic-bukkit/src/main/kotlin/internal/Colors.kt b/mimic-bukkit/src/main/kotlin/internal/Colors.kt index c0be1bc..a0b75c8 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Colors.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Colors.kt @@ -17,6 +17,9 @@ * along with BukkitMimic. If not, see . */ +// Keep it for now +@file:Suppress("DEPRECATION") + package ru.endlesscode.mimic.internal import org.bukkit.ChatColor diff --git a/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt b/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt index d4a8ab1..fe02c90 100644 --- a/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt +++ b/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt @@ -17,7 +17,7 @@ internal fun TextComponent.Builder.appendLine( vararg decorations: TextDecoration, ): TextComponent.Builder = append(text, color, *decorations).appendLine() -internal fun TextComponent.Builder.appendLine(): TextComponent.Builder = append("\n") +internal fun TextComponent.Builder.appendLine(): TextComponent.Builder = append(Component.newline()) internal fun TextComponent.Builder.append( text: String, diff --git a/mimic-bukkit/src/main/kotlin/items/WrappedItemsRegistry.kt b/mimic-bukkit/src/main/kotlin/items/WrappedItemsRegistry.kt index 26eab22..b707ab6 100644 --- a/mimic-bukkit/src/main/kotlin/items/WrappedItemsRegistry.kt +++ b/mimic-bukkit/src/main/kotlin/items/WrappedItemsRegistry.kt @@ -7,7 +7,7 @@ import ru.endlesscode.mimic.WrappedMimicService import ru.endlesscode.mimic.config.MimicConfig internal class WrappedItemsRegistry( - private val delegate: BukkitItemsRegistry, + internal val delegate: BukkitItemsRegistry, private val config: MimicConfig, pluginName: String, pluginManager: PluginManager, @@ -27,3 +27,5 @@ internal class WrappedItemsRegistry( override fun getItem(itemId: String, payload: Any?, amount: Int) = delegate.getItem(itemId, payload, amount) } + +internal fun BukkitItemsRegistry.unwrap() = if (this is WrappedItemsRegistry) delegate else this From 6a7bee21532d777d23509cdbe6a03ee5a162f3e4 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Wed, 23 Apr 2025 00:41:40 +0200 Subject: [PATCH 13/14] chore: Update testing dependencies --- gradle/libs.versions.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0192ccd..d9ead5c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,13 +17,13 @@ mmoitems = "6.9.5-SNAPSHOT" mythiclib = "1.6.2-SNAPSHOT" heroes = "1.9.30-RELEASE" -junit = "5.10.1" -kotest = "5.8.0" -mockk = "1.13.8" +junit = "5.12.2" +kotest = "6.0.0.M3" +mockk = "1.14.0" gradlePlugin-bukkitgradle = "1.0.0" -gradlePlugin-shadow = "8.1.1" -gradlePlugin-versions = "0.50.0" +gradlePlugin-shadow = "8.3.6" +gradlePlugin-versions = "0.52.0" [libraries] @@ -56,7 +56,7 @@ kotlinx-binaryCompatibilityValidator = { module = "org.jetbrains.kotlinx:binary- [plugins] bukkitgradle = { id = "ru.endlesscode.bukkitgradle", version.ref = "gradlePlugin-bukkitgradle" } -shadow = { id = "com.github.johnrengelman.shadow", version.ref = "gradlePlugin-shadow" } +shadow = { id = "com.gradleup.shadow", version.ref = "gradlePlugin-shadow" } versions = { id = "com.github.ben-manes.versions", version.ref = "gradlePlugin-versions" } [bundles] From 9bd6f14278a4c1d693b4431f9e657da21d831404 Mon Sep 17 00:00:00 2001 From: Osip Fatkullin Date: Wed, 23 Apr 2025 10:03:21 +0200 Subject: [PATCH 14/14] chore: Remove redundant compatibility layers --- .../impl/vanilla/MinecraftItemsRegistry.kt | 11 +---------- .../src/main/kotlin/internal/Compat.kt | 1 + .../src/main/kotlin/internal/Configuration.kt | 14 ++------------ .../src/main/kotlin/internal/NamespacedKey.kt | 18 +----------------- 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt index caa12ad..f5776bb 100644 --- a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt +++ b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt @@ -24,7 +24,6 @@ import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.Damageable import org.bukkit.inventory.meta.ItemMeta import ru.endlesscode.mimic.internal.Log -import ru.endlesscode.mimic.internal.callCompat import ru.endlesscode.mimic.items.BukkitItemsRegistry /** @@ -73,7 +72,7 @@ public class MinecraftItemsRegistry : BukkitItemsRegistry { // Apply damage and custom model data isUnbreakable = payload.isUnbreakable (this as? Damageable)?.damage = payload.damage - if (payload.customModelData != null) trySetCustomModelData(payload.customModelData) + if (payload.customModelData != null) setCustomModelData(payload.customModelData) // Apply enchants and item flags payload.enchantments.forEach { (enchant, level) -> addEnchant(enchant, level, true) } @@ -82,14 +81,6 @@ public class MinecraftItemsRegistry : BukkitItemsRegistry { return this } - private fun ItemMeta.trySetCustomModelData(data: Int) { - callCompat( - "ItemMeta.setCustomModelData", - block = { setCustomModelData(data) }, - compat = { Log.w("Payload field 'custom-model-data' supported only since Minecraft 1.14") }, - ) - } - public companion object { public const val ID: String = "minecraft" } diff --git a/mimic-bukkit/src/main/kotlin/internal/Compat.kt b/mimic-bukkit/src/main/kotlin/internal/Compat.kt index a621292..5df4b7c 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Compat.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Compat.kt @@ -2,6 +2,7 @@ package ru.endlesscode.mimic.internal private val notSupportedCalls = mutableSetOf() +@Suppress("unused") // Reserved for further compatibility calls internal inline fun callCompat( key: String, block: () -> T, diff --git a/mimic-bukkit/src/main/kotlin/internal/Configuration.kt b/mimic-bukkit/src/main/kotlin/internal/Configuration.kt index 5126173..95bb8d2 100644 --- a/mimic-bukkit/src/main/kotlin/internal/Configuration.kt +++ b/mimic-bukkit/src/main/kotlin/internal/Configuration.kt @@ -3,13 +3,8 @@ package ru.endlesscode.mimic.internal import org.bukkit.configuration.Configuration import org.bukkit.configuration.file.FileConfigurationOptions -@Suppress("DEPRECATION") // Changed in 1.18.1 internal fun FileConfigurationOptions.setHeader(vararg lines: String) { - callCompat( - "FileConfigurationOptions.setHeader", - block = { setHeader(lines.asList()) }, - compat = { header(lines.joinToString("\n")) }, - ) + setHeader(lines.asList()) } internal fun Configuration.applyDefaults() { @@ -17,11 +12,6 @@ internal fun Configuration.applyDefaults() { for (key in defaults.getKeys(true)) set(key, get(key)) } -// Added in 1.18.1 internal fun Configuration.setComments(path: String, vararg comments: String?) { - callCompat( - "Configuration.setComments", - block = { setComments(path, comments.asList()) }, - compat = { /* no-op */ }, - ) + setComments(path, comments.asList()) } diff --git a/mimic-bukkit/src/main/kotlin/internal/NamespacedKey.kt b/mimic-bukkit/src/main/kotlin/internal/NamespacedKey.kt index 094828e..3eb6b5c 100644 --- a/mimic-bukkit/src/main/kotlin/internal/NamespacedKey.kt +++ b/mimic-bukkit/src/main/kotlin/internal/NamespacedKey.kt @@ -2,20 +2,4 @@ package ru.endlesscode.mimic.internal import org.bukkit.NamespacedKey -internal fun namespacedKeyOf(key: String): NamespacedKey? { - return callCompat( - "NamespacedKey.fromString", - block = { NamespacedKey.fromString(key) }, - compat = { namespacedKeyCompat(key) }, - ) -} - -@Suppress("DEPRECATION") -private fun namespacedKeyCompat(string: String): NamespacedKey? { - val components = string.split(":", limit = 3) - return when (components.size) { - 1 -> NamespacedKey.minecraft(components.first()) - 2 -> NamespacedKey(components.first(), components.last()) - else -> null - } -} +internal fun namespacedKeyOf(key: String): NamespacedKey? = NamespacedKey.fromString(key)