diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index b5b1c7ad..d5da9f10 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 5c4facdd..e3db56ad 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/.run/Run Server [mimic-bukkit].run.xml b/.run/Run Server [mimic-bukkit].run.xml
new file mode 100644
index 00000000..8ece5bf9
--- /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/CHANGELOG.md b/CHANGELOG.md
index e55bcc55..c3f215ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,20 @@
## [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`
-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.
@@ -25,10 +37,10 @@ Since 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 required Java 1.8 → 17
+- Update Kotlin 1.6.20 → 2.1.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 64fcc2b4..e63e03f7 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")
}
@@ -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 b5a0fabf..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 d3886bd9..84524062 100644
--- a/buildSrc/src/main/kotlin/commons.gradle.kts
+++ b/buildSrc/src/main/kotlin/commons.gradle.kts
@@ -18,30 +18,19 @@ tasks.test {
}
kotlin {
- jvmToolchain(16)
+ jvmToolchain(17)
explicitApi()
compilerOptions {
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
- }
-}
-
-// 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"))
+ implementation(kotlin("stdlib"))
testingDependencies()
}
diff --git a/buildSrc/src/main/kotlin/internal/Accessors.kt b/buildSrc/src/main/kotlin/internal/Accessors.kt
new file mode 100644
index 00000000..60ed9bf4
--- /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 87bb80bc..57946636 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()
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index c6ff5b1e..d9ead5c6 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,44 +1,63 @@
[versions]
-kotlin = "1.9.20"
-commandapi = "9.2.0"
-junit = "5.10.1"
+paper = "1.20-R0.1-SNAPSHOT"
+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"
+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.12.2"
+kotest = "6.0.0.M3"
+mockk = "1.14.0"
+
+gradlePlugin-bukkitgradle = "1.0.0"
+gradlePlugin-shadow = "8.3.6"
+gradlePlugin-versions = "0.52.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.6.1"
-adventure = "net.kyori:adventure-platform-bukkit:4.3.1"
+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-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" }
+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:1.9.2"
-rpgplugins-mmoitems = "net.Indyuce:MMOItems:6.7.2"
-rpgplugins-mythiclib = "io.lumine:MythicLib-dist:1.4"
-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.13.2"
-gradleDownloadTask = "de.undercouch:gradle-download-task:5.5.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 = "ru.endlesscode.bukkitgradle:0.10.1"
-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.gradleup.shadow", version.ref = "gradlePlugin-shadow" }
+versions = { id = "com.github.ben-manes.versions", version.ref = "gradlePlugin-versions" }
[bundles]
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7f93135c..9bbc975c 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1af9e093..37f853b1 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 1aa94a42..faf93008 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 93e3f59f..9d21a218 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
diff --git a/mimic-bukkit-api/build.gradle.kts b/mimic-bukkit-api/build.gradle.kts
index 0528f11b..04aca800 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/api/mimic-bukkit.api b/mimic-bukkit/api/mimic-bukkit.api
index 51d172e1..b44f686a 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;
@@ -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 {
diff --git a/mimic-bukkit/build.gradle.kts b/mimic-bukkit/build.gradle.kts
index 9622f60b..ca85928d 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,28 +10,50 @@ plugins {
kotlin("plugin.serialization")
}
-description = "Bukkit plugin with implementations of Mimic APIs"
+description = "Bukkit plugin implementing Mimic APIs"
bukkit {
- meta {
+ apiVersion = "1.20"
+
+ 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"
+ softDepend = listOf("CommandAPI")
+ loadBefore = listOf(
+ "SkillAPI",
+ "BattleLevels",
+ "CustomItems",
+ "MMOCore",
+ "MMOItems",
+ "Heroes",
+ "QuantumRPG",
+ )
}
server {
- setCore("paper")
+ version = "1.21.5"
eula = true
}
}
+tasks.runServer {
+ downloadPlugins {
+ github("CommandAPI", "CommandAPI", "10.0.0", "CommandAPI-10.0.0.jar")
+ }
+}
+
repositories {
+ papermc()
maven(url = "https://gitlab.com/endlesscodegroup/mvn-repo/raw/master/")
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")
}
@@ -45,23 +68,22 @@ 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.commandapi)
- implementation(libs.commandapi.kotlin)
- implementation(libs.adventure)
+ compileOnly(libs.commandapi)
+ compileOnly(libs.commandapi.kotlin)
compileOnly(libs.bundles.rpgplugins) { isTransitive = false }
// 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)
}
@@ -71,6 +93,12 @@ kotlin {
}
}
+tasks.test {
+ javaLauncher = javaToolchains.launcherFor {
+ languageVersion = JavaLanguageVersion.of(17)
+ }
+}
+
tasks.shadowJar {
dependencies {
exclude(dependency("org.jetbrains:annotations:.*"))
@@ -80,9 +108,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")
exclude("META-INF/*.kotlin_module")
exclude("META-INF/com.android.tools/**")
diff --git a/mimic-bukkit/libs/QuantumRPG-5.10.2.jar b/mimic-bukkit/libs/QuantumRPG-5.10.2.jar
index acf19fc5..21e82345 100644
Binary files a/mimic-bukkit/libs/QuantumRPG-5.10.2.jar and b/mimic-bukkit/libs/QuantumRPG-5.10.2.jar differ
diff --git a/mimic-bukkit/src/main/kotlin/MimicPlugin.kt b/mimic-bukkit/src/main/kotlin/MimicPlugin.kt
index a4e6773f..047e9059 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
@@ -60,34 +57,25 @@ 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) }
- 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/ServicesRegistrationListener.kt b/mimic-bukkit/src/main/kotlin/ServicesRegistrationListener.kt
index b26183b1..eb83d7fd 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/ClassSystemSubcommand.kt b/mimic-bukkit/src/main/kotlin/command/ClassSystemSubcommand.kt
index a287277a..22f00eac 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/ConfigCommand.kt b/mimic-bukkit/src/main/kotlin/command/ConfigCommand.kt
index 4cc12340..eb8cb832 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/ConfigMessage.kt b/mimic-bukkit/src/main/kotlin/command/ConfigMessage.kt
index 2b87c7fc..ffcd005c 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 00000000..c393b011
--- /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/InventorySubcommand.kt b/mimic-bukkit/src/main/kotlin/command/InventorySubcommand.kt
index 01eb2401..2ed4e83e 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 af6d31e4..487090a0 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 ed2a4e2e..3c6e036a 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/MainCommand.kt b/mimic-bukkit/src/main/kotlin/command/MainCommand.kt
index c81b2046..d767346d 100644
--- a/mimic-bukkit/src/main/kotlin/command/MainCommand.kt
+++ b/mimic-bukkit/src/main/kotlin/command/MainCommand.kt
@@ -2,47 +2,48 @@ 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
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,
- audiences: BukkitAudiences,
-) = commandAPICommand("mimic") {
+) = commandAPICommand(COMMAND_NAME) {
withPermission("mimic.admin")
- withShortDescription("Show info about Mimic")
- executes(infoExecutor(audiences, pluginFullName))
+ withShortDescription(COMMAND_INFO_DESCRIPTION)
+ 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, _ ->
- val message = buildTextComponent {
+private fun infoExecutor(pluginFullName: String) = CommandExecutor { sender, _ ->
+ val message = text {
appendLine(pluginFullName, NamedTextColor.GREEN)
color(NamedTextColor.GRAY)
append("Use ")
append(createClickableCommand())
append(" to see or change configs")
}
- audiences.sender(sender).sendMessage(message)
+ 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
new file mode 100644
index 00000000..d9d41469
--- /dev/null
+++ b/mimic-bukkit/src/main/kotlin/command/MimicCommands.kt
@@ -0,0 +1,48 @@
+package ru.endlesscode.mimic.command
+
+import dev.jorel.commandapi.CommandAPI
+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
+
+ 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/")
+ registerFallbackCommand(plugin)
+ return
+ } else if (!commandApiPlugin.isEnabled) {
+ Log.w("CommandAPI loaded, but not enabled. Mimic commands won't be registered.")
+ registerFallbackCommand(plugin)
+ return
+ }
+
+ registered = true
+ registerCommand(
+ mimic = mimic,
+ config = config,
+ pluginFullName = plugin.pluginMeta.displayName,
+ )
+ }
+
+ private fun registerFallbackCommand(plugin: JavaPlugin) {
+ plugin.server.commandMap.register(
+ plugin.name.lowercase(),
+ FallbackCommand(plugin.pluginMeta.displayName),
+ )
+ }
+
+ fun unregister() {
+ if (registered) CommandAPI.unregister("mimic")
+ }
+}
\ No newline at end of file
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 91e03c59..3d752ee3 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/impl/mimic/SafeBukkitItemsRegistry.kt b/mimic-bukkit/src/main/kotlin/impl/mimic/SafeBukkitItemsRegistry.kt
index 6f5918cc..eac91e1f 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/mmocore/MmoCoreLevelSystem.kt b/mimic-bukkit/src/main/kotlin/impl/mmocore/MmoCoreLevelSystem.kt
index 95b65b00..48c9f439 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
diff --git a/mimic-bukkit/src/main/kotlin/impl/vanilla/ItemMetaPayload.kt b/mimic-bukkit/src/main/kotlin/impl/vanilla/ItemMetaPayload.kt
index a3944b62..a5fac67f 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 9b8b8bcf..f5776bb1 100644
--- a/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt
+++ b/mimic-bukkit/src/main/kotlin/impl/vanilla/MinecraftItemsRegistry.kt
@@ -24,8 +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.internal.colorized
import ru.endlesscode.mimic.items.BukkitItemsRegistry
/**
@@ -37,7 +35,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()
@@ -68,13 +66,13 @@ 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
(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) }
@@ -83,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/Colors.kt b/mimic-bukkit/src/main/kotlin/internal/Colors.kt
index 1b3d0828..a0b75c86 100644
--- a/mimic-bukkit/src/main/kotlin/internal/Colors.kt
+++ b/mimic-bukkit/src/main/kotlin/internal/Colors.kt
@@ -17,12 +17,11 @@
* along with BukkitMimic. If not, see .
*/
+// Keep it for now
+@file:Suppress("DEPRECATION")
+
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/Compat.kt b/mimic-bukkit/src/main/kotlin/internal/Compat.kt
index c922d683..5df4b7ca 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,
@@ -10,7 +11,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 d9d68e85..95bb8d2b 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")
-internal fun FileConfigurationOptions.setHeader(vararg lines: String?) {
- callCompat(
- "FileConfigurationOptions.setHeader",
- block = { setHeader(lines.asList()) },
- compat = { header(lines.joinToString("\n")) },
- )
+internal fun FileConfigurationOptions.setHeader(vararg lines: String) {
+ setHeader(lines.asList())
}
internal fun Configuration.applyDefaults() {
@@ -18,9 +13,5 @@ internal fun Configuration.applyDefaults() {
}
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/Log.kt b/mimic-bukkit/src/main/kotlin/internal/Log.kt
index 799ed0ca..ca802406 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/NamespacedKey.kt b/mimic-bukkit/src/main/kotlin/internal/NamespacedKey.kt
index 094828e2..3eb6b5cb 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)
diff --git a/mimic-bukkit/src/main/kotlin/internal/Serializers.kt b/mimic-bukkit/src/main/kotlin/internal/Serializers.kt
index 98d107e1..922ea667 100644
--- a/mimic-bukkit/src/main/kotlin/internal/Serializers.kt
+++ b/mimic-bukkit/src/main/kotlin/internal/Serializers.kt
@@ -26,33 +26,62 @@ 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("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)
- ?: throw SerializationException("$value is not a valid key for enchantment, " +
- "must be one of: [${Enchantment.values().joinToString { it.key.toString() }}]")
+ ?: 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() }}]"
+ )
}
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()
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)
}
+
+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/main/kotlin/internal/TextComponent.kt b/mimic-bukkit/src/main/kotlin/internal/TextComponent.kt
index 519bb223..fe02c903 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,
@@ -15,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 26eab224..b707ab67 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
diff --git a/mimic-bukkit/src/main/resources/plugin.yml b/mimic-bukkit/src/main/resources/plugin.yml
deleted file mode 100644
index fe49753f..00000000
--- a/mimic-bukkit/src/main/resources/plugin.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-loadbefore:
- - SkillAPI
- - BattleLevels
- - CustomItems
- - MMOCore
- - MMOItems
- - Heroes
- - QuantumRPG
diff --git a/mimic-bukkit/src/test/kotlin/BukkitTestBase.kt b/mimic-bukkit/src/test/kotlin/BukkitTestBase.kt
index 393e26ea..7e81196e 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 9c13c259..7e686858 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/ItemMetaPayloadTest.kt b/mimic-bukkit/src/test/kotlin/impl/vanilla/ItemMetaPayloadTest.kt
index 7ce060cc..aabfeb9a 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,
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 cb7c4b82..00000000
--- 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
- }
-}