From c4f7bd5b1c37969579a25386fc43e0fcf792fed9 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sat, 25 Apr 2026 23:22:24 +0200 Subject: [PATCH 01/14] feat: implement core command and service commands with shutdown and execute functionalities --- gradle.properties | 2 +- .../argument/SurfOfflinePlayerArgument.kt | 10 + .../command/argument/SurfPlayerArgument.kt | 10 + .../dev/slne/surf/core/client/ClientLoader.kt | 5 + .../client/server/SurfServerServiceImpl.kt | 11 + .../listener/ExecuteCommandRedisListener.kt | 19 ++ .../listener/ExecuteCommandServerListener.kt | 11 + .../redis/listener/ShutdownServerListener.kt | 11 + .../listener/ShutdownServerRedisListener.kt | 19 ++ .../request/ExecuteCommandServerRequest.kt | 29 +++ .../redis/request/ShutdownServerRequest.kt | 31 +++ .../core/common/server/SurfServerService.kt | 4 + .../listener/PaperExecuteCommandListener.kt | 21 ++ .../paper/listener/PaperShutdownListener.kt | 46 ++++ surf-core-velocity/build.gradle.kts | 1 + .../slne/surf/core/velocity/VelocityMain.kt | 5 + .../surf/core/velocity/command/CoreCommand.kt | 40 ++++ .../velocity/command/CorePlayerCommand.kt | 185 +++++++++++++++ .../velocity/command/CoreServiceCommand.kt | 220 ++++++++++++++++++ .../VelocityExecuteCommandListener.kt | 23 ++ .../listener/VelocityShutdownListener.kt | 20 ++ .../velocity/permission/PermissionList.kt | 11 + 22 files changed, 733 insertions(+), 1 deletion(-) create mode 100644 surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt create mode 100644 surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt create mode 100644 surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt create mode 100644 surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt create mode 100644 surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ExecuteCommandServerRequest.kt create mode 100644 surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ShutdownServerRequest.kt create mode 100644 surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt create mode 100644 surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt create mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt create mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt create mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt create mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt create mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt create mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/permission/PermissionList.kt diff --git a/gradle.properties b/gradle.properties index 87c6bd7..c553589 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official kotlin.stdlib.default.dependency=false org.gradle.parallel=true -version=2.2.1-SNAPSHOT +version=2.3.0-SNAPSHOT diff --git a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt index dc247bb..ef62b52 100644 --- a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt +++ b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt @@ -2,9 +2,11 @@ package dev.slne.surf.core.api.velocity.command.argument import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.context.CommandContext +import com.velocitypowered.api.command.CommandSource import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.CommandTree import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions import dev.jorel.commandapi.arguments.CommandAPIArgumentType import dev.jorel.commandapi.executors.CommandArguments import dev.slne.surf.api.core.util.logger @@ -33,6 +35,14 @@ open class SurfOfflinePlayerArgument(nodeName: String) : SurfCoreApi.getOfflinePlayer(StringArgumentType.getString(cmdCtx, key)) }.asDeferred() + override fun replaceSuggestions(suggestions: ArgumentSuggestions): Argument> = + super.replaceSuggestions( + ArgumentSuggestions.stringCollection { _ -> + SurfCoreApi.getOnlinePlayers() + .mapNotNull { it.lastKnownName } + } + ) + companion object { private val log = logger() private val scope = diff --git a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt index 0f8bac3..c1b0ea6 100644 --- a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt +++ b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt @@ -3,10 +3,12 @@ package dev.slne.surf.core.api.velocity.command.argument import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import com.velocitypowered.api.command.CommandSource import com.velocitypowered.api.command.VelocityBrigadierMessage import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.CommandTree import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions import dev.jorel.commandapi.arguments.CommandAPIArgumentType import dev.jorel.commandapi.executors.CommandArguments import dev.slne.surf.api.core.messages.adventure.buildText @@ -36,6 +38,14 @@ open class SurfPlayerArgument(nodeName: String) : } ) ).create() + + override fun replaceSuggestions(suggestions: ArgumentSuggestions): Argument = + super.replaceSuggestions( + ArgumentSuggestions.stringCollection { _ -> + SurfCoreApi.getOnlinePlayers() + .mapNotNull { it.lastKnownName } + } + ) } inline fun CommandTree.surfPlayerArgument( diff --git a/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/ClientLoader.kt b/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/ClientLoader.kt index 0319c8b..98f934c 100644 --- a/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/ClientLoader.kt +++ b/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/ClientLoader.kt @@ -4,8 +4,10 @@ package dev.slne.surf.core.client import dev.slne.surf.core.core.common.event.LocalSurfEventBusListener import dev.slne.surf.core.core.common.player.SurfPlayerService +import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandRedisListener import dev.slne.surf.core.core.common.redis.listener.SendPlayerToProxyListener import dev.slne.surf.core.core.common.redis.listener.SendPlayerToServerListener +import dev.slne.surf.core.core.common.redis.listener.ShutdownServerRedisListener import dev.slne.surf.core.core.common.server.SurfServerService import dev.slne.surf.rabbitmq.api.ClientRabbitMQApi import dev.slne.surf.redis.RedisApi @@ -31,6 +33,9 @@ class ClientLoader( withListener(SendPlayerToServerListener) withListener(SendPlayerToProxyListener) + withRequestResponseHandler(ShutdownServerRedisListener) + withRequestResponseHandler(ExecuteCommandRedisListener) + // Initialize Redis Maps SurfPlayerService SurfServerService diff --git a/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/server/SurfServerServiceImpl.kt b/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/server/SurfServerServiceImpl.kt index 8caba8d..9aba35b 100644 --- a/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/server/SurfServerServiceImpl.kt +++ b/surf-core-core/surf-core-core-client/src/main/kotlin/dev/slne/surf/core/client/server/SurfServerServiceImpl.kt @@ -7,8 +7,11 @@ import dev.slne.surf.core.api.common.server.SurfProxyServer import dev.slne.surf.core.api.common.server.SurfServer import dev.slne.surf.core.api.common.server.state.SurfServerState import dev.slne.surf.core.client.ClientCoreInstance +import dev.slne.surf.core.core.common.redis.request.ExecuteCommandServerRequest +import dev.slne.surf.core.core.common.redis.request.ShutdownServerRequest import dev.slne.surf.core.core.common.server.SurfServerService import it.unimi.dsi.fastutil.objects.ObjectSet +import net.kyori.adventure.text.Component import java.util.* @AutoService(SurfServerService::class) @@ -55,6 +58,14 @@ class SurfServerServiceImpl : SurfServerService { } } + override suspend fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?) = + ShutdownServerRequest.createRequest(commonSurfServer, reason).status + + override suspend fun executeCommand( + commonSurfServer: CommonSurfServer, + command: String + ) = ExecuteCommandServerRequest.createRequest(commonSurfServer, command).status + override fun getServerByName(name: String) = servers.find { it.name == name } override fun getServerByCategory(category: String) = servers.filter { it.category == category }.toObjectSet() diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt new file mode 100644 index 0000000..554596c --- /dev/null +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.core.core.common.redis.listener + +import dev.slne.surf.core.core.common.redis.request.ExecuteCommandServerRequest +import dev.slne.surf.redis.request.HandleRedisRequest +import dev.slne.surf.redis.request.RequestContext + +object ExecuteCommandRedisListener { + @HandleRedisRequest + suspend fun handleExecuteCommandRequest(context: RequestContext) { + context.respond( + ExecuteCommandServerRequest.Response( + ExecuteCommandServerListener.executeCommand( + context.request.commonSurfServer, + context.request.command + ) + ) + ) + } +} \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt new file mode 100644 index 0000000..e7bf524 --- /dev/null +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.core.core.common.redis.listener + +import dev.slne.surf.api.core.util.requiredService +import dev.slne.surf.core.api.common.server.CommonSurfServer + +interface ExecuteCommandServerListener { + suspend fun executeCommand(commonSurfServer: CommonSurfServer, command: String): Boolean + + companion object : + ExecuteCommandServerListener by requiredService() +} \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt new file mode 100644 index 0000000..9e43809 --- /dev/null +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.core.core.common.redis.listener + +import dev.slne.surf.api.core.util.requiredService +import dev.slne.surf.core.api.common.server.CommonSurfServer +import net.kyori.adventure.text.Component + +interface ShutdownServerListener { + fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean + + companion object : ShutdownServerListener by requiredService() +} \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt new file mode 100644 index 0000000..1275439 --- /dev/null +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.core.core.common.redis.listener + +import dev.slne.surf.core.core.common.redis.request.ShutdownServerRequest +import dev.slne.surf.redis.request.HandleRedisRequest +import dev.slne.surf.redis.request.RequestContext + +object ShutdownServerRedisListener { + @HandleRedisRequest + fun handleShutdownRequest(context: RequestContext) { + context.respond( + ShutdownServerRequest.Response( + ShutdownServerListener.shutdown( + context.request.commonSurfServer, + context.request.reason + ) + ) + ) + } +} \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ExecuteCommandServerRequest.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ExecuteCommandServerRequest.kt new file mode 100644 index 0000000..5083cd1 --- /dev/null +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ExecuteCommandServerRequest.kt @@ -0,0 +1,29 @@ +package dev.slne.surf.core.core.common.redis.request + +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.core.CoreInstance +import dev.slne.surf.redis.request.RedisRequest +import dev.slne.surf.redis.request.RedisResponse +import kotlinx.serialization.Serializable +import kotlin.time.Duration.Companion.seconds + +object ExecuteCommandServerRequest { + @Serializable + data class Request( + val commonSurfServer: CommonSurfServer, + val command: String + ) : RedisRequest() + + @Serializable + data class Response( + val status: Boolean + ) : RedisResponse() + + suspend fun createRequest(commonSurfServer: CommonSurfServer, command: String) = + runCatching { + CoreInstance.redisApi.sendRequest( + Request(commonSurfServer, command), + 10.seconds.inWholeMilliseconds + ) + }.getOrNull() ?: Response(false) +} \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ShutdownServerRequest.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ShutdownServerRequest.kt new file mode 100644 index 0000000..0998fdf --- /dev/null +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/request/ShutdownServerRequest.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.core.core.common.redis.request + +import dev.slne.surf.api.core.serializer.adventure.component.SerializableComponent +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.core.CoreInstance +import dev.slne.surf.redis.request.RedisRequest +import dev.slne.surf.redis.request.RedisResponse +import kotlinx.serialization.Serializable +import net.kyori.adventure.text.Component +import kotlin.time.Duration.Companion.seconds + +object ShutdownServerRequest { + @Serializable + data class Request( + val commonSurfServer: CommonSurfServer, + val reason: SerializableComponent? + ) : RedisRequest() + + @Serializable + data class Response( + val status: Boolean + ) : RedisResponse() + + suspend fun createRequest(commonSurfServer: CommonSurfServer, reason: Component?) = + runCatching { + CoreInstance.redisApi.sendRequest( + Request(commonSurfServer, reason), + 10.seconds.inWholeMilliseconds + ) + }.getOrNull() ?: Response(false) +} \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/server/SurfServerService.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/server/SurfServerService.kt index ad3871a..22f8426 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/server/SurfServerService.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/server/SurfServerService.kt @@ -6,6 +6,7 @@ import dev.slne.surf.core.api.common.server.SurfProxyServer import dev.slne.surf.core.api.common.server.SurfServer import dev.slne.surf.core.api.common.server.state.SurfServerState import it.unimi.dsi.fastutil.objects.ObjectSet +import net.kyori.adventure.text.Component import org.jetbrains.annotations.UnmodifiableView import java.util.* @@ -19,6 +20,9 @@ interface SurfServerService { fun removeServer(server: CommonSurfServer) fun changeState(commonSurfServer: CommonSurfServer, state: SurfServerState) + suspend fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean + suspend fun executeCommand(commonSurfServer: CommonSurfServer, command: String): Boolean + fun getServerByName(name: String): SurfServer? fun getServerByUuid(uuid: UUID): CommonSurfServer? fun getServerByCategory(category: String): ObjectSet diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt new file mode 100644 index 0000000..fe11d6e --- /dev/null +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt @@ -0,0 +1,21 @@ +package dev.slne.surf.core.paper.listener + +import com.google.auto.service.AutoService +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandServerListener +import org.bukkit.Bukkit + +@AutoService(ExecuteCommandServerListener::class) +object PaperExecuteCommandListener : ExecuteCommandServerListener { + override suspend fun executeCommand( + commonSurfServer: CommonSurfServer, + command: String + ): Boolean { + if (commonSurfServer.uuid != SurfServer.current().uuid) { + return false + } + + return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command) + } +} \ No newline at end of file diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt new file mode 100644 index 0000000..a307d2d --- /dev/null +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt @@ -0,0 +1,46 @@ +package dev.slne.surf.core.paper.listener + +import com.google.auto.service.AutoService +import dev.slne.surf.api.core.messages.adventure.appendNewline +import dev.slne.surf.api.core.messages.adventure.buildText +import dev.slne.surf.api.paper.util.forEachPlayer +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.core.common.redis.listener.ShutdownServerListener +import net.kyori.adventure.text.Component +import org.bukkit.Bukkit + +@AutoService(ShutdownServerListener::class) +object PaperShutdownListener : ShutdownServerListener { + override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean { + if (commonSurfServer.uuid != SurfServer.current().uuid) { + return false + } + + forEachPlayer { player -> + player.kick(buildDisconnectComponent(reason)) + } + + Bukkit.shutdown() + return true + } + + + private fun buildDisconnectComponent(reason: Component?) = buildText { + appendNewline(2) + primary("CASTCRAFTER") + appendNewline() + primary("COMMUNITY SERVER") + appendNewline(2) + error("DER SERVER WIRD HERUNTERGEFAHREN.") + appendNewline(3) + spacer("Der Server wurde gestoppt. Bitte versuche es später erneut.") + reason?.let { + appendNewline() + spacer("Grund: ") + append(reason) + } + appendNewline(2) + primary("discord.gg/castcrafter") + } +} \ No newline at end of file diff --git a/surf-core-velocity/build.gradle.kts b/surf-core-velocity/build.gradle.kts index 25f15c0..cd53ce4 100644 --- a/surf-core-velocity/build.gradle.kts +++ b/surf-core-velocity/build.gradle.kts @@ -9,6 +9,7 @@ surfVelocityApi { velocityPluginFile { main = "dev.slne.surf.core.velocity.VelocityMain" authors = listOf("red") + version = findProperty("version") as String pluginDependencies { register("surf-rabbitmq-velocity") diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt index a46e33f..4008823 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt @@ -27,9 +27,11 @@ import dev.slne.surf.core.core.common.util.appendCorePrefix import dev.slne.surf.core.core.common.util.niceRed import dev.slne.surf.core.velocity.auth.AuthenticationListener import dev.slne.surf.core.velocity.auth.AuthenticationService +import dev.slne.surf.core.velocity.command.coreCommand import dev.slne.surf.core.velocity.config.VelocityCoreConfigManager import dev.slne.surf.core.velocity.listener.ConnectionListener import dev.slne.surf.core.velocity.listener.VelocityServerListener +import dev.slne.surf.core.velocity.listener.VelocityShutdownListener import dev.slne.surf.core.velocity.redis.handler.SendPlayerToProxyHandler import dev.slne.surf.core.velocity.redis.handler.SendPlayerToServerHandler import dev.slne.surf.core.velocity.redis.listener.VelocityRedisListener @@ -62,6 +64,7 @@ class VelocityMain @Inject constructor( } AuthenticationService.init() + ClientCoreInstance.redisApi.registerRequestHandler(VelocityShutdownListener) ClientCoreInstance.clientLoader.withListener(VelocityRedisListener) ClientCoreInstance.clientLoader.withRequestResponseHandler(SendPlayerToProxyHandler) @@ -99,6 +102,8 @@ class VelocityMain @Inject constructor( SurfServerService.changeState(SurfProxyServer.current(), SurfServerState.RUNNING) + coreCommand() + surfPlayerSyncTask.start() } diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt new file mode 100644 index 0000000..65cdec3 --- /dev/null +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt @@ -0,0 +1,40 @@ +package dev.slne.surf.core.velocity.command + +import dev.jorel.commandapi.kotlindsl.anyExecutor +import dev.jorel.commandapi.kotlindsl.commandAPICommand +import dev.slne.surf.api.core.messages.adventure.sendText +import dev.slne.surf.core.core.common.util.appendCorePrefix +import dev.slne.surf.core.velocity.permission.PermissionList +import dev.slne.surf.core.velocity.plugin +import kotlin.jvm.optionals.getOrNull + +fun coreCommand() = commandAPICommand("core") { + withPermission(PermissionList.CORE_COMMAND) + + anyExecutor { source, _ -> + val coreVersion = + plugin.pluginManager.getPlugin("surf-core-velocity") + .getOrNull()?.description?.version?.getOrNull() ?: "Unbekannt" + val platform = plugin.proxy.version.name + val platformVersion = plugin.proxy.version.version + val vendor = plugin.proxy.version.vendor + + source.sendText { + appendCorePrefix() + info("This proxy is running ") + variableValue("surf-core-velocity") + info(" version ") + variableValue(coreVersion) + info(" on ") + variableValue(platform) + appendSpace() + variableValue(platformVersion) + info(" by ") + variableValue(vendor) + info(".") + } + } + + corePlayerCommand() + coreServiceCommand() +} \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt new file mode 100644 index 0000000..55c5872 --- /dev/null +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt @@ -0,0 +1,185 @@ +package dev.slne.surf.core.velocity.command + +import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.api.core.messages.adventure.buildText +import dev.slne.surf.api.core.messages.adventure.clickRunsCommand +import dev.slne.surf.api.core.messages.adventure.sendText +import dev.slne.surf.api.core.minimessage.miniMessage +import dev.slne.surf.api.core.util.dateTimeFormatter +import dev.slne.surf.core.api.common.player.SurfPlayer +import dev.slne.surf.core.api.common.util.sendText +import dev.slne.surf.core.api.velocity.command.argument.surfPlayerArgument +import dev.slne.surf.core.core.common.player.SurfPlayerService +import dev.slne.surf.core.core.common.util.appendCorePrefix +import dev.slne.surf.core.core.common.util.niceRed +import dev.slne.surf.core.velocity.permission.PermissionList +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.TextDecoration + +fun corePlayerCommand() = subcommand("player") { + withPermission(PermissionList.CORE_COMMAND_PLAYER) + + literalArgument("list") { + anyExecutor { source, _ -> + if (SurfPlayerService.players.isEmpty()) { + source.sendText { + appendCorePrefix() + error("Derzeit sind keine Spieler auf dem Netzwerk online.") + } + return@anyExecutor + } + + source.sendText { + appendCorePrefix() + info("Derzeit sind ") + variableValue(SurfPlayerService.players.size) + info(" Spieler auf dem Netzwerk online:") + appendCollection(SurfPlayerService.players) { player -> + buildText { + variableValue(player.username) + clickRunsCommand("/core player ${player.username} info") + hoverEvent(buildText { + info("Online auf ") + variableValue("${player.currentServer?.name ?: "Unbekannt"} (${player.currentProxy?.name ?: "Unbekannt"})") + }) + } + } + } + } + } + + surfPlayerArgument("target") { + literalArgument("find") { + anyExecutor { source, arguments -> + val target: SurfPlayer by arguments + + source.sendText { + appendCorePrefix() + info("Der Spieler ") + variableValue(target.username) + info(" ist derzeit online auf ") + variableValue("${target.currentServer?.name ?: "Unbekannt"} (${target.currentProxy?.name ?: "Unbekannt"})") + info(". ") + + append { + spacer("[TP]") + clickRunsCommand("/ntp ${target.username}") + hoverEvent(buildText { + info("Teleportiere dich zu ${target.username}") + }) + } + } + } + } + + literalArgument("info") { + anyExecutor { source, arguments -> + val target: SurfPlayer by arguments + + source.sendText { + appendCorePrefix() + spacer("*") + spacer("-".repeat(30 - target.username.length / 2)) + variableValue(target.username) + spacer("-".repeat(30 - target.username.length / 2)) + spacer("*") + + appendNewline() + appendCorePrefix() + info("UUID: ") + variableValue(target.uuid.toString()) + + appendNewline() + appendCorePrefix() + info("Letzter Name: ") + variableValue(target.lastKnownName ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Aktueller Server: ") + variableValue(target.currentServer?.name ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Aktueller Proxy: ") + variableValue(target.currentProxy?.name ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Erstmals gesehen: ") + variableValue(target.firstSeen?.let { + dateTimeFormatter.format(it).toString() + } ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Verbindung transferiert: ") + variableValue(target.transferred) + + appendNewline() + appendCorePrefix() + info("Ip Adresse: ") + variableValue(target.lastKnownIpAddress?.toString() ?: "Unbekannt") + + + + appendNewline() + appendCorePrefix() + spacer("*") + spacer("-".repeat(30)) + spacer("*") + } + } + } + + literalArgument("notify") { + textArgument("message") + multiLiteralArgument("prefix", "--moderation", "--system", "--warn", optional = true) + + anyExecutor { source, arguments -> + val target: SurfPlayer by arguments + val message: String by arguments + val prefix: String? by arguments + + target.sendText { + appendCorePrefix() + appendSpace() + append(findPrefix(prefix)) + append(miniMessage.deserialize(message)) + } + + source.sendText { + appendCorePrefix() + info("Die Nachricht wurde an alle Spieler gesendet.") + } + } + } + } +} + +private fun findPrefix(prefix: String?) = buildText { + when (prefix) { + "--moderation" -> { + spacer("[") + error("MODERATION") + spacer("]") + appendSpace() + } + + "--system" -> { + spacer("[") + variableValue("SYSTEM") + spacer("]") + appendSpace() + } + + "--warn" -> { + spacer("[") + niceRed("WARNUNG", TextDecoration.BOLD) + spacer("]") + appendSpace() + } + + else -> Component.empty() + } +} \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt new file mode 100644 index 0000000..5680647 --- /dev/null +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt @@ -0,0 +1,220 @@ +package dev.slne.surf.core.velocity.command + +import com.github.shynixn.mccoroutine.velocity.launch +import com.velocitypowered.api.proxy.ConsoleCommandSource +import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.api.core.messages.adventure.sendText +import dev.slne.surf.api.core.minimessage.miniMessage +import dev.slne.surf.api.velocity.command.executors.anyExecutorSuspend +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.api.velocity.command.argument.surfServerArgument +import dev.slne.surf.core.core.common.server.SurfServerService +import dev.slne.surf.core.core.common.util.appendCorePrefix +import dev.slne.surf.core.velocity.permission.PermissionList +import dev.slne.surf.core.velocity.plugin +import net.kyori.adventure.text.event.ClickEvent +import java.time.Duration +import java.time.OffsetDateTime + +fun coreServiceCommand() = subcommand("service") { + withPermission(PermissionList.CORE_COMMAND_SERVICE) + + literalArgument("list") { + + } + + + surfServerArgument("service") { + literalArgument("shutdown") { + textArgument("reason", optional = true) { + anyExecutorSuspend { source, arguments -> + val service: CommonSurfServer by arguments + val reason: String? by arguments + + if (source is ConsoleCommandSource || service.getPlayerCount() <= 5) { + source.sendText { + appendInfoPrefix() + info("Der Server ") + variableValue(service.name) + info(" wird heruntergefahren...") + } + + val result = + SurfServerService.shutdown( + service, + reason?.let { miniMessage.deserialize(it) }) + + if (result) { + source.sendText { + appendCorePrefix() + success("Der Server ") + variableValue(service.name) + success(" wurde erfolgreich heruntergefahren.") + } + } else { + source.sendText { + appendCorePrefix() + error("Der Server ") + variableValue(service.name) + error(" konnte nicht heruntergefahren werden.") + } + } + + return@anyExecutorSuspend + } + + source.sendText { + appendInfoPrefix() + info("Möchtest du wirklich den Server ") + variableValue(service.name) + info(" herunterfahren? Es sind derzeit ") + variableValue(service.getPlayerCount()) + info(" Spieler online! ") + append { + spacer("[") + success("Bestätigen") + spacer("]") + clickEvent(ClickEvent.callback { + plugin.pluginContainer.launch { + source.sendText { + appendInfoPrefix() + info("Der Server ") + variableValue(service.name) + info(" wird heruntergefahren...") + } + + val result = + SurfServerService.shutdown( + service, + reason?.let { miniMessage.deserialize(it) }) + + if (result) { + source.sendText { + appendCorePrefix() + success("Der Server ") + variableValue(service.name) + success(" wurde erfolgreich heruntergefahren.") + } + } else { + source.sendText { + appendCorePrefix() + error("Der Server ") + variableValue(service.name) + error(" konnte nicht heruntergefahren werden.") + } + } + } + }) + } + } + + + } + } + } + + literalArgument("info") { + anyExecutor { source, arguments -> + val service: CommonSurfServer by arguments + + source.sendText { + appendCorePrefix() + spacer("*") + spacer("-".repeat(30 - service.name.length / 2)) + variableValue(service.name) + spacer("-".repeat(30 - service.name.length / 2)) + spacer("*") + + appendNewline() + appendCorePrefix() + info("ID: ") + variableValue(service.uuid.toString()) + + appendNewline() + appendCorePrefix() + info("Interner Name: ") + variableValue(service.name) + + appendNewline() + appendCorePrefix() + info("Anzeigename: ") + variableValue(service.displayName) + + appendNewline() + appendCorePrefix() + info("Serverkategorie: ") + variableValue(service.category) + + appendNewline() + appendCorePrefix() + info("Servertyp: ") + variableValue(if (service.isProxy()) "Proxy" else "Backend") + + appendNewline() + appendCorePrefix() + info("Status: ") + variableValue(service.state.toString()) + + appendNewline() + appendCorePrefix() + info("Spieler: ") + variableValue("${service.getPlayerCount()}/${service.maxPlayers}") + + appendNewline() + appendCorePrefix() + info("Uptime: ") + variableValue( + Duration.between(service.startedAt, OffsetDateTime.now()).toString() + ) + + appendNewline() + appendCorePrefix() + spacer("*") + spacer("-".repeat(30)) + spacer("*") + } + } + } + + + literalArgument("sudo") { + textArgument("command") + + playerExecutor { player, arguments -> + val service: CommonSurfServer by arguments + val command: String by arguments + + if (blockedCommands.any { command.startsWith(it, ignoreCase = true) }) { + player.sendText { + appendCorePrefix() + error("Du darfst diesen Befehl nicht auf dem Server ") + variableValue(service.name) + error(" ausführen.") + } + return@playerExecutor + } + + val result = SurfServerService.executeCommand(service, command) + + if (result) { + player.sendText { + appendCorePrefix() + success("Der Befehl wurde erfolgreich auf dem Server ") + variableValue(service.name) + success(" ausgeführt.") + } + } else { + player.sendText { + appendCorePrefix() + error("Der Befehl konnte nicht auf dem Server ") + variableValue(service.name) + error(" ausgeführt werden.") + } + } + } + } + } +} + +private val blockedCommands = + listOf("lp", "lpv", "luckperms", "perm", "permission", "permissions", "luckpermsvelocity") \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt new file mode 100644 index 0000000..ec2fe83 --- /dev/null +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt @@ -0,0 +1,23 @@ +package dev.slne.surf.core.velocity.listener + +import com.google.auto.service.AutoService +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandServerListener +import dev.slne.surf.core.velocity.plugin +import dev.slne.surf.core.velocity.proxy +import kotlinx.coroutines.future.await + +@AutoService(ExecuteCommandServerListener::class) +object VelocityExecuteCommandListener : ExecuteCommandServerListener { + override suspend fun executeCommand( + commonSurfServer: CommonSurfServer, + command: String + ): Boolean { + if (commonSurfServer.uuid != SurfServer.current().uuid) { + return false + } + + return plugin.proxy.commandManager.executeAsync(proxy.consoleCommandSource, command).await() + } +} \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt new file mode 100644 index 0000000..475614f --- /dev/null +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt @@ -0,0 +1,20 @@ +package dev.slne.surf.core.velocity.listener + +import com.google.auto.service.AutoService +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.core.common.redis.listener.ShutdownServerListener +import dev.slne.surf.core.velocity.plugin +import net.kyori.adventure.text.Component + +@AutoService(ShutdownServerListener::class) +object VelocityShutdownListener : ShutdownServerListener { + override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean { + if (commonSurfServer.uuid != SurfServer.current().uuid) { + return false + } + + plugin.proxy.shutdown(reason) + return true + } +} \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/permission/PermissionList.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/permission/PermissionList.kt new file mode 100644 index 0000000..591e73f --- /dev/null +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/permission/PermissionList.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.core.velocity.permission + +object PermissionList { + private const val BASE = "surf.core" + + const val CORE_COMMAND = "$BASE.command" + + const val CORE_COMMAND_PLAYER = "$CORE_COMMAND.player" + + const val CORE_COMMAND_SERVICE = "$CORE_COMMAND.service" +} \ No newline at end of file From f336815601afc88007efde04772dda5dbd5b16a7 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sat, 25 Apr 2026 23:26:11 +0200 Subject: [PATCH 02/14] feat: add service list command to display active servers with player counts --- gradle.properties | 2 +- .../velocity/command/CoreServiceCommand.kt | 39 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index c553589..94db2d5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official kotlin.stdlib.default.dependency=false org.gradle.parallel=true -version=2.3.0-SNAPSHOT +version=2.3.0-SNAPSHOT \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt index 5680647..ae024d2 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt @@ -3,9 +3,12 @@ package dev.slne.surf.core.velocity.command import com.github.shynixn.mccoroutine.velocity.launch import com.velocitypowered.api.proxy.ConsoleCommandSource import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.api.core.messages.adventure.buildText +import dev.slne.surf.api.core.messages.adventure.clickRunsCommand import dev.slne.surf.api.core.messages.adventure.sendText import dev.slne.surf.api.core.minimessage.miniMessage import dev.slne.surf.api.velocity.command.executors.anyExecutorSuspend +import dev.slne.surf.api.velocity.command.executors.playerExecutorSuspend import dev.slne.surf.core.api.common.server.CommonSurfServer import dev.slne.surf.core.api.velocity.command.argument.surfServerArgument import dev.slne.surf.core.core.common.server.SurfServerService @@ -20,7 +23,37 @@ fun coreServiceCommand() = subcommand("service") { withPermission(PermissionList.CORE_COMMAND_SERVICE) literalArgument("list") { + anyExecutor { source, _ -> + val services = SurfServerService.servers + if (services.isEmpty()) { + source.sendText { + appendCorePrefix() + error("Derzeit sind keine Server auf dem Netzwerk online.") + } + return@anyExecutor + } + + source.sendText { + appendCorePrefix() + info("Derzeit sind ") + variableValue(services.size) + info(" Server aktiv: ") + appendCollection(services) { service -> + buildText { + variableValue(service.displayName) + clickRunsCommand("/core service ${service.name} info") + hoverEvent(buildText { + info("ID: ") + variableValue(service.uuid.toString()) + appendNewline() + info("Spieler: ") + variableValue("${service.getPlayerCount()}/${service.maxPlayers}") + }) + } + } + } + } } @@ -107,8 +140,6 @@ fun coreServiceCommand() = subcommand("service") { }) } } - - } } } @@ -180,7 +211,7 @@ fun coreServiceCommand() = subcommand("service") { literalArgument("sudo") { textArgument("command") - playerExecutor { player, arguments -> + playerExecutorSuspend { player, arguments -> val service: CommonSurfServer by arguments val command: String by arguments @@ -191,7 +222,7 @@ fun coreServiceCommand() = subcommand("service") { variableValue(service.name) error(" ausführen.") } - return@playerExecutor + return@playerExecutorSuspend } val result = SurfServerService.executeCommand(service, command) From e3f59b5a2c698640c7f60c91f55a17b0dae63eb8 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sun, 26 Apr 2026 00:27:04 +0200 Subject: [PATCH 03/14] feat: enhance core command with player and service management functionalities --- .../argument/SurfCommonServerArgument.kt | 9 + .../argument/SurfOfflinePlayerArgument.kt | 6 +- .../command/argument/SurfPlayerArgument.kt | 7 +- .../listener/ExecuteCommandRedisListener.kt | 14 +- .../listener/ExecuteCommandServerListener.kt | 6 +- .../redis/listener/ShutdownServerListener.kt | 6 +- .../listener/ShutdownServerRedisListener.kt | 15 +- .../core/paper/command/SurfCoreCommand.kt | 2 +- .../listener/PaperExecuteCommandListener.kt | 6 +- .../paper/listener/PaperShutdownListener.kt | 6 +- .../slne/surf/core/velocity/VelocityMain.kt | 2 - .../surf/core/velocity/command/CoreCommand.kt | 462 +++++++++++++++++- .../velocity/command/CorePlayerCommand.kt | 185 ------- .../velocity/command/CoreServiceCommand.kt | 251 ---------- .../VelocityExecuteCommandListener.kt | 10 +- .../listener/VelocityShutdownListener.kt | 10 +- 16 files changed, 515 insertions(+), 482 deletions(-) delete mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt delete mode 100644 surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt diff --git a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfCommonServerArgument.kt b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfCommonServerArgument.kt index 4711a2d..372f9f8 100644 --- a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfCommonServerArgument.kt +++ b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfCommonServerArgument.kt @@ -7,6 +7,7 @@ import com.velocitypowered.api.command.VelocityBrigadierMessage import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.CommandTree import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions import dev.jorel.commandapi.arguments.CommandAPIArgumentType import dev.jorel.commandapi.executors.CommandArguments import dev.slne.surf.api.core.messages.adventure.buildText @@ -19,6 +20,14 @@ open class SurfServerArgument(nodeName: String) : return CommonSurfServer::class.java } + init { + replaceSuggestions( + ArgumentSuggestions.stringCollection { _ -> + SurfCoreApi.getCommonServers().map { it.name } + } + ) + } + override fun getArgumentType(): CommandAPIArgumentType? { return CommandAPIArgumentType.PRIMITIVE_STRING } diff --git a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt index ef62b52..d66684b 100644 --- a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt +++ b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfOfflinePlayerArgument.kt @@ -2,7 +2,6 @@ package dev.slne.surf.core.api.velocity.command.argument import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.context.CommandContext -import com.velocitypowered.api.command.CommandSource import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.CommandTree import dev.jorel.commandapi.arguments.Argument @@ -35,13 +34,14 @@ open class SurfOfflinePlayerArgument(nodeName: String) : SurfCoreApi.getOfflinePlayer(StringArgumentType.getString(cmdCtx, key)) }.asDeferred() - override fun replaceSuggestions(suggestions: ArgumentSuggestions): Argument> = - super.replaceSuggestions( + init { + replaceSuggestions( ArgumentSuggestions.stringCollection { _ -> SurfCoreApi.getOnlinePlayers() .mapNotNull { it.lastKnownName } } ) + } companion object { private val log = logger() diff --git a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt index c1b0ea6..297e3d3 100644 --- a/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt +++ b/surf-core-api/surf-core-api-velocity/src/main/kotlin/dev/slne/surf/core/api/velocity/command/argument/SurfPlayerArgument.kt @@ -3,7 +3,6 @@ package dev.slne.surf.core.api.velocity.command.argument import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.exceptions.SimpleCommandExceptionType -import com.velocitypowered.api.command.CommandSource import com.velocitypowered.api.command.VelocityBrigadierMessage import dev.jorel.commandapi.CommandAPICommand import dev.jorel.commandapi.CommandTree @@ -39,13 +38,15 @@ open class SurfPlayerArgument(nodeName: String) : ) ).create() - override fun replaceSuggestions(suggestions: ArgumentSuggestions): Argument = - super.replaceSuggestions( + + init { + replaceSuggestions( ArgumentSuggestions.stringCollection { _ -> SurfCoreApi.getOnlinePlayers() .mapNotNull { it.lastKnownName } } ) + } } inline fun CommandTree.surfPlayerArgument( diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt index 554596c..0e469e3 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt @@ -7,13 +7,15 @@ import dev.slne.surf.redis.request.RequestContext object ExecuteCommandRedisListener { @HandleRedisRequest suspend fun handleExecuteCommandRequest(context: RequestContext) { - context.respond( - ExecuteCommandServerRequest.Response( - ExecuteCommandServerListener.executeCommand( - context.request.commonSurfServer, - context.request.command + ExecuteCommandServerListener.executeCommand( + context.request.commonSurfServer, + context.request.command + )?.let { + context.respond( + ExecuteCommandServerRequest.Response( + it ) ) - ) + } } } \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt index e7bf524..5182772 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt @@ -3,9 +3,11 @@ package dev.slne.surf.core.core.common.redis.listener import dev.slne.surf.api.core.util.requiredService import dev.slne.surf.core.api.common.server.CommonSurfServer +private val listener = requiredService() + interface ExecuteCommandServerListener { - suspend fun executeCommand(commonSurfServer: CommonSurfServer, command: String): Boolean + suspend fun executeCommand(commonSurfServer: CommonSurfServer, command: String): Boolean? companion object : - ExecuteCommandServerListener by requiredService() + ExecuteCommandServerListener by listener } \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt index 9e43809..e590457 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt @@ -4,8 +4,10 @@ import dev.slne.surf.api.core.util.requiredService import dev.slne.surf.core.api.common.server.CommonSurfServer import net.kyori.adventure.text.Component +private val listener = requiredService() + interface ShutdownServerListener { - fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean + fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean? - companion object : ShutdownServerListener by requiredService() + companion object : ShutdownServerListener by listener } \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt index 1275439..7e9dc89 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt @@ -7,13 +7,16 @@ import dev.slne.surf.redis.request.RequestContext object ShutdownServerRedisListener { @HandleRedisRequest fun handleShutdownRequest(context: RequestContext) { - context.respond( - ShutdownServerRequest.Response( - ShutdownServerListener.shutdown( - context.request.commonSurfServer, - context.request.reason + ShutdownServerListener.shutdown( + context.request.commonSurfServer, + context.request.reason + )?.let { + context.respond( + ShutdownServerRequest.Response( + it ) ) - ) + } + } } \ No newline at end of file diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/SurfCoreCommand.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/SurfCoreCommand.kt index 81eafcf..76a757e 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/SurfCoreCommand.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/SurfCoreCommand.kt @@ -17,7 +17,7 @@ import dev.slne.surf.core.paper.PaperBootstrap import dev.slne.surf.core.paper.permission.PermissionRegistry import dev.slne.surf.core.paper.plugin -fun surfCoreCommand() = commandTree("core") { +fun surfCoreCommand() = commandTree("surfcore") { withPermission(PermissionRegistry.COMMAND_CORE) literalArgument("reload") { anyExecutor { executor, _ -> diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt index fe11d6e..69b14f6 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt @@ -7,13 +7,13 @@ import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandServerListene import org.bukkit.Bukkit @AutoService(ExecuteCommandServerListener::class) -object PaperExecuteCommandListener : ExecuteCommandServerListener { +class PaperExecuteCommandListener : ExecuteCommandServerListener { override suspend fun executeCommand( commonSurfServer: CommonSurfServer, command: String - ): Boolean { + ): Boolean? { if (commonSurfServer.uuid != SurfServer.current().uuid) { - return false + return null } return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt index a307d2d..371e6a1 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt @@ -11,10 +11,10 @@ import net.kyori.adventure.text.Component import org.bukkit.Bukkit @AutoService(ShutdownServerListener::class) -object PaperShutdownListener : ShutdownServerListener { - override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean { +class PaperShutdownListener : ShutdownServerListener { + override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean? { if (commonSurfServer.uuid != SurfServer.current().uuid) { - return false + return null } forEachPlayer { player -> diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt index 4008823..db21f71 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/VelocityMain.kt @@ -31,7 +31,6 @@ import dev.slne.surf.core.velocity.command.coreCommand import dev.slne.surf.core.velocity.config.VelocityCoreConfigManager import dev.slne.surf.core.velocity.listener.ConnectionListener import dev.slne.surf.core.velocity.listener.VelocityServerListener -import dev.slne.surf.core.velocity.listener.VelocityShutdownListener import dev.slne.surf.core.velocity.redis.handler.SendPlayerToProxyHandler import dev.slne.surf.core.velocity.redis.handler.SendPlayerToServerHandler import dev.slne.surf.core.velocity.redis.listener.VelocityRedisListener @@ -64,7 +63,6 @@ class VelocityMain @Inject constructor( } AuthenticationService.init() - ClientCoreInstance.redisApi.registerRequestHandler(VelocityShutdownListener) ClientCoreInstance.clientLoader.withListener(VelocityRedisListener) ClientCoreInstance.clientLoader.withRequestResponseHandler(SendPlayerToProxyHandler) diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt index 65cdec3..bbde9c3 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt @@ -1,14 +1,34 @@ package dev.slne.surf.core.velocity.command -import dev.jorel.commandapi.kotlindsl.anyExecutor -import dev.jorel.commandapi.kotlindsl.commandAPICommand +import com.github.shynixn.mccoroutine.velocity.launch +import com.velocitypowered.api.proxy.ConsoleCommandSource +import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.api.core.messages.adventure.buildText +import dev.slne.surf.api.core.messages.adventure.clickRunsCommand import dev.slne.surf.api.core.messages.adventure.sendText +import dev.slne.surf.api.core.minimessage.miniMessage +import dev.slne.surf.api.core.util.dateTimeFormatter +import dev.slne.surf.api.velocity.command.executors.anyExecutorSuspend +import dev.slne.surf.api.velocity.command.executors.playerExecutorSuspend +import dev.slne.surf.core.api.common.player.SurfPlayer +import dev.slne.surf.core.api.common.server.CommonSurfServer +import dev.slne.surf.core.api.common.util.sendText +import dev.slne.surf.core.api.velocity.command.argument.surfPlayerArgument +import dev.slne.surf.core.api.velocity.command.argument.surfServerArgument +import dev.slne.surf.core.core.common.player.SurfPlayerService +import dev.slne.surf.core.core.common.server.SurfServerService import dev.slne.surf.core.core.common.util.appendCorePrefix +import dev.slne.surf.core.core.common.util.niceRed import dev.slne.surf.core.velocity.permission.PermissionList import dev.slne.surf.core.velocity.plugin +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.event.ClickEvent +import net.kyori.adventure.text.format.TextDecoration +import java.time.Duration +import java.time.OffsetDateTime import kotlin.jvm.optionals.getOrNull -fun coreCommand() = commandAPICommand("core") { +fun coreCommand() = commandTree("core") { withPermission(PermissionList.CORE_COMMAND) anyExecutor { source, _ -> @@ -35,6 +55,438 @@ fun coreCommand() = commandAPICommand("core") { } } - corePlayerCommand() - coreServiceCommand() + literalArgument("player") { + withPermission(PermissionList.CORE_COMMAND_PLAYER) + + literalArgument("#list") { + anyExecutor { source, _ -> + if (SurfPlayerService.players.isEmpty()) { + source.sendText { + appendCorePrefix() + error("Derzeit sind keine Spieler auf dem Netzwerk online.") + } + return@anyExecutor + } + + source.sendText { + appendCorePrefix() + info("Derzeit sind ") + variableValue(SurfPlayerService.players.size) + info(" Spieler auf dem Netzwerk online: ") + appendCollection(SurfPlayerService.players) { player -> + buildText { + variableValue(player.username) + clickRunsCommand("/core player ${player.username} info") + hoverEvent(buildText { + info("Online auf ") + variableValue("${player.currentServer?.name ?: "Unbekannt"} (${player.currentProxy?.name ?: "Unbekannt"})") + }) + } + } + } + } + } + + surfPlayerArgument("target") { + literalArgument("find") { + anyExecutor { source, arguments -> + val target: SurfPlayer by arguments + + source.sendText { + appendCorePrefix() + info("Der Spieler ") + variableValue(target.username) + info(" ist derzeit online auf ") + variableValue("${target.currentServer?.name ?: "Unbekannt"} (${target.currentProxy?.name ?: "Unbekannt"})") + info(". ") + + append { + spacer("[TP]") + clickRunsCommand("/ntp ${target.username}") + hoverEvent(buildText { + info("Teleportiere dich zu ${target.username}") + }) + } + } + } + } + + literalArgument("info") { + anyExecutor { source, arguments -> + val target: SurfPlayer by arguments + + source.sendText { + appendCorePrefix() + spacer("*") + spacer("-".repeat((30 - target.username.length) / 2)) + variableValue(target.username) + spacer("-".repeat((30 - target.username.length) / 2)) + spacer("*") + + appendNewline() + appendCorePrefix() + + appendNewline() + appendCorePrefix() + info("UUID: ") + variableValue(target.uuid.toString()) + + appendNewline() + appendCorePrefix() + info("Letzter Name: ") + variableValue(target.lastKnownName ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Aktueller Server: ") + variableValue(target.currentServer?.name ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Aktueller Proxy: ") + variableValue(target.currentProxy?.name ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Erstmals gesehen: ") + variableValue(target.firstSeen?.let { + dateTimeFormatter.format(it).toString() + } ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + info("Verbindung transferiert: ") + variableValue(target.transferred) + + appendNewline() + appendCorePrefix() + info("Ip Adresse: ") + variableValue(target.lastKnownIpAddress?.toString() ?: "Unbekannt") + + appendNewline() + appendCorePrefix() + + appendNewline() + appendCorePrefix() + spacer("*") + spacer("-".repeat(30)) + spacer("*") + } + } + } + + literalArgument("notify") { + textArgument("message") { + multiLiteralArgument( + "prefix", + "--moderation", + "--system", + "--warn", + optional = true + ) { + anyExecutor { source, arguments -> + val target: SurfPlayer by arguments + val message: String by arguments + val prefix: String? by arguments + + target.sendText { + appendCorePrefix() + append(findPrefix(prefix)) + append(miniMessage.deserialize(message)) + } + + source.sendText { + appendCorePrefix() + info("Die Nachricht wurde gesendet.") + } + } + } + } + } + } + } + + literalArgument("service") { + withPermission(PermissionList.CORE_COMMAND_SERVICE) + + literalArgument("#list") { + anyExecutor { source, _ -> + val services = SurfServerService.servers + + if (services.isEmpty()) { + source.sendText { + appendCorePrefix() + error("Derzeit sind keine Server auf dem Netzwerk online.") + } + return@anyExecutor + } + + source.sendText { + appendCorePrefix() + info("Derzeit sind ") + variableValue(services.size) + info(" Server aktiv: ") + appendCollection(services) { service -> + buildText { + variableValue(service.displayName) + clickRunsCommand("/core service ${service.name} info") + hoverEvent(buildText { + info("ID: ") + variableValue(service.uuid.toString()) + appendNewline() + info("Spieler: ") + variableValue("${service.getPlayerCount()}/${service.maxPlayers}") + }) + } + } + } + } + } + + + surfServerArgument("service") { + literalArgument("shutdown") { + textArgument("reason", optional = true) { + anyExecutorSuspend { source, arguments -> + val service: CommonSurfServer by arguments + val reason: String? by arguments + + if (source is ConsoleCommandSource || service.getPlayerCount() <= 5) { + source.sendText { + appendInfoPrefix() + info("Der Server ") + variableValue(service.name) + info(" wird heruntergefahren...") + } + + val result = + SurfServerService.shutdown( + service, + reason?.let { miniMessage.deserialize(it) }) + + if (result) { + source.sendText { + appendCorePrefix() + success("Der Server ") + variableValue(service.name) + success(" wurde erfolgreich heruntergefahren.") + } + } else { + source.sendText { + appendCorePrefix() + error("Der Server ") + variableValue(service.name) + error(" konnte nicht heruntergefahren werden.") + } + } + + return@anyExecutorSuspend + } + + source.sendText { + appendInfoPrefix() + info("Möchtest du wirklich den Server ") + variableValue(service.name) + info(" herunterfahren? Es sind derzeit ") + variableValue(service.getPlayerCount()) + info(" Spieler online! ") + append { + spacer("[") + success("Bestätigen") + spacer("]") + clickEvent(ClickEvent.callback { + plugin.pluginContainer.launch { + source.sendText { + appendInfoPrefix() + info("Der Server ") + variableValue(service.name) + info(" wird heruntergefahren...") + } + + val result = + SurfServerService.shutdown( + service, + reason?.let { miniMessage.deserialize(it) }) + + if (result) { + source.sendText { + appendCorePrefix() + success("Der Server ") + variableValue(service.name) + success(" wurde erfolgreich heruntergefahren.") + } + } else { + source.sendText { + appendCorePrefix() + error("Der Server ") + variableValue(service.name) + error(" konnte nicht heruntergefahren werden.") + } + } + } + }) + } + } + } + } + } + + literalArgument("info") { + anyExecutor { source, arguments -> + val service: CommonSurfServer by arguments + + source.sendText { + appendCorePrefix() + spacer("*") + spacer("-".repeat((30 - service.name.length) / 2)) + variableValue(service.name) + spacer("-".repeat((30 - service.name.length) / 2)) + spacer("*") + + appendNewline() + appendCorePrefix() + + appendNewline() + appendCorePrefix() + info("ID: ") + variableValue(service.uuid.toString()) + + appendNewline() + appendCorePrefix() + info("Interner Name: ") + variableValue(service.name) + + appendNewline() + appendCorePrefix() + info("Anzeigename: ") + variableValue(service.displayName) + + appendNewline() + appendCorePrefix() + info("Serverkategorie: ") + variableValue(service.category) + + appendNewline() + appendCorePrefix() + info("Servertyp: ") + variableValue(if (service.isProxy()) "Proxy" else "Backend") + + appendNewline() + appendCorePrefix() + info("Status: ") + variableValue(service.state.toString()) + + appendNewline() + appendCorePrefix() + info("Spieler: ") + variableValue("${service.getPlayerCount()}/${service.maxPlayers}") + + appendNewline() + appendCorePrefix() + info("Uptime: ") + variableValue( + formatDuration( + Duration.between( + service.startedAt, + OffsetDateTime.now() + ) + ) + ) + + appendNewline() + appendCorePrefix() + + + appendNewline() + appendCorePrefix() + spacer("*") + spacer("-".repeat(30)) + spacer("*") + } + } + } + + + literalArgument("sudo") { + textArgument("command") { + playerExecutorSuspend { player, arguments -> + val service: CommonSurfServer by arguments + val command: String by arguments + + if (blockedCommands.any { command.startsWith(it, ignoreCase = true) }) { + player.sendText { + appendCorePrefix() + error("Du darfst diesen Befehl nicht auf dem Server ") + variableValue(service.name) + error(" ausführen.") + } + return@playerExecutorSuspend + } + + val result = SurfServerService.executeCommand(service, command) + + if (result) { + player.sendText { + appendCorePrefix() + success("Der Befehl wurde erfolgreich auf dem Server ") + variableValue(service.name) + success(" ausgeführt.") + } + } else { + player.sendText { + appendCorePrefix() + error("Der Befehl konnte nicht auf dem Server ") + variableValue(service.name) + error(" ausgeführt werden.") + } + } + } + } + } + } + } +} + +private val blockedCommands = + listOf("lp", "lpv", "luckperms", "perm", "permission", "permissions", "luckpermsvelocity") + +private fun findPrefix(prefix: String?) = buildText { + when (prefix) { + "--moderation" -> { + spacer("[") + error("MODERATION") + spacer("]") + appendSpace() + } + + "--system" -> { + spacer("[") + variableValue("SYSTEM") + spacer("]") + appendSpace() + } + + "--warn" -> { + spacer("[") + niceRed("WARNUNG", TextDecoration.BOLD) + spacer("]") + appendSpace() + } + + else -> Component.empty() + } +} + +private fun formatDuration(duration: Duration): String { + val seconds = duration.seconds % 60 + val minutes = (duration.toMinutes() % 60) + val hours = (duration.toHours() % 24) + val days = duration.toDays() + + return buildString { + if (days > 0) append("${days}d ") + if (hours > 0) append("${hours}h ") + if (minutes > 0) append("${minutes}m ") + append("${seconds}s") + }.trim() } \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt deleted file mode 100644 index 55c5872..0000000 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CorePlayerCommand.kt +++ /dev/null @@ -1,185 +0,0 @@ -package dev.slne.surf.core.velocity.command - -import dev.jorel.commandapi.kotlindsl.* -import dev.slne.surf.api.core.messages.adventure.buildText -import dev.slne.surf.api.core.messages.adventure.clickRunsCommand -import dev.slne.surf.api.core.messages.adventure.sendText -import dev.slne.surf.api.core.minimessage.miniMessage -import dev.slne.surf.api.core.util.dateTimeFormatter -import dev.slne.surf.core.api.common.player.SurfPlayer -import dev.slne.surf.core.api.common.util.sendText -import dev.slne.surf.core.api.velocity.command.argument.surfPlayerArgument -import dev.slne.surf.core.core.common.player.SurfPlayerService -import dev.slne.surf.core.core.common.util.appendCorePrefix -import dev.slne.surf.core.core.common.util.niceRed -import dev.slne.surf.core.velocity.permission.PermissionList -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.format.TextDecoration - -fun corePlayerCommand() = subcommand("player") { - withPermission(PermissionList.CORE_COMMAND_PLAYER) - - literalArgument("list") { - anyExecutor { source, _ -> - if (SurfPlayerService.players.isEmpty()) { - source.sendText { - appendCorePrefix() - error("Derzeit sind keine Spieler auf dem Netzwerk online.") - } - return@anyExecutor - } - - source.sendText { - appendCorePrefix() - info("Derzeit sind ") - variableValue(SurfPlayerService.players.size) - info(" Spieler auf dem Netzwerk online:") - appendCollection(SurfPlayerService.players) { player -> - buildText { - variableValue(player.username) - clickRunsCommand("/core player ${player.username} info") - hoverEvent(buildText { - info("Online auf ") - variableValue("${player.currentServer?.name ?: "Unbekannt"} (${player.currentProxy?.name ?: "Unbekannt"})") - }) - } - } - } - } - } - - surfPlayerArgument("target") { - literalArgument("find") { - anyExecutor { source, arguments -> - val target: SurfPlayer by arguments - - source.sendText { - appendCorePrefix() - info("Der Spieler ") - variableValue(target.username) - info(" ist derzeit online auf ") - variableValue("${target.currentServer?.name ?: "Unbekannt"} (${target.currentProxy?.name ?: "Unbekannt"})") - info(". ") - - append { - spacer("[TP]") - clickRunsCommand("/ntp ${target.username}") - hoverEvent(buildText { - info("Teleportiere dich zu ${target.username}") - }) - } - } - } - } - - literalArgument("info") { - anyExecutor { source, arguments -> - val target: SurfPlayer by arguments - - source.sendText { - appendCorePrefix() - spacer("*") - spacer("-".repeat(30 - target.username.length / 2)) - variableValue(target.username) - spacer("-".repeat(30 - target.username.length / 2)) - spacer("*") - - appendNewline() - appendCorePrefix() - info("UUID: ") - variableValue(target.uuid.toString()) - - appendNewline() - appendCorePrefix() - info("Letzter Name: ") - variableValue(target.lastKnownName ?: "Unbekannt") - - appendNewline() - appendCorePrefix() - info("Aktueller Server: ") - variableValue(target.currentServer?.name ?: "Unbekannt") - - appendNewline() - appendCorePrefix() - info("Aktueller Proxy: ") - variableValue(target.currentProxy?.name ?: "Unbekannt") - - appendNewline() - appendCorePrefix() - info("Erstmals gesehen: ") - variableValue(target.firstSeen?.let { - dateTimeFormatter.format(it).toString() - } ?: "Unbekannt") - - appendNewline() - appendCorePrefix() - info("Verbindung transferiert: ") - variableValue(target.transferred) - - appendNewline() - appendCorePrefix() - info("Ip Adresse: ") - variableValue(target.lastKnownIpAddress?.toString() ?: "Unbekannt") - - - - appendNewline() - appendCorePrefix() - spacer("*") - spacer("-".repeat(30)) - spacer("*") - } - } - } - - literalArgument("notify") { - textArgument("message") - multiLiteralArgument("prefix", "--moderation", "--system", "--warn", optional = true) - - anyExecutor { source, arguments -> - val target: SurfPlayer by arguments - val message: String by arguments - val prefix: String? by arguments - - target.sendText { - appendCorePrefix() - appendSpace() - append(findPrefix(prefix)) - append(miniMessage.deserialize(message)) - } - - source.sendText { - appendCorePrefix() - info("Die Nachricht wurde an alle Spieler gesendet.") - } - } - } - } -} - -private fun findPrefix(prefix: String?) = buildText { - when (prefix) { - "--moderation" -> { - spacer("[") - error("MODERATION") - spacer("]") - appendSpace() - } - - "--system" -> { - spacer("[") - variableValue("SYSTEM") - spacer("]") - appendSpace() - } - - "--warn" -> { - spacer("[") - niceRed("WARNUNG", TextDecoration.BOLD) - spacer("]") - appendSpace() - } - - else -> Component.empty() - } -} \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt deleted file mode 100644 index ae024d2..0000000 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreServiceCommand.kt +++ /dev/null @@ -1,251 +0,0 @@ -package dev.slne.surf.core.velocity.command - -import com.github.shynixn.mccoroutine.velocity.launch -import com.velocitypowered.api.proxy.ConsoleCommandSource -import dev.jorel.commandapi.kotlindsl.* -import dev.slne.surf.api.core.messages.adventure.buildText -import dev.slne.surf.api.core.messages.adventure.clickRunsCommand -import dev.slne.surf.api.core.messages.adventure.sendText -import dev.slne.surf.api.core.minimessage.miniMessage -import dev.slne.surf.api.velocity.command.executors.anyExecutorSuspend -import dev.slne.surf.api.velocity.command.executors.playerExecutorSuspend -import dev.slne.surf.core.api.common.server.CommonSurfServer -import dev.slne.surf.core.api.velocity.command.argument.surfServerArgument -import dev.slne.surf.core.core.common.server.SurfServerService -import dev.slne.surf.core.core.common.util.appendCorePrefix -import dev.slne.surf.core.velocity.permission.PermissionList -import dev.slne.surf.core.velocity.plugin -import net.kyori.adventure.text.event.ClickEvent -import java.time.Duration -import java.time.OffsetDateTime - -fun coreServiceCommand() = subcommand("service") { - withPermission(PermissionList.CORE_COMMAND_SERVICE) - - literalArgument("list") { - anyExecutor { source, _ -> - val services = SurfServerService.servers - - if (services.isEmpty()) { - source.sendText { - appendCorePrefix() - error("Derzeit sind keine Server auf dem Netzwerk online.") - } - return@anyExecutor - } - - source.sendText { - appendCorePrefix() - info("Derzeit sind ") - variableValue(services.size) - info(" Server aktiv: ") - appendCollection(services) { service -> - buildText { - variableValue(service.displayName) - clickRunsCommand("/core service ${service.name} info") - hoverEvent(buildText { - info("ID: ") - variableValue(service.uuid.toString()) - appendNewline() - info("Spieler: ") - variableValue("${service.getPlayerCount()}/${service.maxPlayers}") - }) - } - } - } - } - } - - - surfServerArgument("service") { - literalArgument("shutdown") { - textArgument("reason", optional = true) { - anyExecutorSuspend { source, arguments -> - val service: CommonSurfServer by arguments - val reason: String? by arguments - - if (source is ConsoleCommandSource || service.getPlayerCount() <= 5) { - source.sendText { - appendInfoPrefix() - info("Der Server ") - variableValue(service.name) - info(" wird heruntergefahren...") - } - - val result = - SurfServerService.shutdown( - service, - reason?.let { miniMessage.deserialize(it) }) - - if (result) { - source.sendText { - appendCorePrefix() - success("Der Server ") - variableValue(service.name) - success(" wurde erfolgreich heruntergefahren.") - } - } else { - source.sendText { - appendCorePrefix() - error("Der Server ") - variableValue(service.name) - error(" konnte nicht heruntergefahren werden.") - } - } - - return@anyExecutorSuspend - } - - source.sendText { - appendInfoPrefix() - info("Möchtest du wirklich den Server ") - variableValue(service.name) - info(" herunterfahren? Es sind derzeit ") - variableValue(service.getPlayerCount()) - info(" Spieler online! ") - append { - spacer("[") - success("Bestätigen") - spacer("]") - clickEvent(ClickEvent.callback { - plugin.pluginContainer.launch { - source.sendText { - appendInfoPrefix() - info("Der Server ") - variableValue(service.name) - info(" wird heruntergefahren...") - } - - val result = - SurfServerService.shutdown( - service, - reason?.let { miniMessage.deserialize(it) }) - - if (result) { - source.sendText { - appendCorePrefix() - success("Der Server ") - variableValue(service.name) - success(" wurde erfolgreich heruntergefahren.") - } - } else { - source.sendText { - appendCorePrefix() - error("Der Server ") - variableValue(service.name) - error(" konnte nicht heruntergefahren werden.") - } - } - } - }) - } - } - } - } - } - - literalArgument("info") { - anyExecutor { source, arguments -> - val service: CommonSurfServer by arguments - - source.sendText { - appendCorePrefix() - spacer("*") - spacer("-".repeat(30 - service.name.length / 2)) - variableValue(service.name) - spacer("-".repeat(30 - service.name.length / 2)) - spacer("*") - - appendNewline() - appendCorePrefix() - info("ID: ") - variableValue(service.uuid.toString()) - - appendNewline() - appendCorePrefix() - info("Interner Name: ") - variableValue(service.name) - - appendNewline() - appendCorePrefix() - info("Anzeigename: ") - variableValue(service.displayName) - - appendNewline() - appendCorePrefix() - info("Serverkategorie: ") - variableValue(service.category) - - appendNewline() - appendCorePrefix() - info("Servertyp: ") - variableValue(if (service.isProxy()) "Proxy" else "Backend") - - appendNewline() - appendCorePrefix() - info("Status: ") - variableValue(service.state.toString()) - - appendNewline() - appendCorePrefix() - info("Spieler: ") - variableValue("${service.getPlayerCount()}/${service.maxPlayers}") - - appendNewline() - appendCorePrefix() - info("Uptime: ") - variableValue( - Duration.between(service.startedAt, OffsetDateTime.now()).toString() - ) - - appendNewline() - appendCorePrefix() - spacer("*") - spacer("-".repeat(30)) - spacer("*") - } - } - } - - - literalArgument("sudo") { - textArgument("command") - - playerExecutorSuspend { player, arguments -> - val service: CommonSurfServer by arguments - val command: String by arguments - - if (blockedCommands.any { command.startsWith(it, ignoreCase = true) }) { - player.sendText { - appendCorePrefix() - error("Du darfst diesen Befehl nicht auf dem Server ") - variableValue(service.name) - error(" ausführen.") - } - return@playerExecutorSuspend - } - - val result = SurfServerService.executeCommand(service, command) - - if (result) { - player.sendText { - appendCorePrefix() - success("Der Befehl wurde erfolgreich auf dem Server ") - variableValue(service.name) - success(" ausgeführt.") - } - } else { - player.sendText { - appendCorePrefix() - error("Der Befehl konnte nicht auf dem Server ") - variableValue(service.name) - error(" ausgeführt werden.") - } - } - } - } - } -} - -private val blockedCommands = - listOf("lp", "lpv", "luckperms", "perm", "permission", "permissions", "luckpermsvelocity") \ No newline at end of file diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt index ec2fe83..3fbe411 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt @@ -2,20 +2,20 @@ package dev.slne.surf.core.velocity.listener import com.google.auto.service.AutoService import dev.slne.surf.core.api.common.server.CommonSurfServer -import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.api.common.server.SurfProxyServer import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandServerListener import dev.slne.surf.core.velocity.plugin import dev.slne.surf.core.velocity.proxy import kotlinx.coroutines.future.await @AutoService(ExecuteCommandServerListener::class) -object VelocityExecuteCommandListener : ExecuteCommandServerListener { +class VelocityExecuteCommandListener : ExecuteCommandServerListener { override suspend fun executeCommand( commonSurfServer: CommonSurfServer, command: String - ): Boolean { - if (commonSurfServer.uuid != SurfServer.current().uuid) { - return false + ): Boolean? { + if (commonSurfServer.uuid != SurfProxyServer.current().uuid) { + return null } return plugin.proxy.commandManager.executeAsync(proxy.consoleCommandSource, command).await() diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt index 475614f..a514652 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt @@ -2,16 +2,16 @@ package dev.slne.surf.core.velocity.listener import com.google.auto.service.AutoService import dev.slne.surf.core.api.common.server.CommonSurfServer -import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.api.common.server.SurfProxyServer import dev.slne.surf.core.core.common.redis.listener.ShutdownServerListener import dev.slne.surf.core.velocity.plugin import net.kyori.adventure.text.Component @AutoService(ShutdownServerListener::class) -object VelocityShutdownListener : ShutdownServerListener { - override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean { - if (commonSurfServer.uuid != SurfServer.current().uuid) { - return false +class VelocityShutdownListener : ShutdownServerListener { + override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean? { + if (commonSurfServer.uuid != SurfProxyServer.current().uuid) { + return null } plugin.proxy.shutdown(reason) From 666931a1cc8220dcec3da16d59305a3b4f87c64c Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sun, 26 Apr 2026 09:08:32 +0200 Subject: [PATCH 04/14] feat: add player join event handler to customize display name --- .../surf/core/paper/listener/PlayerConnectListener.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt index e0b9be5..02db860 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt @@ -4,6 +4,7 @@ import com.github.shynixn.mccoroutine.folia.launch import com.github.shynixn.mccoroutine.folia.scope import dev.slne.surf.api.core.messages.adventure.* import dev.slne.surf.api.paper.command.util.idOrThrow +import dev.slne.surf.api.paper.util.getPrefixedName import dev.slne.surf.core.api.common.server.connection.SurfProxyServerConnectionResult import dev.slne.surf.core.api.paper.util.surfPlayer import dev.slne.surf.core.core.CoreInstance @@ -128,6 +129,13 @@ object PlayerConnectListener : Listener { } } + @EventHandler + fun onJoin(event: PlayerJoinEvent) { + event.player.displayName(buildText { + append(event.player.getPrefixedName()) + }) + } + private fun buildDisconnectComponent(errorCode: String) = buildText { appendNewline(2) primary("CASTCRAFTER") From cecb2ce297be731a4d74ee45ae4be30c453d3474 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Sun, 26 Apr 2026 12:03:34 +0200 Subject: [PATCH 05/14] feat: integrate LuckPerms event handling to update player display names --- .../dev/slne/surf/core/paper/PaperMain.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperMain.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperMain.kt index 892b11a..bf56c91 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperMain.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperMain.kt @@ -1,7 +1,9 @@ package dev.slne.surf.core.paper import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin +import dev.slne.surf.api.core.luckperms.LuckPermsAccess import dev.slne.surf.api.paper.event.register +import dev.slne.surf.api.paper.util.getPrefixedName import dev.slne.surf.core.api.common.event.SurfServerOnlineEvent import dev.slne.surf.core.api.common.event.SurfServerStoppingEvent import dev.slne.surf.core.api.common.server.SurfServer @@ -13,6 +15,7 @@ import dev.slne.surf.core.paper.command.* import dev.slne.surf.core.paper.event.SurfServerEventListener import dev.slne.surf.core.paper.listener.PlayerConnectListener import dev.slne.surf.core.paper.task.surfServerInformationSyncTask +import net.luckperms.api.event.user.UserDataRecalculateEvent import org.bukkit.Bukkit import org.bukkit.plugin.java.JavaPlugin @@ -47,6 +50,9 @@ class PaperMain : SuspendingJavaPlugin() { SurfServer.current().copy(maxPlayers = Bukkit.getMaxPlayers()) ) + + luckPerms() + surfServerInformationSyncTask.start() } @@ -58,4 +64,16 @@ class PaperMain : SuspendingJavaPlugin() { ClientCoreInstance.clientLoader.onDisable() } + + + private fun luckPerms() { + LuckPermsAccess.luckperms.eventBus.subscribe( + plugin, + UserDataRecalculateEvent::class.java + ) { event -> + Bukkit.getPlayer(event.user.uniqueId)?.let { + it.displayName(it.getPrefixedName()) + } + } + } } \ No newline at end of file From 99f8bdeeee333542fa60d6827a4d08dbf9dfb81d Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Mon, 27 Apr 2026 17:06:40 +0200 Subject: [PATCH 06/14] feat: add SurfPlayerErrorsTable to database table imports in CoreMicroservice --- .../dev/slne/surf/core/microservice/CoreMicroservice.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/CoreMicroservice.kt b/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/CoreMicroservice.kt index 787478e..130a764 100644 --- a/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/CoreMicroservice.kt +++ b/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/CoreMicroservice.kt @@ -1,10 +1,7 @@ package dev.slne.surf.core.microservice import com.google.auto.service.AutoService -import dev.slne.surf.core.microservice.database.tables.SurfPlayerIpAddressHistoriesTable -import dev.slne.surf.core.microservice.database.tables.SurfPlayerNameHistoriesTable -import dev.slne.surf.core.microservice.database.tables.SurfPlayerTexturesHistoriesTable -import dev.slne.surf.core.microservice.database.tables.SurfPlayersTable +import dev.slne.surf.core.microservice.database.tables.* import dev.slne.surf.core.microservice.rabbit.* import dev.slne.surf.database.DatabaseApi import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.SchemaUtils @@ -25,7 +22,8 @@ class CoreMicroservice : Microservice() { SurfPlayerIpAddressHistoriesTable, SurfPlayerNameHistoriesTable, SurfPlayersTable, - SurfPlayerTexturesHistoriesTable + SurfPlayerTexturesHistoriesTable, + SurfPlayerErrorsTable ) } From 980472d324bca930e44d70571e3f683adae13d49 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Mon, 27 Apr 2026 17:13:43 +0200 Subject: [PATCH 07/14] feat: enhance SurfPlayerErrorHandler to respond with error details after saving --- .../rabbit/SurfPlayerErrorHandler.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/rabbit/SurfPlayerErrorHandler.kt b/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/rabbit/SurfPlayerErrorHandler.kt index 7cc937b..8cd8ec6 100644 --- a/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/rabbit/SurfPlayerErrorHandler.kt +++ b/surf-core-microservice/src/main/kotlin/dev/slne/surf/core/microservice/rabbit/SurfPlayerErrorHandler.kt @@ -1,6 +1,7 @@ package dev.slne.surf.core.microservice.rabbit import dev.slne.surf.core.core.common.rabbit.packet.player.error.SaveSurfPlayerErrorRequestPacket +import dev.slne.surf.core.core.common.rabbit.packet.player.error.SingleSurfPlayerErrorResponsePacket import dev.slne.surf.core.microservice.database.repository.SurfPlayerErrorRepository import dev.slne.surf.rabbitmq.api.handler.RabbitHandler import kotlinx.coroutines.launch @@ -8,12 +9,16 @@ import kotlinx.coroutines.launch object SurfPlayerErrorHandler { @RabbitHandler fun handleSavePlayerError(packet: SaveSurfPlayerErrorRequestPacket) = packet.launch { - SurfPlayerErrorRepository.saveError( - playerUuid = packet.playerUuid, - occurredOn = packet.occurredOn, - occurredAt = packet.occurredAt, - staffMessage = packet.staffMessage, - errorCode = packet.errorCode + packet.respond( + SingleSurfPlayerErrorResponsePacket( + SurfPlayerErrorRepository.saveError( + playerUuid = packet.playerUuid, + occurredOn = packet.occurredOn, + occurredAt = packet.occurredAt, + staffMessage = packet.staffMessage, + errorCode = packet.errorCode + ) + ) ) } } \ No newline at end of file From 76c2b14c57f88496e9fe8857df10530d430d8bbd Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Fri, 1 May 2026 15:53:41 +0200 Subject: [PATCH 08/14] feat: update network broadcast command to include formatted info prefix --- .../slne/surf/core/paper/command/NetworkBroadcastCommand.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt index fe16b5a..88e42d3 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt @@ -8,7 +8,9 @@ import dev.slne.surf.api.core.messages.adventure.sendText import dev.slne.surf.core.api.common.SurfCoreApi import dev.slne.surf.core.api.common.util.sendText import dev.slne.surf.core.core.common.util.appendCorePrefix +import dev.slne.surf.core.core.common.util.niceRed import dev.slne.surf.core.paper.permission.PermissionRegistry +import net.kyori.adventure.text.format.TextDecoration import net.kyori.adventure.text.minimessage.MiniMessage fun networkBroadcastCommand() = commandTree("nbroadcast") { @@ -19,7 +21,8 @@ fun networkBroadcastCommand() = commandTree("nbroadcast") { SurfCoreApi.getOnlinePlayers().forEach { it.sendText { - appendCorePrefix() + appendNewline() + niceRed("INFO: ", TextDecoration.BOLD) append(MiniMessage.miniMessage().deserialize(message)) } } From 6b2eec37c56d5d5c080c8b3c173bdf848b6c8419 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Fri, 1 May 2026 15:59:08 +0200 Subject: [PATCH 09/14] feat: add newline after info message in NetworkBroadcastCommand --- .../dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt index 88e42d3..eaeb36c 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt @@ -24,6 +24,7 @@ fun networkBroadcastCommand() = commandTree("nbroadcast") { appendNewline() niceRed("INFO: ", TextDecoration.BOLD) append(MiniMessage.miniMessage().deserialize(message)) + appendNewline() } } From 780221931dd56008d17b64bb02e8115255344517 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Fri, 1 May 2026 16:07:52 +0200 Subject: [PATCH 10/14] feat: add core prefix to info messages in NetworkBroadcastCommand --- .../slne/surf/core/paper/command/NetworkBroadcastCommand.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt index eaeb36c..91c1387 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/command/NetworkBroadcastCommand.kt @@ -21,10 +21,15 @@ fun networkBroadcastCommand() = commandTree("nbroadcast") { SurfCoreApi.getOnlinePlayers().forEach { it.sendText { + appendCorePrefix() + appendNewline() + appendCorePrefix() niceRed("INFO: ", TextDecoration.BOLD) append(MiniMessage.miniMessage().deserialize(message)) + appendNewline() + appendCorePrefix() } } From fb3b2e551756925dc41bd85504caf364491eb783 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Tue, 5 May 2026 08:13:57 +0200 Subject: [PATCH 11/14] feat: implement CorePlayerInfoProvider interface and default implementation for server info --- .../core/api/paper/CorePlayerInfoProvider.kt | 38 +++++++++++++++++++ .../slne/surf/core/paper/PaperBootstrap.kt | 4 ++ .../api/DefaultCorePlayerInfoProvider.kt | 23 +++++++++++ 3 files changed, 65 insertions(+) create mode 100644 surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt create mode 100644 surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt diff --git a/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt b/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt new file mode 100644 index 0000000..561a7f9 --- /dev/null +++ b/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt @@ -0,0 +1,38 @@ +package dev.slne.surf.core.api.paper + +import dev.slne.surf.core.api.paper.CorePlayerInfoProvider.Companion.getServerInfo +import java.util.* + +interface CorePlayerInfoProvider { + fun createServerInfo(playerUuid: UUID): ServerInfo? + + /** + * Server Info data class containing the server name, nice name and region. This is used to provide information about the server a player is currently on. + * + * @param serverName The name of the server the player is currently on. + * @param serverNiceName The nice name of the server the player is currently on. + * @param serverRegion The region of the server the player is currently on. + * + * NOTE: This method should not be used to gain access to players current server. Use [dev.slne.surf.core.api.common.player.SurfPlayer.currentServer] instead. + * + * @see [getServerInfo] + */ + data class ServerInfo( + val serverName: String, + val serverNiceName: String, + val serverRegion: String + ) + + companion object { + private lateinit var instance: CorePlayerInfoProvider + + fun setInstance(provider: CorePlayerInfoProvider) { + instance = provider + } + + /** + * Available after plugin bootstrapper + */ + fun getServerInfo(playerUuid: UUID) = instance.createServerInfo(playerUuid) + } +} \ No newline at end of file diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperBootstrap.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperBootstrap.kt index f70a85b..3dbca9c 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperBootstrap.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/PaperBootstrap.kt @@ -3,11 +3,13 @@ package dev.slne.surf.core.paper import dev.slne.surf.core.api.common.event.SurfServerStartEvent import dev.slne.surf.core.api.common.server.SurfServer import dev.slne.surf.core.api.common.server.state.SurfServerState +import dev.slne.surf.core.api.paper.CorePlayerInfoProvider import dev.slne.surf.core.client.ClientCoreInstance import dev.slne.surf.core.core.CoreInstance import dev.slne.surf.core.core.common.config.SurfServerConfiguration import dev.slne.surf.core.core.common.event.SurfEventBus import dev.slne.surf.core.core.common.server.SurfServerService +import dev.slne.surf.core.paper.api.DefaultCorePlayerInfoProvider import dev.slne.surf.core.paper.redis.listener.PaperRedisListener import dev.slne.surf.core.paper.teleport.TeleportRedisListener import io.papermc.paper.plugin.bootstrap.BootstrapContext @@ -46,6 +48,8 @@ class PaperBootstrap : PluginBootstrap { SurfEventBus.fire(SurfServerStartEvent(surfServerConfig.serverName)) SurfServerService.addServer(server) + + CorePlayerInfoProvider.setInstance(DefaultCorePlayerInfoProvider) } companion object { diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt new file mode 100644 index 0000000..fb67072 --- /dev/null +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt @@ -0,0 +1,23 @@ +package dev.slne.surf.core.paper.api + +import dev.slne.surf.core.api.common.server.SurfServer +import dev.slne.surf.core.api.paper.CorePlayerInfoProvider +import org.bukkit.Bukkit +import org.bukkit.World +import java.util.* + +object DefaultCorePlayerInfoProvider : CorePlayerInfoProvider { + override fun createServerInfo(playerUuid: UUID): CorePlayerInfoProvider.ServerInfo? { + val player = Bukkit.getPlayer(playerUuid) ?: return null + + return CorePlayerInfoProvider.ServerInfo( + serverName = SurfServer.current().name, + serverNiceName = SurfServer.current().displayName, + serverRegion = when (player.world.environment) { + World.Environment.NETHER -> "Nether" + World.Environment.THE_END -> "End" + else -> "Overworld" + } + ) + } +} \ No newline at end of file From 9030b15d3bbd3d6b722319e0c042c03e46eb0404 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft <143264463+TheBjoRedCraft@users.noreply.github.com> Date: Thu, 7 May 2026 15:57:21 +0200 Subject: [PATCH 12/14] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../velocity/listener/VelocityShutdownListener.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt index a514652..576b6e0 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt @@ -14,7 +14,17 @@ class VelocityShutdownListener : ShutdownServerListener { return null } - plugin.proxy.shutdown(reason) + val shutdownThread = Thread { + try { + Thread.sleep(100) + } catch (_: InterruptedException) { + Thread.currentThread().interrupt() + } + + plugin.proxy.shutdown(reason) + } + shutdownThread.isDaemon = false + shutdownThread.start() return true } } \ No newline at end of file From 879f65e6bae89c1a623448a786b74a4e193141aa Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Thu, 7 May 2026 16:11:54 +0200 Subject: [PATCH 13/14] fix: update server display name in ServerInfo and improve core version retrieval --- .../core/api/paper/CorePlayerInfoProvider.kt | 4 ++-- .../listener/ExecuteCommandRedisListener.kt | 2 +- ...rverListener.kt => RemoteCommandExecutor.kt} | 6 +++--- ...rverListener.kt => ServerShutdownHandler.kt} | 6 +++--- .../listener/ShutdownServerRedisListener.kt | 2 +- .../paper/api/DefaultCorePlayerInfoProvider.kt | 2 +- ...istener.kt => PaperRemoteCommandListener.kt} | 13 +++++++++---- ...tdownListener.kt => PaperShutdownHandler.kt} | 10 ++++++---- surf-core-velocity/build.gradle.kts | 1 - .../surf/core/velocity/command/CoreCommand.kt | 17 +++++++++-------- ...ener.kt => VelocityRemoteCommandListener.kt} | 6 +++--- ...wnListener.kt => VelocityShutdownHandler.kt} | 6 +++--- 12 files changed, 41 insertions(+), 34 deletions(-) rename surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/{ExecuteCommandServerListener.kt => RemoteCommandExecutor.kt} (64%) rename surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/{ShutdownServerListener.kt => ServerShutdownHandler.kt} (65%) rename surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/{PaperExecuteCommandListener.kt => PaperRemoteCommandListener.kt} (50%) rename surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/{PaperShutdownListener.kt => PaperShutdownHandler.kt} (83%) rename surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/{VelocityExecuteCommandListener.kt => VelocityRemoteCommandListener.kt} (76%) rename surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/{VelocityShutdownListener.kt => VelocityShutdownHandler.kt} (82%) diff --git a/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt b/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt index 561a7f9..05de044 100644 --- a/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt +++ b/surf-core-api/surf-core-api-paper/src/main/kotlin/dev/slne/surf/core/api/paper/CorePlayerInfoProvider.kt @@ -10,7 +10,7 @@ interface CorePlayerInfoProvider { * Server Info data class containing the server name, nice name and region. This is used to provide information about the server a player is currently on. * * @param serverName The name of the server the player is currently on. - * @param serverNiceName The nice name of the server the player is currently on. + * @param serverDisplayName The nice name of the server the player is currently on. * @param serverRegion The region of the server the player is currently on. * * NOTE: This method should not be used to gain access to players current server. Use [dev.slne.surf.core.api.common.player.SurfPlayer.currentServer] instead. @@ -19,7 +19,7 @@ interface CorePlayerInfoProvider { */ data class ServerInfo( val serverName: String, - val serverNiceName: String, + val serverDisplayName: String, val serverRegion: String ) diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt index 0e469e3..b6956a2 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandRedisListener.kt @@ -7,7 +7,7 @@ import dev.slne.surf.redis.request.RequestContext object ExecuteCommandRedisListener { @HandleRedisRequest suspend fun handleExecuteCommandRequest(context: RequestContext) { - ExecuteCommandServerListener.executeCommand( + RemoteCommandExecutor.executeCommand( context.request.commonSurfServer, context.request.command )?.let { diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/RemoteCommandExecutor.kt similarity index 64% rename from surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt rename to surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/RemoteCommandExecutor.kt index 5182772..18239bd 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ExecuteCommandServerListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/RemoteCommandExecutor.kt @@ -3,11 +3,11 @@ package dev.slne.surf.core.core.common.redis.listener import dev.slne.surf.api.core.util.requiredService import dev.slne.surf.core.api.common.server.CommonSurfServer -private val listener = requiredService() +private val listener = requiredService() -interface ExecuteCommandServerListener { +interface RemoteCommandExecutor { suspend fun executeCommand(commonSurfServer: CommonSurfServer, command: String): Boolean? companion object : - ExecuteCommandServerListener by listener + RemoteCommandExecutor by listener } \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ServerShutdownHandler.kt similarity index 65% rename from surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt rename to surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ServerShutdownHandler.kt index e590457..a5335b2 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ServerShutdownHandler.kt @@ -4,10 +4,10 @@ import dev.slne.surf.api.core.util.requiredService import dev.slne.surf.core.api.common.server.CommonSurfServer import net.kyori.adventure.text.Component -private val listener = requiredService() +private val listener = requiredService() -interface ShutdownServerListener { +interface ServerShutdownHandler { fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean? - companion object : ShutdownServerListener by listener + companion object : ServerShutdownHandler by listener } \ No newline at end of file diff --git a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt index 7e9dc89..4658d4f 100644 --- a/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt +++ b/surf-core-core/surf-core-core-common/src/main/kotlin/dev/slne/surf/core/core/common/redis/listener/ShutdownServerRedisListener.kt @@ -7,7 +7,7 @@ import dev.slne.surf.redis.request.RequestContext object ShutdownServerRedisListener { @HandleRedisRequest fun handleShutdownRequest(context: RequestContext) { - ShutdownServerListener.shutdown( + ServerShutdownHandler.shutdown( context.request.commonSurfServer, context.request.reason )?.let { diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt index fb67072..a313ebf 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/api/DefaultCorePlayerInfoProvider.kt @@ -12,7 +12,7 @@ object DefaultCorePlayerInfoProvider : CorePlayerInfoProvider { return CorePlayerInfoProvider.ServerInfo( serverName = SurfServer.current().name, - serverNiceName = SurfServer.current().displayName, + serverDisplayName = SurfServer.current().displayName, serverRegion = when (player.world.environment) { World.Environment.NETHER -> "Nether" World.Environment.THE_END -> "End" diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperRemoteCommandListener.kt similarity index 50% rename from surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt rename to surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperRemoteCommandListener.kt index 69b14f6..8792beb 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperExecuteCommandListener.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperRemoteCommandListener.kt @@ -1,13 +1,16 @@ package dev.slne.surf.core.paper.listener +import com.github.shynixn.mccoroutine.folia.globalRegionDispatcher import com.google.auto.service.AutoService import dev.slne.surf.core.api.common.server.CommonSurfServer import dev.slne.surf.core.api.common.server.SurfServer -import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandServerListener +import dev.slne.surf.core.core.common.redis.listener.RemoteCommandExecutor +import dev.slne.surf.core.paper.plugin +import kotlinx.coroutines.withContext import org.bukkit.Bukkit -@AutoService(ExecuteCommandServerListener::class) -class PaperExecuteCommandListener : ExecuteCommandServerListener { +@AutoService(RemoteCommandExecutor::class) +class PaperRemoteCommandListener : RemoteCommandExecutor { override suspend fun executeCommand( commonSurfServer: CommonSurfServer, command: String @@ -16,6 +19,8 @@ class PaperExecuteCommandListener : ExecuteCommandServerListener { return null } - return Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command) + return withContext(plugin.globalRegionDispatcher) { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command) + } } } \ No newline at end of file diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownHandler.kt similarity index 83% rename from surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt rename to surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownHandler.kt index 371e6a1..3e1f9b2 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownListener.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PaperShutdownHandler.kt @@ -6,19 +6,21 @@ import dev.slne.surf.api.core.messages.adventure.buildText import dev.slne.surf.api.paper.util.forEachPlayer import dev.slne.surf.core.api.common.server.CommonSurfServer import dev.slne.surf.core.api.common.server.SurfServer -import dev.slne.surf.core.core.common.redis.listener.ShutdownServerListener +import dev.slne.surf.core.core.common.redis.listener.ServerShutdownHandler import net.kyori.adventure.text.Component import org.bukkit.Bukkit -@AutoService(ShutdownServerListener::class) -class PaperShutdownListener : ShutdownServerListener { +@AutoService(ServerShutdownHandler::class) +class PaperShutdownHandler : ServerShutdownHandler { override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean? { if (commonSurfServer.uuid != SurfServer.current().uuid) { return null } + val msg = buildDisconnectComponent(reason) + forEachPlayer { player -> - player.kick(buildDisconnectComponent(reason)) + player.kick(msg) } Bukkit.shutdown() diff --git a/surf-core-velocity/build.gradle.kts b/surf-core-velocity/build.gradle.kts index cd53ce4..25f15c0 100644 --- a/surf-core-velocity/build.gradle.kts +++ b/surf-core-velocity/build.gradle.kts @@ -9,7 +9,6 @@ surfVelocityApi { velocityPluginFile { main = "dev.slne.surf.core.velocity.VelocityMain" authors = listOf("red") - version = findProperty("version") as String pluginDependencies { register("surf-rabbitmq-velocity") diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt index bbde9c3..f6c1fa6 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/command/CoreCommand.kt @@ -3,6 +3,7 @@ package dev.slne.surf.core.velocity.command import com.github.shynixn.mccoroutine.velocity.launch import com.velocitypowered.api.proxy.ConsoleCommandSource import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.api.core.messages.CommonComponents import dev.slne.surf.api.core.messages.adventure.buildText import dev.slne.surf.api.core.messages.adventure.clickRunsCommand import dev.slne.surf.api.core.messages.adventure.sendText @@ -26,15 +27,14 @@ import net.kyori.adventure.text.event.ClickEvent import net.kyori.adventure.text.format.TextDecoration import java.time.Duration import java.time.OffsetDateTime -import kotlin.jvm.optionals.getOrNull +import kotlin.jvm.optionals.getOrElse +import kotlin.time.toKotlinDuration fun coreCommand() = commandTree("core") { withPermission(PermissionList.CORE_COMMAND) anyExecutor { source, _ -> - val coreVersion = - plugin.pluginManager.getPlugin("surf-core-velocity") - .getOrNull()?.description?.version?.getOrNull() ?: "Unbekannt" + val coreVersion = plugin.pluginContainer.description.version.getOrElse { "#Unknown" } val platform = plugin.proxy.version.name val platformVersion = plugin.proxy.version.version val vendor = plugin.proxy.version.vendor @@ -384,19 +384,20 @@ fun coreCommand() = commandTree("core") { appendNewline() appendCorePrefix() info("Uptime: ") - variableValue( - formatDuration( + append( + CommonComponents.formatTime( Duration.between( service.startedAt, OffsetDateTime.now() - ) + ).toKotlinDuration(), + showSeconds = true, + shortForms = false ) ) appendNewline() appendCorePrefix() - appendNewline() appendCorePrefix() spacer("*") diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityRemoteCommandListener.kt similarity index 76% rename from surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt rename to surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityRemoteCommandListener.kt index 3fbe411..3292bd2 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityExecuteCommandListener.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityRemoteCommandListener.kt @@ -3,13 +3,13 @@ package dev.slne.surf.core.velocity.listener import com.google.auto.service.AutoService import dev.slne.surf.core.api.common.server.CommonSurfServer import dev.slne.surf.core.api.common.server.SurfProxyServer -import dev.slne.surf.core.core.common.redis.listener.ExecuteCommandServerListener +import dev.slne.surf.core.core.common.redis.listener.RemoteCommandExecutor import dev.slne.surf.core.velocity.plugin import dev.slne.surf.core.velocity.proxy import kotlinx.coroutines.future.await -@AutoService(ExecuteCommandServerListener::class) -class VelocityExecuteCommandListener : ExecuteCommandServerListener { +@AutoService(RemoteCommandExecutor::class) +class VelocityRemoteCommandListener : RemoteCommandExecutor { override suspend fun executeCommand( commonSurfServer: CommonSurfServer, command: String diff --git a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownHandler.kt similarity index 82% rename from surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt rename to surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownHandler.kt index 576b6e0..042ef8a 100644 --- a/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownListener.kt +++ b/surf-core-velocity/src/main/kotlin/dev/slne/surf/core/velocity/listener/VelocityShutdownHandler.kt @@ -3,12 +3,12 @@ package dev.slne.surf.core.velocity.listener import com.google.auto.service.AutoService import dev.slne.surf.core.api.common.server.CommonSurfServer import dev.slne.surf.core.api.common.server.SurfProxyServer -import dev.slne.surf.core.core.common.redis.listener.ShutdownServerListener +import dev.slne.surf.core.core.common.redis.listener.ServerShutdownHandler import dev.slne.surf.core.velocity.plugin import net.kyori.adventure.text.Component -@AutoService(ShutdownServerListener::class) -class VelocityShutdownListener : ShutdownServerListener { +@AutoService(ServerShutdownHandler::class) +class VelocityShutdownHandler : ServerShutdownHandler { override fun shutdown(commonSurfServer: CommonSurfServer, reason: Component?): Boolean? { if (commonSurfServer.uuid != SurfProxyServer.current().uuid) { return null From 4e8e97c2eb9aa81b5bbca4bffb3a67875aea6561 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Thu, 7 May 2026 16:12:32 +0200 Subject: [PATCH 14/14] refactor: simplify player display name handling in onJoin event --- .../slne/surf/core/paper/listener/PlayerConnectListener.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt index 02db860..5d8fb3a 100644 --- a/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt +++ b/surf-core-paper/src/main/kotlin/dev/slne/surf/core/paper/listener/PlayerConnectListener.kt @@ -131,9 +131,7 @@ object PlayerConnectListener : Listener { @EventHandler fun onJoin(event: PlayerJoinEvent) { - event.player.displayName(buildText { - append(event.player.getPrefixedName()) - }) + event.player.displayName(event.player.getPrefixedName()) } private fun buildDisconnectComponent(errorCode: String) = buildText {