Skip to content

Commit

Permalink
feat(shulker-proxy-agent): add glist, gtp and gfind commands
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremylvln committed Oct 27, 2023
1 parent c29eac1 commit 850af26
Show file tree
Hide file tree
Showing 12 changed files with 284 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -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")
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<out String>) {
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 <player>").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())
}
}
Original file line number Diff line number Diff line change
@@ -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<out String>) {
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<String>) {
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<BaseComponent> {
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()
}
}
Original file line number Diff line number Diff line change
@@ -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<out String>) {
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 <player> [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())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<CommandSource>("gfind")
.requires { it.hasPermission("shulker.command.gfind") }
.then(RequiredArgumentBuilder.argument<CommandSource, String>("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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,57 +8,50 @@ 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

object GlobalListCommand {
fun create(agent: ShulkerProxyAgentCommon, proxyServer: ProxyServer): BrigadierCommand {
val rootNode = LiteralArgumentBuilder.literal<CommandSource>("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<CommandSource, String>("server", StringArgumentType.word())
.suggests { _, builder ->
proxyServer.allServers.forEach { server ->
builder.suggest(server.serverInfo.name)
}
.then(
RequiredArgumentBuilder.argument<CommandSource, String>("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()

return BrigadierCommand(rootNode)
}

private fun showPlayerListInServers(agent: ShulkerProxyAgentCommon, source: CommandSource, serverNames: Set<String>) {
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 {
Expand Down
Loading

0 comments on commit 850af26

Please sign in to comment.