From 850af2615347fc7b0384ad1a33d7d305c7baf3d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Levilain?= Date: Sat, 28 Oct 2023 00:55:05 +0200 Subject: [PATCH] feat(shulker-proxy-agent): add glist, gtp and gfind commands --- .../bungeecord/ShulkerProxyAgentBungeeCord.kt | 7 +++ .../bungeecord/commands/GlobalFindCommand.kt | 32 ++++++++++ .../bungeecord/commands/GlobalListCommand.kt | 48 +++++++++++++++ .../commands/GlobalTeleportCommand.kt | 40 +++++++++++++ .../proxyagent/ShulkerProxyAgentCommon.kt | 4 ++ .../adapters/pubsub/PubSubAdapter.kt | 6 ++ .../adapters/pubsub/RedisPubSubAdapter.kt | 23 +++++++ .../proxyagent/utils/MessageUtils.kt | 8 --- .../velocity/ShulkerProxyAgentVelocity.kt | 10 ++++ .../velocity/commands/GlobalFindCommand.kt | 37 ++++++++++++ .../velocity/commands/GlobalListCommand.kt | 41 ++++++------- .../commands/GlobalTeleportCommand.kt | 60 +++++++++++++++++++ 12 files changed, 284 insertions(+), 32 deletions(-) create mode 100644 packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalFindCommand.kt create mode 100644 packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalListCommand.kt create mode 100644 packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalTeleportCommand.kt create mode 100644 packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/PubSubAdapter.kt create mode 100644 packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/RedisPubSubAdapter.kt create mode 100644 packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalFindCommand.kt create mode 100644 packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalTeleportCommand.kt diff --git a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ShulkerProxyAgentBungeeCord.kt b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ShulkerProxyAgentBungeeCord.kt index a934b080..402cbe34 100644 --- a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ShulkerProxyAgentBungeeCord.kt +++ b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/ShulkerProxyAgentBungeeCord.kt @@ -1,6 +1,9 @@ package io.shulkermc.proxyagent.bungeecord import io.shulkermc.proxyagent.ShulkerProxyAgentCommon +import io.shulkermc.proxyagent.bungeecord.commands.GlobalFindCommand +import io.shulkermc.proxyagent.bungeecord.commands.GlobalListCommand +import io.shulkermc.proxyagent.bungeecord.commands.GlobalTeleportCommand import net.md_5.bungee.api.plugin.Plugin @Suppress("unused") @@ -9,6 +12,10 @@ class ShulkerProxyAgentBungeeCord : Plugin() { override fun onEnable() { this.agent.onProxyInitialization() + + this.proxy.pluginManager.registerCommand(this, GlobalListCommand(this.agent, this.proxy)) + this.proxy.pluginManager.registerCommand(this, GlobalTeleportCommand(this.agent)) + this.proxy.pluginManager.registerCommand(this, GlobalFindCommand(this.agent)) } override fun onDisable() { diff --git a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalFindCommand.kt b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalFindCommand.kt new file mode 100644 index 00000000..c9b9a19b --- /dev/null +++ b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalFindCommand.kt @@ -0,0 +1,32 @@ +package io.shulkermc.proxyagent.bungeecord.commands + +import io.shulkermc.proxyagent.ShulkerProxyAgentCommon +import net.md_5.bungee.api.ChatColor +import net.md_5.bungee.api.CommandSender +import net.md_5.bungee.api.chat.ComponentBuilder +import net.md_5.bungee.api.plugin.Command + +class GlobalFindCommand(private val agent: ShulkerProxyAgentCommon) : Command("gfind", "shulker.command.gfind") { + override fun execute(sender: CommandSender, args: Array) { + if (!this.hasPermission(sender)) { + sender.sendMessage(*ComponentBuilder("You don't have permission to execute this command.").color(ChatColor.RED).create()) + return + } + + if (args.size != 1) { + sender.sendMessage(*ComponentBuilder("Usage: /gfind ").color(ChatColor.RED).create()) + return + } + + val player = args[0] + val playerPosition = this.agent.cache.getPlayerIdFromName(player) + .flatMap { playerId -> this.agent.cache.getPlayerPosition(playerId) } + + if (playerPosition.isEmpty) { + sender.sendMessage(*ComponentBuilder("Player $player not found.").color(ChatColor.RED).create()) + return + } + + sender.sendMessage(*ComponentBuilder("Player $player is connected on proxy ${playerPosition.get().proxyName} and located on server ${playerPosition.get().serverName}.").color(ChatColor.GREEN).create()) + } +} diff --git a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalListCommand.kt b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalListCommand.kt new file mode 100644 index 00000000..e01f4d9f --- /dev/null +++ b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalListCommand.kt @@ -0,0 +1,48 @@ +package io.shulkermc.proxyagent.bungeecord.commands + +import io.shulkermc.proxyagent.ShulkerProxyAgentCommon +import net.md_5.bungee.api.ChatColor +import net.md_5.bungee.api.CommandSender +import net.md_5.bungee.api.ProxyServer +import net.md_5.bungee.api.chat.BaseComponent +import net.md_5.bungee.api.chat.ComponentBuilder +import net.md_5.bungee.api.chat.TextComponent +import net.md_5.bungee.api.plugin.Command + +class GlobalListCommand(private val agent: ShulkerProxyAgentCommon, private val proxyServer: ProxyServer) : Command("glist", "shulker.command.glist") { + override fun execute(sender: CommandSender, args: Array) { + if (!this.hasPermission(sender)) { + sender.sendMessage(*ComponentBuilder("You don't have permission to execute this command.").color(ChatColor.RED).create()) + return + } + + if (args.size != 1) { + this.showPlayerListInServers(sender, this.proxyServer.servers.keys) + return + } + + val server = args[0] + this.showPlayerListInServers(sender, setOf(server)) + } + + private fun showPlayerListInServers(sender: CommandSender, serverNames: Set) { + sender.sendMessage(*ComponentBuilder("⎯".repeat(63)).color(ChatColor.DARK_GRAY).strikethrough(true).create()) + sender.sendMessage(TextComponent("")) + serverNames.map { serverName -> + sender.sendMessage(*this.createServerListMessage(serverName)) + sender.sendMessage(TextComponent("")) + } + sender.sendMessage(*ComponentBuilder("⎯".repeat(63)).color(ChatColor.DARK_GRAY).strikethrough(true).create()) + } + + private fun createServerListMessage(serverName: String): Array { + val playerNames = this.agent.cache.getPlayerNamesFromIds(this.agent.cache.listPlayersInServer(serverName)).values + .sortedBy { it.lowercase() } + .joinToString(", ") { it } + + return ComponentBuilder("$serverName:\n") + .color(ChatColor.WHITE) + .append(ComponentBuilder(playerNames).color(ChatColor.GRAY).currentComponent) + .create() + } +} diff --git a/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalTeleportCommand.kt b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalTeleportCommand.kt new file mode 100644 index 00000000..8e5ec042 --- /dev/null +++ b/packages/shulker-proxy-agent/src/bungeecord/kotlin/io/shulkermc/proxyagent/bungeecord/commands/GlobalTeleportCommand.kt @@ -0,0 +1,40 @@ +package io.shulkermc.proxyagent.bungeecord.commands + +import io.shulkermc.proxyagent.ShulkerProxyAgentCommon +import net.md_5.bungee.api.ChatColor +import net.md_5.bungee.api.CommandSender +import net.md_5.bungee.api.chat.ComponentBuilder +import net.md_5.bungee.api.plugin.Command + +class GlobalTeleportCommand(private val agent: ShulkerProxyAgentCommon) : Command("gtp", "shulker.command.gtp") { + override fun execute(sender: CommandSender, args: Array) { + if (!this.hasPermission(sender)) { + sender.sendMessage(*ComponentBuilder("You don't have permission to execute this command.").color(ChatColor.RED).create()) + return + } + + if (args.isEmpty() || args.size > 2) { + sender.sendMessage(*ComponentBuilder("Usage: /gtp [server]").color(ChatColor.RED).create()) + return + } + + val player = args[0] + val playerPosition = this.agent.cache.getPlayerIdFromName(player) + .flatMap { playerId -> this.agent.cache.getPlayerPosition(playerId) } + + if (playerPosition.isEmpty) { + sender.sendMessage(*ComponentBuilder("Player $player not found.").color(ChatColor.RED).create()) + return + } + + if (args.size == 1) { + val server = playerPosition.get().serverName + this.agent.pubSub.teleportPlayerOnServer(player, server) + sender.sendMessage(*ComponentBuilder("Teleported to server $server.").color(ChatColor.GREEN).create()) + } else { + val server = args[1] + this.agent.pubSub.teleportPlayerOnServer(player, server) + sender.sendMessage(*ComponentBuilder("Teleported $player to server $server.").color(ChatColor.GREEN).create()) + } + } +} diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt index f99622da..34d83860 100644 --- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt +++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/ShulkerProxyAgentCommon.kt @@ -8,6 +8,8 @@ import io.shulkermc.proxyagent.adapters.filesystem.FileSystemAdapter import io.shulkermc.proxyagent.adapters.filesystem.LocalFileSystemAdapter import io.shulkermc.proxyagent.adapters.kubernetes.KubernetesGatewayAdapter import io.shulkermc.proxyagent.adapters.kubernetes.ImplKubernetesGatewayAdapter +import io.shulkermc.proxyagent.adapters.pubsub.PubSubAdapter +import io.shulkermc.proxyagent.adapters.pubsub.RedisPubSubAdapter import io.shulkermc.proxyagent.api.ShulkerProxyAPI import io.shulkermc.proxyagent.api.ShulkerProxyAPIImpl import io.shulkermc.proxyagent.services.PlayerMovementService @@ -28,6 +30,7 @@ class ShulkerProxyAgentCommon(val proxyInterface: ProxyInterface, val logger: Lo lateinit var kubernetesGateway: KubernetesGatewayAdapter lateinit var fileSystem: FileSystemAdapter lateinit var cache: CacheAdapter + lateinit var pubSub: PubSubAdapter // Services lateinit var serverDirectoryService: ServerDirectoryService @@ -51,6 +54,7 @@ class ShulkerProxyAgentCommon(val proxyInterface: ProxyInterface, val logger: Lo this.fileSystem = LocalFileSystemAdapter() this.kubernetesGateway = ImplKubernetesGatewayAdapter(Configuration.PROXY_NAMESPACE, Configuration.PROXY_NAME) this.cache = RedisCacheAdapter(this.jedisPool) + this.pubSub = RedisPubSubAdapter(this.jedisPool) this.serverDirectoryService = ServerDirectoryService(this) this.playerMovementService = PlayerMovementService(this) diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/PubSubAdapter.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/PubSubAdapter.kt new file mode 100644 index 00000000..664bcefe --- /dev/null +++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/PubSubAdapter.kt @@ -0,0 +1,6 @@ +package io.shulkermc.proxyagent.adapters.pubsub + +interface PubSubAdapter { + fun teleportPlayerOnServer(playerId: String, serverName: String) + fun onTeleportPlayerOnServer(callback: (playerId: String, serverName: String) -> Unit) +} diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/RedisPubSubAdapter.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/RedisPubSubAdapter.kt new file mode 100644 index 00000000..347abd06 --- /dev/null +++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/adapters/pubsub/RedisPubSubAdapter.kt @@ -0,0 +1,23 @@ +package io.shulkermc.proxyagent.adapters.pubsub + +import redis.clients.jedis.JedisPool +import redis.clients.jedis.JedisPubSub + +class RedisPubSubAdapter(private val jedisPool: JedisPool) : PubSubAdapter { + override fun teleportPlayerOnServer(playerId: String, serverName: String) { + this.jedisPool.resource.use { jedis -> + jedis.publish("shulker:teleport", "$playerId:$serverName") + } + } + + override fun onTeleportPlayerOnServer(callback: (playerId: String, serverName: String) -> Unit) { + this.jedisPool.resource.use { jedis -> + jedis.subscribe(object : JedisPubSub() { + override fun onMessage(channel: String, message: String) { + val (playerId, serverName) = message.split(":") + callback(playerId, serverName) + } + }, "shulker:teleport") + } + } +} diff --git a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/utils/MessageUtils.kt b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/utils/MessageUtils.kt index ffdd073a..705bdcd9 100644 --- a/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/utils/MessageUtils.kt +++ b/packages/shulker-proxy-agent/src/common/kotlin/io/shulkermc/proxyagent/utils/MessageUtils.kt @@ -5,8 +5,6 @@ import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextColor import net.kyori.adventure.text.format.TextDecoration -val SEPARATOR = Component.text("⎯".repeat(63)).color(NamedTextColor.DARK_GRAY).decorate(TextDecoration.STRIKETHROUGH) - fun createDisconnectMessage(message: String, color: TextColor): Component = Component.text("◆ Shulker ◆\n") .color(NamedTextColor.LIGHT_PURPLE) @@ -16,9 +14,3 @@ fun createDisconnectMessage(message: String, color: TextColor): Component = .color(color) .decorate(TextDecoration.BOLD) ) - -fun createBlockTitleMessage(title: String): Component = - Component.text(" ◆ ") - .color(NamedTextColor.LIGHT_PURPLE) - .decorate(TextDecoration.BOLD) - .append(Component.text(title).color(NamedTextColor.LIGHT_PURPLE)) diff --git a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ShulkerProxyAgentVelocity.kt b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ShulkerProxyAgentVelocity.kt index aa0cf0de..cbdb1254 100644 --- a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ShulkerProxyAgentVelocity.kt +++ b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/ShulkerProxyAgentVelocity.kt @@ -8,7 +8,9 @@ import com.velocitypowered.api.plugin.Plugin import com.velocitypowered.api.proxy.ProxyServer import io.shulkermc.proxyagent.ShulkerProxyAgentCommon import io.shulkermc.proxyagent.VelocityBuildConfig +import io.shulkermc.proxyagent.velocity.commands.GlobalFindCommand import io.shulkermc.proxyagent.velocity.commands.GlobalListCommand +import io.shulkermc.proxyagent.velocity.commands.GlobalTeleportCommand import java.util.logging.Logger @Plugin( @@ -32,6 +34,14 @@ class ShulkerProxyAgentVelocity @Inject constructor( commandManager.metaBuilder("glist").plugin(this).build(), GlobalListCommand.create(this.agent, this.proxy) ) + commandManager.register( + commandManager.metaBuilder("gtp").plugin(this).build(), + GlobalTeleportCommand.create(this.agent, this.proxy) + ) + commandManager.register( + commandManager.metaBuilder("gfind").plugin(this).build(), + GlobalFindCommand.create(this.agent) + ) } @Subscribe diff --git a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalFindCommand.kt b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalFindCommand.kt new file mode 100644 index 00000000..e0009145 --- /dev/null +++ b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalFindCommand.kt @@ -0,0 +1,37 @@ +package io.shulkermc.proxyagent.velocity.commands + +import com.mojang.brigadier.Command +import com.mojang.brigadier.arguments.StringArgumentType +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.velocitypowered.api.command.BrigadierCommand +import com.velocitypowered.api.command.CommandSource +import io.shulkermc.proxyagent.ShulkerProxyAgentCommon +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor + +object GlobalFindCommand { + fun create(agent: ShulkerProxyAgentCommon): BrigadierCommand { + val rootNode = LiteralArgumentBuilder.literal("gfind") + .requires { it.hasPermission("shulker.command.gfind") } + .then(RequiredArgumentBuilder.argument("player", StringArgumentType.word()) + .executes { context -> + val source = context.source + val player = context.getArgument("player", String::class.java) + val playerPosition = agent.cache.getPlayerIdFromName(player) + .flatMap { playerId -> agent.cache.getPlayerPosition(playerId) } + + if (playerPosition.isEmpty) { + source.sendMessage(Component.text("Player $player not found.", NamedTextColor.RED)) + return@executes Command.SINGLE_SUCCESS + } + + source.sendMessage(Component.text("Player $player is connected on proxy ${playerPosition.get().proxyName} and located on server ${playerPosition.get().serverName}.", NamedTextColor.GREEN)) + return@executes Command.SINGLE_SUCCESS + } + ) + .build() + + return BrigadierCommand(rootNode) + } +} diff --git a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalListCommand.kt b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalListCommand.kt index 1a2c03bf..53f2d9f9 100644 --- a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalListCommand.kt +++ b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalListCommand.kt @@ -8,7 +8,6 @@ import com.velocitypowered.api.command.BrigadierCommand import com.velocitypowered.api.command.CommandSource import com.velocitypowered.api.proxy.ProxyServer import io.shulkermc.proxyagent.ShulkerProxyAgentCommon -import io.shulkermc.proxyagent.utils.SEPARATOR import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextDecoration @@ -16,28 +15,29 @@ import net.kyori.adventure.text.format.TextDecoration object GlobalListCommand { fun create(agent: ShulkerProxyAgentCommon, proxyServer: ProxyServer): BrigadierCommand { val rootNode = LiteralArgumentBuilder.literal("glist") - //.requires { it.hasPermission("shulker.command.glist") } + .requires { it.hasPermission("shulker.command.glist") } .executes { context -> val source = context.source showPlayerListInServers(agent, source, proxyServer.allServers.map { it.serverInfo.name }.toSet()) return@executes Command.SINGLE_SUCCESS } - .then(RequiredArgumentBuilder.argument("server", StringArgumentType.word()) - .suggests { _, builder -> - proxyServer.allServers.forEach { server -> - builder.suggest(server.serverInfo.name) - } + .then( + RequiredArgumentBuilder.argument("server", StringArgumentType.word()) + .suggests { _, builder -> + proxyServer.allServers.forEach { server -> + builder.suggest(server.serverInfo.name) + } - return@suggests builder.buildFuture() - } - .executes { context -> - val source = context.source - val server = context.getArgument("server", String::class.java) + return@suggests builder.buildFuture() + } + .executes { context -> + val source = context.source + val server = context.getArgument("server", String::class.java) - showPlayerListInServers(agent, source, setOf(server)) - return@executes Command.SINGLE_SUCCESS - } + showPlayerListInServers(agent, source, setOf(server)) + return@executes Command.SINGLE_SUCCESS + } ) .build() @@ -45,20 +45,13 @@ object GlobalListCommand { } private fun showPlayerListInServers(agent: ShulkerProxyAgentCommon, source: CommandSource, serverNames: Set) { - source.sendMessage(SEPARATOR) + source.sendMessage(Component.text("⎯".repeat(63)).color(NamedTextColor.DARK_GRAY).decorate(TextDecoration.STRIKETHROUGH)) source.sendMessage(Component.empty()) - source.sendMessage(Component.text(" ◆ ") - .color(NamedTextColor.LIGHT_PURPLE) - .decorate(TextDecoration.BOLD) - .append(Component.text("Global list of connected players").color(NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.BOLD, false))) - source.sendMessage(Component.empty()) - serverNames.map { serverName -> source.sendMessage(this.createServerListMessage(agent, serverName)) source.sendMessage(Component.empty()) } - - source.sendMessage(SEPARATOR) + source.sendMessage(Component.text("⎯".repeat(63)).color(NamedTextColor.DARK_GRAY).decorate(TextDecoration.STRIKETHROUGH)) } private fun createServerListMessage(agent: ShulkerProxyAgentCommon, serverName: String): Component { diff --git a/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalTeleportCommand.kt b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalTeleportCommand.kt new file mode 100644 index 00000000..2899f227 --- /dev/null +++ b/packages/shulker-proxy-agent/src/velocity/kotlin/io/shulkermc/proxyagent/velocity/commands/GlobalTeleportCommand.kt @@ -0,0 +1,60 @@ +package io.shulkermc.proxyagent.velocity.commands + +import com.mojang.brigadier.Command +import com.mojang.brigadier.arguments.StringArgumentType +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.builder.RequiredArgumentBuilder +import com.velocitypowered.api.command.BrigadierCommand +import com.velocitypowered.api.command.CommandSource +import com.velocitypowered.api.proxy.ProxyServer +import io.shulkermc.proxyagent.ShulkerProxyAgentCommon +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor + +object GlobalTeleportCommand { + fun create(agent: ShulkerProxyAgentCommon, proxyServer: ProxyServer): BrigadierCommand { + val rootNode = LiteralArgumentBuilder.literal("gtp") + .requires { it.hasPermission("shulker.command.gtp") } + .then(RequiredArgumentBuilder.argument("player", StringArgumentType.word()) + .executes { context -> + val source = context.source + val player = context.getArgument("player", String::class.java) + val playerPosition = agent.cache.getPlayerIdFromName(player) + .flatMap { playerId -> agent.cache.getPlayerPosition(playerId) } + + if (playerPosition.isEmpty) { + source.sendMessage(Component.text("Player $player not found.", NamedTextColor.RED)) + return@executes Command.SINGLE_SUCCESS + } + + val server = playerPosition.get().serverName + agent.pubSub.teleportPlayerOnServer(player, server) + source.sendMessage(Component.text("Teleported to server $server.", NamedTextColor.GREEN)) + + return@executes Command.SINGLE_SUCCESS + } + .then(RequiredArgumentBuilder.argument("server", StringArgumentType.word()) + .suggests { _, builder -> + proxyServer.allServers.forEach { server -> + builder.suggest(server.serverInfo.name) + } + + return@suggests builder.buildFuture() + } + .executes { context -> + val source = context.source + val player = context.getArgument("player", String::class.java) + val server = context.getArgument("server", String::class.java) + + agent.pubSub.teleportPlayerOnServer(player, server) + source.sendMessage(Component.text("Teleported $player to server $server.", NamedTextColor.GREEN)) + + return@executes Command.SINGLE_SUCCESS + } + ) + ) + .build() + + return BrigadierCommand(rootNode) + } +}