diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 148fdd2..6d0ee1c 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index eb82b3e..1b4f911 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -9,5 +9,5 @@ - + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9950b53..61476e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +### Changed +- **CommandAPI is no longer required** + ## 4.5.1 ### Changed diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8700506..e68ed92 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,8 @@ [versions] -kotlin = "1.9.24" +kotlin = "2.0.0" coroutines = "1.8.1" -jvmToolchain = "17" -paper = "1.20.4-R0.1-SNAPSHOT" -commandApi = "9.4.1" +jvmToolchain = "21" +paper = "1.20.6-R0.1-SNAPSHOT" dynmap = "3.5-SNAPSHOT" @@ -14,7 +13,6 @@ coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core" annotations = { group = "org.jetbrains", name = "annotations", version = "24.0.1" } paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" } -spigot = { group = "org.spigotmc", name = "spigot-api", version.ref = "paper" } # Required dependencies # (own) @@ -22,6 +20,7 @@ md5Commons = { group = "de.md5lukas", name = "md5-commons", version = "3.0.0-SNA kinvs = { group = "de.md5lukas", name = "kinvs", version = "1.1.0" } sqliteHelper = { group = "de.md5lukas", name = "sqlite-kotlin-helper", version = "1.2.2" } konfig = { group = "de.md5lukas", name = "spigot-konfig", version = "1.0.1" } +paperBrigadier = { group = "de.md5lukas.paper", name = "paper-brigadier", version = "1.0.0" } pathfinder = { group = "de.md5lukas", name = "pathfinder", version = "1.0.0-SNAPSHOT" } # (external) @@ -29,9 +28,6 @@ schedulers = { group = "de.md5lukas", name = "schedulers", version = "1.0.1" } skedule = { group = "de.md5lukas", name = "skedule", version = "2.0.0" } anvilGui = { group = "de.md5lukas", name = "anvilgui", version = "2.0.0-SNAPSHOT" } bStats = { group = "org.bstats", name = "bstats-bukkit", version = "3.0.2" } -commandapi-core = { group = "dev.jorel", name = "commandapi-bukkit-core", version.ref = "commandApi" } -commandapi-kotlin = { group = "dev.jorel", name = "commandapi-bukkit-kotlin", version.ref = "commandApi" } -brigadier = { group = "com.mojang", name = "brigadier", version = "1.1.8" } # Optional dependencies vaultApi = { group = "com.github.MilkBowl", name = "VaultAPI", version = "1.7.1" } @@ -67,6 +63,3 @@ minotaur = { id = "com.modrinth.minotaur", version = "2.+" } runPaper = { id = "xyz.jpenilla.run-paper", version = "2.+" } spotless = { id = "com.diffplug.spotless", version = "6.+" } changelog = { id = "org.jetbrains.changelog", version = "2.1.0" } - -[bundles] -commandApi = ["commandapi-core", "commandapi-kotlin", "brigadier"] diff --git a/pointers/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManager.kt b/pointers/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManager.kt index b72392c..463d619 100644 --- a/pointers/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManager.kt +++ b/pointers/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManager.kt @@ -200,7 +200,7 @@ class PointerManager( * @param player The player to load the enabled pointers for * @return The enabled pointers */ - fun loadEnabledPointers(player: Player): CompletableFuture> { + fun loadEnabledPointers(player: Player): CompletableFuture> { return CompletableFuture.completedFuture(emptyMap()) } diff --git a/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt b/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt index 87fb356..226d58d 100644 --- a/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt +++ b/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt @@ -1,7 +1,7 @@ package de.md5lukas.waypoints.util import de.md5lukas.commons.paper.editMeta -import java.net.URL +import java.net.URI import java.util.* import org.bukkit.Location import org.bukkit.Material @@ -46,7 +46,9 @@ fun createCustomPlayerHead(plugin: Plugin, textureId: String): ItemStack { val profile = plugin.server.createProfile(UUID.randomUUID(), "CUSTOM_HEAD") profile.setTextures( - profile.textures.also { it.skin = URL("https://textures.minecraft.net/texture/$textureId") }) + profile.textures.also { + it.skin = URI.create("https://textures.minecraft.net/texture/$textureId").toURL() + }) val stack = ItemStack(Material.PLAYER_HEAD) stack.editMeta { playerProfile = profile } diff --git a/waypoints/build.gradle.kts b/waypoints/build.gradle.kts index 14a6af6..5bba26c 100644 --- a/waypoints/build.gradle.kts +++ b/waypoints/build.gradle.kts @@ -41,13 +41,13 @@ dependencies { implementation(libs.md5Commons) implementation(libs.kinvs) implementation(libs.konfig) + implementation(libs.paperBrigadier) { this.isChanging = true } // Required dependencies implementation(libs.schedulers) implementation(libs.skedule) implementation(libs.anvilGui) implementation(libs.bStats) - implementation(libs.bundles.commandApi) // Optional dependencies implementation(libs.vaultApi) @@ -64,6 +64,13 @@ dependencies { testRuntimeOnly(libs.junitLauncher) } +configurations.all { + resolutionStrategy { + cacheChangingModulesFor(10, TimeUnit.MINUTES) + cacheDynamicVersionsFor(10, TimeUnit.MINUTES) + } +} + tasks { register("createResourceIndex") @@ -73,8 +80,7 @@ tasks { val properties = mapOf( "version" to project.version, - "apiVersion" to - libs.versions.paper.get().substringBefore('-').split('.').take(2).joinToString("."), + "apiVersion" to libs.versions.paper.get().substringBefore('-'), "kotlinVersion" to libs.versions.kotlin.get(), "coroutinesVersion" to libs.versions.coroutines.get(), ) @@ -114,6 +120,7 @@ tasks { include(dependency(libs.md5Commons.get())) include(dependency(libs.kinvs.get())) include(dependency(libs.konfig.get())) + include(dependency(libs.paperBrigadier.get())) include(dependency(libs.schedulers.get())) include(dependency(libs.skedule.get())) @@ -121,8 +128,8 @@ tasks { include(dependency("org.bstats::")) } - arrayOf("commons", "kinvs", "konfig", "schedulers", "signgui").forEach { - relocate("de.md5lukas.$it", "de.md5lukas.waypoints.libs.$it") + arrayOf("commons", "kinvs", "konfig", "schedulers", "signgui", "paper.brigadier").forEach { + relocate("de.md5lukas.$it", "de.md5lukas.waypoints.libs.${it.substringAfterLast('.')}") } arrayOf("com.okkero.skedule", "net.wesjd.anvilgui", "org.bstats").forEach { relocate(it, "de.md5lukas.waypoints.libs.${it.substringAfterLast('.')}") @@ -136,8 +143,8 @@ tasks { minecraftVersion(libs.versions.paper.get().substringBefore('-')) downloadPlugins { - modrinth("commandapi", libs.versions.commandApi.get()) - github("dmulloy2", "ProtocolLib", "5.2.0", "ProtocolLib.jar") + url( + "https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar") } } @@ -159,7 +166,7 @@ modrinth { versionType = "release" uploadFile.set(tasks.shadowJar) - gameVersions.addAll("1.20.2", "1.20.4", "1.20.6") + gameVersions.addAll(libs.versions.paper.get().substringBefore('-')) loaders.addAll("paper", "folia") syncBodyFrom = provider { rootProject.file("README.md").readText() } @@ -169,7 +176,6 @@ modrinth { } dependencies { - with(required) { project("commandapi") } with(optional) { project("pl3xmap") project("bluemap") diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/WaypointsPlugin.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/WaypointsPlugin.kt index 7f985ff..90cb268 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/WaypointsPlugin.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/WaypointsPlugin.kt @@ -34,6 +34,7 @@ import de.md5lukas.waypoints.tasks.CleanDatabaseTask import de.md5lukas.waypoints.util.APIExtensions import de.md5lukas.waypoints.util.TeleportManager import de.md5lukas.waypoints.util.UpdateChecker +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents import java.io.File import java.util.concurrent.TimeUnit import java.util.logging.Level @@ -222,9 +223,16 @@ class WaypointsPlugin : JavaPlugin() { } } + @Suppress("UnstableApiUsage") private fun registerCommands() { - WaypointsCommand(this).register() - WaypointsScriptCommand(this).register() + lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS) { + val registrar = it.registrar() + registrar.register( + WaypointsCommand(this).buildCommand(), waypointsConfig.general.commands.waypointsAliases) + registrar.register( + WaypointsScriptCommand(this).buildCommand(), + waypointsConfig.general.commands.waypointsScriptAliases) + } } private fun registerEvents() { diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsCommand.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsCommand.kt index ef7e55a..29b6f06 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsCommand.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsCommand.kt @@ -1,10 +1,16 @@ package de.md5lukas.waypoints.command +import com.mojang.brigadier.tree.LiteralCommandNode import com.okkero.skedule.skedule import de.md5lukas.commons.paper.isOutOfBounds import de.md5lukas.commons.paper.placeholder +import de.md5lukas.paper.brigadier.arguments.* +import de.md5lukas.paper.brigadier.executors.* +import de.md5lukas.paper.brigadier.requirements.* +import de.md5lukas.paper.brigadier.suggestions.SuggestionProviders import de.md5lukas.waypoints.WaypointsPermissions import de.md5lukas.waypoints.WaypointsPlugin +import de.md5lukas.waypoints.command.arguments.WaypointsSuggestionProvider import de.md5lukas.waypoints.gui.WaypointsGUI import de.md5lukas.waypoints.pointers.TemporaryWaypointTrackable import de.md5lukas.waypoints.pointers.WaypointTrackable @@ -14,12 +20,10 @@ import de.md5lukas.waypoints.util.createWaypointPublic import de.md5lukas.waypoints.util.humanReadableByteCountBin import de.md5lukas.waypoints.util.labelResolver import de.md5lukas.waypoints.util.searchWaypoint -import dev.jorel.commandapi.arguments.GreedyStringArgument -import dev.jorel.commandapi.arguments.LocationType -import dev.jorel.commandapi.kotlindsl.* +import io.papermc.paper.command.brigadier.CommandSourceStack import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder import org.bukkit.Location -import org.bukkit.OfflinePlayer +import org.bukkit.command.CommandSender import org.bukkit.entity.Player class WaypointsCommand(private val plugin: WaypointsPlugin) { @@ -27,225 +31,220 @@ class WaypointsCommand(private val plugin: WaypointsPlugin) { private val translations get() = plugin.translations - fun register() { - commandTree("waypoints") { - withPermission(WaypointsPermissions.COMMAND_PERMISSION) - withAliases(*plugin.waypointsConfig.general.commands.waypointsAliases.toTypedArray()) - playerExecutor { player, _ -> WaypointsGUI(plugin, player, player.uniqueId) } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } - literalArgument("help") { - anyExecutor { sender, args -> - val labelResolver = args.labelResolver - translations.COMMAND_HELP_HEADER.send(sender) + @Suppress("UnstableApiUsage") + fun buildCommand(): LiteralCommandNode = + command("waypoints") { + requiresPermission(WaypointsPermissions.COMMAND_PERMISSION) + executes { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } + executes { player, _ -> WaypointsGUI(plugin, player, player.uniqueId) } + literal("help") { + executes { sender, context -> + val labelResolver = context.labelResolver + translations.COMMAND_HELP_HEADER.send(sender) - if (sender is Player) translations.COMMAND_HELP_GUI.send(sender, labelResolver) + if (sender is Player) translations.COMMAND_HELP_GUI.send(sender, labelResolver) - translations.COMMAND_HELP_HELP.send(sender, labelResolver) + translations.COMMAND_HELP_HELP.send(sender, labelResolver) - if (sender is Player) { - translations.COMMAND_HELP_SELECT.send(sender, labelResolver) - translations.COMMAND_HELP_DESELECT.send(sender, labelResolver) - translations.COMMAND_HELP_TELEPORT.send(sender, labelResolver) - if (sender.hasPermission(WaypointsPermissions.MODIFY_PRIVATE)) { - translations.COMMAND_HELP_SET_PRIVATE.send(sender, labelResolver) - } - if (plugin.waypointsConfig.general.features.globalWaypoints) { - if (sender.hasPermission(WaypointsPermissions.MODIFY_PUBLIC)) { - translations.COMMAND_HELP_SET_PUBLIC.send(sender, labelResolver) + if (sender is Player) { + translations.COMMAND_HELP_SELECT.send(sender, labelResolver) + translations.COMMAND_HELP_DESELECT.send(sender, labelResolver) + translations.COMMAND_HELP_TELEPORT.send(sender, labelResolver) + if (sender.hasPermission(WaypointsPermissions.MODIFY_PRIVATE)) { + translations.COMMAND_HELP_SET_PRIVATE.send(sender, labelResolver) + } + if (plugin.waypointsConfig.general.features.globalWaypoints) { + if (sender.hasPermission(WaypointsPermissions.MODIFY_PUBLIC)) { + translations.COMMAND_HELP_SET_PUBLIC.send(sender, labelResolver) + } + if (sender.hasPermission(WaypointsPermissions.MODIFY_PERMISSION)) { + translations.COMMAND_HELP_SET_PERMISSION.send(sender, labelResolver) + } + } + if (sender.hasPermission(WaypointsPermissions.TEMPORARY_WAYPOINT)) { + translations.COMMAND_HELP_SET_TEMPORARY.send(sender, labelResolver) } - if (sender.hasPermission(WaypointsPermissions.MODIFY_PERMISSION)) { - translations.COMMAND_HELP_SET_PERMISSION.send(sender, labelResolver) + if (sender.hasPermission(WaypointsPermissions.COMMAND_OTHER)) { + translations.COMMAND_HELP_OTHER.send(sender, labelResolver) } } - if (sender.hasPermission(WaypointsPermissions.TEMPORARY_WAYPOINT)) { - translations.COMMAND_HELP_SET_TEMPORARY.send(sender, labelResolver) + if (sender.hasPermission(WaypointsPermissions.COMMAND_STATISTICS)) { + translations.COMMAND_HELP_STATISTICS.send(sender, labelResolver) } - if (sender.hasPermission(WaypointsPermissions.COMMAND_OTHER)) { - translations.COMMAND_HELP_OTHER.send(sender, labelResolver) + if (sender.hasPermission(WaypointsPermissions.COMMAND_RELOAD)) { + translations.COMMAND_HELP_RELOAD.send(sender, labelResolver) } } - if (sender.hasPermission(WaypointsPermissions.COMMAND_STATISTICS)) { - translations.COMMAND_HELP_STATISTICS.send(sender, labelResolver) - } - if (sender.hasPermission(WaypointsPermissions.COMMAND_RELOAD)) { - translations.COMMAND_HELP_RELOAD.send(sender, labelResolver) - } } - } - literalArgument("select") { - argument( - GreedyStringArgument("name") - .replaceSuggestions( - WaypointsArgumentSuggestions(plugin, textMode = false, allowGlobals = true))) { - playerExecutor { player, args -> - plugin.skedule(player) { - val waypoint = searchWaypoint(plugin, player, args["name"] as String, true) - if (waypoint == null) { - translations.COMMAND_SEARCH_NOT_FOUND_WAYPOINT.send(player) - } else { - plugin.pointerManager.enable(player, WaypointTrackable(plugin, waypoint)) - translations.COMMAND_SELECT_SELECTED.send( - player, Placeholder.unparsed("name", waypoint.name)) - player.playSound(plugin.waypointsConfig.sounds.waypointSelected) - } + literal("select") { + requiresPlayer() + greedyString("name") { + suggests(WaypointsSuggestionProvider(plugin, textMode = false, allowGlobals = true)) + executes { player, context -> + plugin.skedule(player) { + val waypoint = searchWaypoint(plugin, player, context["name"], true) + if (waypoint == null) { + translations.COMMAND_SEARCH_NOT_FOUND_WAYPOINT.send(player) + } else { + plugin.pointerManager.enable(player, WaypointTrackable(plugin, waypoint)) + translations.COMMAND_SELECT_SELECTED.send( + player, Placeholder.unparsed("name", waypoint.name)) + player.playSound(plugin.waypointsConfig.sounds.waypointSelected) } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } } - } - literalArgument("deselectAll") { - playerExecutor { player, _ -> - plugin.pointerManager.disable(player) { true } - translations.COMMAND_DESELECT_DONE.send(player) + } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } - } - if (plugin.waypointsConfig.general.features.teleportation) { - literalArgument("teleport") { - argument( - GreedyStringArgument("name") - .replaceSuggestions( - WaypointsArgumentSuggestions(plugin, textMode = false, allowGlobals = true) { - sender, - waypoint -> - if (sender !is Player) { - false - } else { - plugin.teleportManager.isAllowedToTeleportToWaypoint(sender, waypoint) - } - })) { - playerExecutor { player, args -> - plugin.skedule(player) { - val waypoint = searchWaypoint(plugin, player, args["name"] as String, true) - if (waypoint == null) { - translations.COMMAND_SEARCH_NOT_FOUND_WAYPOINT.send(player) - } else if (plugin.teleportManager.isAllowedToTeleportToWaypoint( - player, waypoint)) { - plugin.teleportManager.teleportPlayerToWaypoint(player, waypoint) - } else { - translations.MESSAGE_TELEPORT_NOT_ALLOWED.send(player) - } - } + literal("deselectAll") { + requiresPlayer() + executes { player, _ -> + plugin.pointerManager.disable(player) { true } + translations.COMMAND_DESELECT_DONE.send(player) + } + } + literal("teleport") { + requires { plugin.waypointsConfig.general.features.teleportation } + requiresPlayer() + greedyString("name") { + suggests( + WaypointsSuggestionProvider(plugin, textMode = false, allowGlobals = true) { + sender, + waypoint -> + plugin.teleportManager.isAllowedToTeleportToWaypoint(sender as Player, waypoint) + }) + executes { player, context -> + plugin.skedule(player) { + val waypoint = searchWaypoint(plugin, player, context["name"], true) + if (waypoint == null) { + translations.COMMAND_SEARCH_NOT_FOUND_WAYPOINT.send(player) + } else if (plugin.teleportManager.isAllowedToTeleportToWaypoint(player, waypoint)) { + plugin.teleportManager.teleportPlayerToWaypoint(player, waypoint) + } else { + translations.MESSAGE_TELEPORT_NOT_ALLOWED.send(player) } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } } + } + } } - } - literalArgument("set") { - withPermission(WaypointsPermissions.MODIFY_PRIVATE) - greedyStringArgument("name") { - playerExecutor { player, args -> - val name = args["name"] as String - - plugin.skedule(player) { createWaypointPrivate(plugin, player, name) } + literal("set") { + requiresPlayer() + requiresPermission(WaypointsPermissions.MODIFY_PRIVATE) + greedyString("name") { + executes { player, context -> + plugin.skedule(player) { createWaypointPrivate(plugin, player, context["name"]) } + } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } } - } - if (plugin.waypointsConfig.general.features.globalWaypoints) { - literalArgument("setPublic") { - withRequirement { + literal("setPublic") { + requires { plugin.waypointsConfig.general.features.globalWaypoints } + requiresPlayer() + andRequires { + val sender = it.sender + plugin.waypointsConfig.general.features.publicOwnershipWaypoints || - it.hasPermission(WaypointsPermissions.MODIFY_PUBLIC) + sender.hasPermission(WaypointsPermissions.MODIFY_PUBLIC) } - greedyStringArgument("name") { - playerExecutor { player, args -> - val name = args["name"] as String - - plugin.skedule(player) { createWaypointPublic(plugin, player, name) } + greedyString("name") { + executes { player, context -> + plugin.skedule(player) { createWaypointPublic(plugin, player, context["name"]) } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } } } - literalArgument("setPermission") { - withPermission(WaypointsPermissions.MODIFY_PERMISSION) - stringArgument("permission") { - greedyStringArgument("name") { - playerExecutor { player, args -> - val permission = args["permission"] as String - val name = args["name"] as String - + literal("setPermission") { + requires { plugin.waypointsConfig.general.features.globalWaypoints } + requiresPlayer() + requiresPermission(WaypointsPermissions.MODIFY_PERMISSION) + word("permission") { + greedyString("name") { + executes { player, context -> plugin.skedule(player) { - createWaypointPermission(plugin, player, name, permission) + createWaypointPermission(plugin, player, context["name"], context["permission"]) } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } } } } - } - literalArgument("setTemporary") { - withPermission(WaypointsPermissions.TEMPORARY_WAYPOINT) - locationArgument("target", LocationType.BLOCK_POSITION) { - entitySelectorArgumentManyPlayers("players", optional = true) { - withPermission(WaypointsPermissions.TEMPORARY_WAYPOINT_OTHERS) - playerExecutor { player, args -> - val location = args["target"] as Location - @Suppress("UNCHECKED_CAST") - val players = args["players"] as? Collection ?: listOf(player) - - if (location.isOutOfBounds) { - translations.WAYPOINT_CREATE_COORDINATES_OUT_OF_BOUNDS.send(player) - } else { - plugin.skedule { - players.forEach { - if (it == player || - plugin.api.getWaypointPlayer(it.uniqueId).canReceiveTemporaryWaypoints) { - plugin.pointerManager.enable(it, TemporaryWaypointTrackable(plugin, location)) - } else { - translations.MESSAGE_TEMPORARY_WAYPOINTS_BLOCKED.send( - player, "name" placeholder it.displayName()) - } - } - } + literal("setTemporary") { + requiresPlayer() + requiresPermission(WaypointsPermissions.TEMPORARY_WAYPOINT) + blockPosition("target") { + players("players") { + requiresPermission(WaypointsPermissions.TEMPORARY_WAYPOINT_OTHERS) + executes { player, context -> + setTemporary( + player, + context.getBlockPosition("target").toLocation(player.world), + context.getPlayers("players")) } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } + executes { player, context -> + setTemporary( + player, + context.getBlockPosition("target").toLocation(player.world), + listOf(player)) + } } } - } - literalArgument("other") { - withPermission(WaypointsPermissions.COMMAND_OTHER) - offlinePlayerArgument("target") { - playerExecutor { player, args -> - val otherUUID = (args["target"] as OfflinePlayer).uniqueId + literal("other") { + requiresPlayer() + requiresPermission(WaypointsPermissions.COMMAND_OTHER) + playerProfiles("target") { + suggests(SuggestionProviders.onlinePlayers(false)) + executes { player, context -> + val otherUUID = context.getPlayerProfiles("target").first().id!! - plugin.skedule(player) { - if (!plugin.api.waypointsPlayerExists(otherUUID)) { - translations.COMMAND_OTHER_PLAYER_NO_WAYPOINTS.send(player) - } else { - WaypointsGUI(plugin, player, otherUUID) + plugin.skedule(player) { + if (plugin.api.waypointsPlayerExists(otherUUID)) { + WaypointsGUI(plugin, player, otherUUID) + } else { + translations.COMMAND_OTHER_PLAYER_NO_WAYPOINTS.send(player) + } } } } - anyExecutor { sender, _ -> translations.COMMAND_NOT_A_PLAYER.send(sender) } } - } - literalArgument("statistics") { - withPermission(WaypointsPermissions.COMMAND_STATISTICS) - anyExecutor { sender, _ -> - with(plugin.api.statistics) { - translations.COMMAND_STATISTICS_MESSAGE.send( - sender, - "db_file_size" placeholder databaseSize.humanReadableByteCountBin(), - "total_waypoints" placeholder totalWaypoints, - "private_waypoints" placeholder privateWaypoints, - "death_waypoints" placeholder deathWaypoints, - "public_waypoints" placeholder publicWaypoints, - "permission_waypoints" placeholder permissionWaypoints, - "total_folders" placeholder totalFolders, - "private_folders" placeholder privateFolders, - "public_folders" placeholder publicFolders, - "permission_folders" placeholder permissionFolders, - ) + literal("statistics") { + requiresPermission(WaypointsPermissions.COMMAND_STATISTICS) + executes { sender, _ -> + with(plugin.api.statistics) { + translations.COMMAND_STATISTICS_MESSAGE.send( + sender, + "db_file_size" placeholder databaseSize.humanReadableByteCountBin(), + "total_waypoints" placeholder totalWaypoints, + "private_waypoints" placeholder privateWaypoints, + "death_waypoints" placeholder deathWaypoints, + "public_waypoints" placeholder publicWaypoints, + "permission_waypoints" placeholder permissionWaypoints, + "total_folders" placeholder totalFolders, + "private_folders" placeholder privateFolders, + "public_folders" placeholder publicFolders, + "permission_folders" placeholder permissionFolders, + ) + } + } + } + literal("reload") { + requiresPermission(WaypointsPermissions.COMMAND_RELOAD) + executes { sender, _ -> + plugin.reloadConfiguration() + translations.COMMAND_RELOAD_FINISHED.send(sender) } } } - literalArgument("reload") { - withPermission(WaypointsPermissions.COMMAND_RELOAD) - anyExecutor { sender, _ -> - plugin.reloadConfiguration() - translations.COMMAND_RELOAD_FINISHED.send(sender) + + private fun setTemporary(player: Player, location: Location, players: Collection) { + if (location.isOutOfBounds) { + translations.WAYPOINT_CREATE_COORDINATES_OUT_OF_BOUNDS.send(player) + } else { + plugin.skedule { + players.forEach { + if (it == player || + plugin.api.getWaypointPlayer(it.uniqueId).canReceiveTemporaryWaypoints) { + plugin.pointerManager.enable(it, TemporaryWaypointTrackable(plugin, location)) + } else { + translations.MESSAGE_TEMPORARY_WAYPOINTS_BLOCKED.send( + player, "name" placeholder it.displayName()) + } } } } diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsScriptCommand.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsScriptCommand.kt index 7a4b1d1..751f373 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsScriptCommand.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsScriptCommand.kt @@ -1,139 +1,137 @@ package de.md5lukas.waypoints.command +import com.mojang.brigadier.tree.LiteralCommandNode import com.okkero.skedule.skedule import de.md5lukas.commons.paper.isOutOfBounds import de.md5lukas.commons.paper.placeholder +import de.md5lukas.paper.brigadier.arguments.* +import de.md5lukas.paper.brigadier.executors.* +import de.md5lukas.paper.brigadier.requirements.* import de.md5lukas.waypoints.WaypointsPermissions import de.md5lukas.waypoints.WaypointsPlugin +import de.md5lukas.waypoints.command.arguments.BeaconColorArgument +import de.md5lukas.waypoints.command.arguments.WaypointsSuggestionProvider import de.md5lukas.waypoints.pointers.BeaconColor import de.md5lukas.waypoints.pointers.TemporaryWaypointTrackable import de.md5lukas.waypoints.pointers.WaypointTrackable import de.md5lukas.waypoints.util.labelResolver import de.md5lukas.waypoints.util.searchWaypoints -import dev.jorel.commandapi.arguments.ArgumentSuggestions -import dev.jorel.commandapi.arguments.GreedyStringArgument -import dev.jorel.commandapi.arguments.LocationType -import dev.jorel.commandapi.arguments.StringArgument -import dev.jorel.commandapi.kotlindsl.anyExecutor -import dev.jorel.commandapi.kotlindsl.argument -import dev.jorel.commandapi.kotlindsl.commandTree -import dev.jorel.commandapi.kotlindsl.literalArgument -import dev.jorel.commandapi.kotlindsl.locationArgument -import dev.jorel.commandapi.kotlindsl.optionalArgument -import dev.jorel.commandapi.kotlindsl.playerArgument -import dev.jorel.commandapi.kotlindsl.uuidArgument +import io.papermc.paper.command.brigadier.CommandSourceStack import java.util.UUID import net.kyori.adventure.text.event.ClickEvent import org.bukkit.Location +import org.bukkit.command.CommandSender import org.bukkit.entity.Player +@Suppress("UnstableApiUsage") class WaypointsScriptCommand(private val plugin: WaypointsPlugin) { private val translations get() = plugin.translations - fun register() { - commandTree("waypointsscript") { - withPermission(WaypointsPermissions.COMMAND_SCRIPTING) - withAliases(*plugin.waypointsConfig.general.commands.waypointsScriptAliases.toTypedArray()) - anyExecutor { sender, args -> - val labelResolver = args.labelResolver - translations.COMMAND_SCRIPT_HELP_HEADER.send(sender) - translations.COMMAND_SCRIPT_HELP_DESELECT_WAYPOINT.send(sender, labelResolver) - translations.COMMAND_SCRIPT_HELP_SELECT_WAYPOINT.send(sender, labelResolver) - translations.COMMAND_SCRIPT_HELP_TEMPORARY_WAYPOINT.send(sender, labelResolver) - translations.COMMAND_SCRIPT_HELP_UUID.send(sender, labelResolver) - } - literalArgument("deselectWaypoint") { - playerArgument("player") { - anyExecutor { _, args -> - val player = args["player"] as Player + fun buildCommand(): LiteralCommandNode = + command("waypointsscript") { + requiresPermission(WaypointsPermissions.COMMAND_SCRIPTING) + executes { sender, context -> + val labelResolver = context.labelResolver + translations.COMMAND_SCRIPT_HELP_HEADER.send(sender) + translations.COMMAND_SCRIPT_HELP_DESELECT_WAYPOINT.send(sender, labelResolver) + translations.COMMAND_SCRIPT_HELP_SELECT_WAYPOINT.send(sender, labelResolver) + translations.COMMAND_SCRIPT_HELP_TEMPORARY_WAYPOINT.send(sender, labelResolver) + translations.COMMAND_SCRIPT_HELP_UUID.send(sender, labelResolver) + } + literal("deselectWaypoint") { + player("player") { + executes { _, context -> + val player = context.getPlayer("player") - plugin.pointerManager.disable(player) { true } + plugin.pointerManager.disable(player) { true } + } } } - } - literalArgument("selectWaypoint") { - playerArgument("player") { - uuidArgument("waypoint-id") { - anyExecutor { sender, args -> - val player = args["player"] as Player - val uuid = args["waypoint-id"] as UUID + literal("selectWaypoint") { + player("player") { + uuid("waypoint-id") { + executes { sender, context -> + val player = context.getPlayer("player") + val uuid: UUID = context["waypoint-id"] - plugin.skedule(player) { - val waypoint = plugin.api.getWaypointByID(uuid) + plugin.skedule(player) { + val waypoint = plugin.api.getWaypointByID(uuid) - if (waypoint == null) { - translations.COMMAND_SCRIPT_SELECT_WAYPOINT_WAYPOINT_NOT_FOUND.send( - sender, "uuid" placeholder uuid.toString()) - return@skedule - } + if (waypoint == null) { + translations.COMMAND_SCRIPT_SELECT_WAYPOINT_WAYPOINT_NOT_FOUND.send( + sender, "uuid" placeholder uuid.toString()) + return@skedule + } - plugin.pointerManager.enable(player, WaypointTrackable(plugin, waypoint)) + plugin.pointerManager.enable(player, WaypointTrackable(plugin, waypoint)) + } } } } } - } - literalArgument("temporaryWaypoint") { - playerArgument("player") { - locationArgument("target", LocationType.BLOCK_POSITION) { - optionalArgument( - StringArgument("beacon-color") - .replaceSuggestions( - ArgumentSuggestions.strings( - BeaconColor.entries.map { it.name }.toList()))) { - anyExecutor { sender, args -> - val player = args["player"] as Player - val target = args["target"] as Location - val beaconColorString = args["beacon-color"] as String? - - val beaconColor = - BeaconColor.entries.firstOrNull { it.name.equals(beaconColorString, true) } - if (beaconColorString !== null && beaconColor === null) { - translations.COMMAND_SCRIPT_TEMPORARY_WAYPOINT_BEACON_COLOR_NOT_FOUND.send( - sender) - return@anyExecutor - } - - if (target.isOutOfBounds) { - translations.WAYPOINT_CREATE_COORDINATES_OUT_OF_BOUNDS.send(sender) - } else { - plugin.pointerManager.enable( - player, TemporaryWaypointTrackable(plugin, target, beaconColor)) - } - } + literal("temporaryWaypoint") { + player("player") { + blockPosition("target") { + argument("beacon-color", BeaconColorArgument(plugin)) { + executes { sender, context -> + val player = context.getPlayer("player") + temporaryWaypoint( + sender, + player, + context.getBlockPosition("target").toLocation(player.world), + context["beacon-color"]) } + } + executes { sender, context -> + val player = context.getPlayer("player") + temporaryWaypoint( + sender, + player, + context.getBlockPosition("target").toLocation(player.world), + null) + } + } } } - } - literalArgument("uuid") { - argument( - GreedyStringArgument("query") - .replaceSuggestions( - WaypointsArgumentSuggestions(plugin, textMode = false, allowGlobals = true))) { - anyExecutor { sender, args -> - plugin.skedule { - val result = searchWaypoints(plugin, sender, args["query"] as String, true) - if (result.isEmpty()) { - translations.COMMAND_SCRIPT_UUID_NO_MATCH.send(sender) - } else { - translations.COMMAND_SCRIPT_UUID_HEADER.send(sender) - result.forEach { - sender.sendMessage( - translations.COMMAND_SCRIPT_UUID_RESULT.withReplacements( - "name" placeholder it.name, - "folder" placeholder (it.getFolder()?.name ?: "null"), - ) - .clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.COPY_TO_CLIPBOARD, it.id.toString()))) - } + literal("uuid") { + greedyString("query") { + suggests(WaypointsSuggestionProvider(plugin, textMode = false, allowGlobals = true)) + executes { sender, context -> + plugin.skedule { + val result = searchWaypoints(plugin, sender, context["query"], true) + if (result.isEmpty()) { + translations.COMMAND_SCRIPT_UUID_NO_MATCH.send(sender) + } else { + translations.COMMAND_SCRIPT_UUID_HEADER.send(sender) + result.forEach { + sender.sendMessage( + translations.COMMAND_SCRIPT_UUID_RESULT.withReplacements( + "name" placeholder it.name, + "folder" placeholder (it.getFolder()?.name ?: "null"), + ) + .clickEvent( + ClickEvent.clickEvent( + ClickEvent.Action.COPY_TO_CLIPBOARD, it.id.toString()))) } } } } + } + } } + + private fun temporaryWaypoint( + sender: CommandSender, + player: Player, + target: Location, + beaconColor: BeaconColor? + ) { + if (target.isOutOfBounds) { + translations.WAYPOINT_CREATE_COORDINATES_OUT_OF_BOUNDS.send(sender) + } else { + plugin.pointerManager.enable(player, TemporaryWaypointTrackable(plugin, target, beaconColor)) } } } diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/arguments/BeaconColorArgument.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/arguments/BeaconColorArgument.kt new file mode 100644 index 0000000..d84af40 --- /dev/null +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/arguments/BeaconColorArgument.kt @@ -0,0 +1,51 @@ +package de.md5lukas.waypoints.command.arguments + +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.arguments.StringArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import de.md5lukas.waypoints.WaypointsPlugin +import de.md5lukas.waypoints.pointers.BeaconColor +import io.papermc.paper.command.brigadier.MessageComponentSerializer +import io.papermc.paper.command.brigadier.argument.CustomArgumentType +import java.util.concurrent.CompletableFuture + +@Suppress("UnstableApiUsage") +class BeaconColorArgument(private val plugin: WaypointsPlugin) : + CustomArgumentType.Converted { + + private val unknownBeaconColor + get() = + SimpleCommandExceptionType( + MessageComponentSerializer.message() + .serialize( + plugin.translations.COMMAND_SCRIPT_TEMPORARY_WAYPOINT_BEACON_COLOR_NOT_FOUND + .text)) + + override fun convert(string: String): BeaconColor { + BeaconColor.entries.forEach { + if (it.name.equals(string, ignoreCase = true)) { + return it + } + } + throw unknownBeaconColor.create() + } + + private val nativeType = StringArgumentType.word()!! + + override fun getNativeType(): ArgumentType = nativeType + + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder + ): CompletableFuture { + BeaconColor.entries.forEach { + if (it.name.startsWith(builder.remaining, ignoreCase = true)) { + builder.suggest(it.name) + } + } + return builder.buildFuture() + } +} diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsArgumentSuggestions.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/arguments/WaypointsSuggestionProvider.kt similarity index 74% rename from waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsArgumentSuggestions.kt rename to waypoints/src/main/kotlin/de/md5lukas/waypoints/command/arguments/WaypointsSuggestionProvider.kt index d734444..e1b27e0 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/WaypointsArgumentSuggestions.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/command/arguments/WaypointsSuggestionProvider.kt @@ -1,37 +1,39 @@ -package de.md5lukas.waypoints.command +package de.md5lukas.waypoints.command.arguments import com.mojang.brigadier.Message +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.suggestion.SuggestionProvider import com.mojang.brigadier.suggestion.Suggestions import com.mojang.brigadier.suggestion.SuggestionsBuilder import com.okkero.skedule.future import de.md5lukas.commons.containsNonWordCharacter import de.md5lukas.waypoints.WaypointsPlugin import de.md5lukas.waypoints.api.Waypoint -import dev.jorel.commandapi.BukkitTooltip -import dev.jorel.commandapi.SuggestionInfo -import dev.jorel.commandapi.arguments.ArgumentSuggestions +import io.papermc.paper.command.brigadier.CommandSourceStack +import io.papermc.paper.command.brigadier.MessageComponentSerializer import java.util.concurrent.CompletableFuture import org.bukkit.command.CommandSender import org.bukkit.entity.Player -class WaypointsArgumentSuggestions( +@Suppress("UnstableApiUsage") +class WaypointsSuggestionProvider( private val plugin: WaypointsPlugin, private val textMode: Boolean, private val allowGlobals: Boolean, private val filter: (suspend (CommandSender, Waypoint) -> Boolean)? = null, -) : ArgumentSuggestions { +) : SuggestionProvider { - override fun suggest( - info: SuggestionInfo, - builder: SuggestionsBuilder, + override fun getSuggestions( + context: CommandContext, + builder: SuggestionsBuilder ): CompletableFuture { - val sender = info.sender + val sender = (context.source as CommandSourceStack).sender return plugin.future { val query = if (textMode) { - info.currentArg.removePrefix("\"").removeSuffix("\"") - } else info.currentArg + builder.remaining.removePrefix("\"").removeSuffix("\"") + } else builder.remaining if (allowGlobals) { val publicPrefix = plugin.translations.COMMAND_SEARCH_PREFIX_PUBLIC.rawText + "/" @@ -79,9 +81,10 @@ class WaypointsArgumentSuggestions( private fun Waypoint.getTooltip(sender: CommandSender): Message = plugin.apiExtensions.run { - BukkitTooltip.messageFromAdventureComponent( - plugin.translations.COMMAND_SEARCH_TOOLTIP.withReplacements( - *getResolvers(sender as? Player))) + MessageComponentSerializer.message() + .serialize( + plugin.translations.COMMAND_SEARCH_TOOLTIP.withReplacements( + *getResolvers(sender as? Player))) } private suspend fun shouldDiscard(sender: CommandSender, waypoint: Waypoint) = diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/pointers/TrailConfigurationImpl.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/pointers/TrailConfigurationImpl.kt index 252c435..bf2ff44 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/pointers/TrailConfigurationImpl.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/pointers/TrailConfigurationImpl.kt @@ -59,11 +59,11 @@ class TrailConfigurationImpl : RepeatingPointerConfigurationImpl(), TrailConfigu private set @ConfigPath("particle.normal") - override var particleNormal: Particle = Particle.VILLAGER_HAPPY + override var particleNormal: Particle = Particle.WAX_ON private set @ConfigPath("particle.highlight") - override var particleHighlight: Particle = Particle.FLAME + override var particleHighlight: Particle = Particle.WAX_OFF private set override var highlightDistance: Int = 0 diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/events/WaypointsListener.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/events/WaypointsListener.kt index 8deb3f9..2f6b35f 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/events/WaypointsListener.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/events/WaypointsListener.kt @@ -4,6 +4,7 @@ import com.okkero.skedule.skedule import de.md5lukas.waypoints.WaypointsPlugin import de.md5lukas.waypoints.gui.WaypointsGUI import de.md5lukas.waypoints.util.checkWorldAvailability +import org.bukkit.entity.Player import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.entity.PlayerDeathEvent @@ -33,4 +34,9 @@ class WaypointsListener(private val plugin: WaypointsPlugin) : Listener { WaypointsGUI(plugin, e.player, e.player.uniqueId) } } + + @EventHandler + fun onConfigReload(e: ConfigReloadEvent) { + plugin.server.onlinePlayers.forEach(Player::updateCommands) + } } diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManagerHooks.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManagerHooks.kt index 994e08c..3c5c5c9 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManagerHooks.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/PointerManagerHooks.kt @@ -45,7 +45,7 @@ class PointerManagerHooks(private val plugin: WaypointsPlugin) : Hooks { -> PointerVariant.entries.firstOrNull { it.key == storedKey }?.let { result[it] = value } } - result as Map + result } private inner class ActionBarPointerHooks : Hooks.ActionBar { diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/Brigadier.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/Brigadier.kt new file mode 100644 index 0000000..fed9a3a --- /dev/null +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/Brigadier.kt @@ -0,0 +1,8 @@ +package de.md5lukas.waypoints.util + +import com.mojang.brigadier.context.CommandContext +import de.md5lukas.commons.paper.placeholder +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver + +val CommandContext<*>.labelResolver: TagResolver + get() = "label" placeholder input.substringBefore(' ').removePrefix("/") diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/CommandAPI.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/CommandAPI.kt deleted file mode 100644 index 2a1ffc2..0000000 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/CommandAPI.kt +++ /dev/null @@ -1,8 +0,0 @@ -package de.md5lukas.waypoints.util - -import de.md5lukas.commons.paper.placeholder -import dev.jorel.commandapi.executors.CommandArguments -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver - -val CommandArguments.labelResolver: TagResolver - get() = "label" placeholder fullInput().substringBefore(' ').removePrefix("/") diff --git a/waypoints/src/main/resources/plugin.yml b/waypoints/src/main/resources/plugin.yml index 2572269..3539a71 100644 --- a/waypoints/src/main/resources/plugin.yml +++ b/waypoints/src/main/resources/plugin.yml @@ -9,9 +9,6 @@ website: https://github.com/Sytm/waypoints api-version: "${apiVersion}" folia-supported: true -depend: - - CommandAPI - softdepend: - Vault - dynmap