diff --git a/.gitignore b/.gitignore index a5b1113..8d9649f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ gradle-app.setting .project # JDT-specific (Eclipse Java Development Tools) .classpath + +.idea/ + +.kotlin/ \ No newline at end of file diff --git a/README.md b/README.md index 60a1c45..c03492f 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,9 @@ This repository is licensed under [Apache 2.0][license]. [banner]: https://github.com/simplecloudapp/branding/blob/main/readme/banner/plugin/cloud-command.png?raw=true -[issue-bug-report]: https://github.com/theSimpleCloud/command-plugin/issues/new?labels=bug&projects=template=01_BUG-REPORT.yml&title=%5BBUG%5D+%3Ctitle%3E -[issue-feature-request]: https://github.com/theSimpleCloud/command-plugin/discussions/new?category=ideas -[docs-thisproject]: https://docs.simplecloud.app/plugin/cloud-command +[issue-bug-report]: https://github.com/simplecloudapp/command-plugin/issues/new?labels=bug&projects=template=01_BUG-REPORT.yml&title=%5BBUG%5D+%3Ctitle%3E +[issue-feature-request]: https://github.com/simplecloudapp/command-plugin/discussions/new?category=ideas +[docs-thisproject]: https://docs.simplecloud.app/en/manual/plugin/cloud-command [docs-contribute]: https://docs.simplecloud.app/contribute [modrinth]: https://modrinth.com/plugin/command-plugin diff --git a/build.gradle.kts b/build.gradle.kts index 7865ec7..ce4b160 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,6 +20,7 @@ allprojects { maven("https://buf.build/gen/maven") maven("https://repo.simplecloud.app/snapshots") maven("https://repo.papermc.io/repository/maven-public/") + maven("https://repo.simplecloud.app/snapshots") } } @@ -31,7 +32,8 @@ subprojects { dependencies { testImplementation(rootProject.libs.kotlin.test) - compileOnly(rootProject.libs.kotlin.jvm) + implementation(rootProject.libs.kotlin.jvm) + implementation(rootProject.libs.kotlinx.coroutines.core) } publishing { @@ -55,27 +57,11 @@ subprojects { } tasks.named("shadowJar", ShadowJar::class) { - dependencies { - exclude(dependency("com.velocitypowered:velocity-api")) - - relocate("org.incendo", "app.simplecloud.plugin.command.relocate.incendo") - relocate("org.spongepowered", "app.simplecloud.plugin.command.relocate.spongepowered") - relocate("app.simplecloud.plugin.api", "app.simplecloud.plugin.command.relocate.plugin.api") - } - /* dependsOn("processResources") - dependencies { - include(project(":command-shared")) - - /** - * TODO: Add dependencies ADDED BY YOU like this: - * include(dependency(libs.your.dependency.get())) - */ - include(dependency(libs.cloud.core.get())) - // TODO: only include the velocity dependency in the velocity plugin - include(dependency(libs.cloud.velocity.get())) - - } */ + mergeServiceFiles() + relocate("org.incendo", "app.simplecloud.plugin.command.relocate.incendo") + relocate("org.spongepowered", "app.simplecloud.plugin.command.relocate.spongepowered") archiveFileName.set("${project.name}.jar") + archiveClassifier.set("") } } diff --git a/command-bungeecord/build.gradle.kts b/command-bungeecord/build.gradle.kts index fab9f1d..f9611e6 100644 --- a/command-bungeecord/build.gradle.kts +++ b/command-bungeecord/build.gradle.kts @@ -3,10 +3,10 @@ plugins { } dependencies { - api(project(":command-shared")) - api(libs.bungeecord.api) - api(libs.adveture.platform.bungeecord) - api(libs.cloud.bungeecord) + implementation(project(":command-shared")) + implementation(libs.adveture.platform.bungeecord) + implementation(libs.cloud.bungeecord) + compileOnly(libs.bungeecord.api) } modrinth { @@ -16,8 +16,6 @@ modrinth { versionType.set("beta") uploadFile.set(tasks.shadowJar) gameVersions.addAll( - - "1.20", "1.20.1", "1.20.2", @@ -36,8 +34,7 @@ modrinth { "1.21.8", "1.21.9", "1.21.10", - - + "1.21.11" ) loaders.add("bungeecord") loaders.add("waterfall") diff --git a/command-bungeecord/src/main/kotlin/app/simplecloud/plugin/command/bungeecord/BungeeCordPlugin.kt b/command-bungeecord/src/main/kotlin/app/simplecloud/plugin/command/bungeecord/BungeeCordPlugin.kt index 4ff472d..64d81f1 100644 --- a/command-bungeecord/src/main/kotlin/app/simplecloud/plugin/command/bungeecord/BungeeCordPlugin.kt +++ b/command-bungeecord/src/main/kotlin/app/simplecloud/plugin/command/bungeecord/BungeeCordPlugin.kt @@ -10,11 +10,10 @@ import org.incendo.cloud.SenderMapper import org.incendo.cloud.bungee.BungeeCommandManager import org.incendo.cloud.execution.ExecutionCoordinator - /** * @author Fynn Bauer in 2024 */ -class BungeeCordPlugin(): Plugin() { +class BungeeCordPlugin : Plugin() { private lateinit var commandManager: BungeeCommandManager private lateinit var commandPlugin: CommandPlugin @@ -45,6 +44,7 @@ class BungeeCordPlugin(): Plugin() { override fun onDisable() { adventure.close() + commandPlugin.config.close() } fun adventure(): BungeeAudiences { diff --git a/command-bungeecord/src/main/resources/plugin.yml b/command-bungeecord/src/main/resources/plugin.yml index f46eaa9..3d63b0a 100644 --- a/command-bungeecord/src/main/resources/plugin.yml +++ b/command-bungeecord/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: CommandPlugin -version: 0.0.1-EXPERIMENTAL +version: 1.0.0 author: Kaseax main: app.simplecloud.plugin.command.bungeecord.BungeeCordPlugin depends: [simplecloud-api] \ No newline at end of file diff --git a/command-shared/build.gradle.kts b/command-shared/build.gradle.kts index 1c2708d..98d99f0 100644 --- a/command-shared/build.gradle.kts +++ b/command-shared/build.gradle.kts @@ -1,12 +1,9 @@ dependencies { - compileOnly(libs.simplecloud.controller) + compileOnly(libs.simplecloud.api) api(libs.cloud.core) api(libs.adventure.api) api(libs.adventure.text.minimessage) - implementation(rootProject.libs.configurate.yaml) - implementation(rootProject.libs.configurate.kotlin) { - exclude(group = "org.jetbrains.kotlin") - exclude(group = "org.jetbrains.kotlinx") - } + implementation(libs.bundles.logging) + implementation(libs.bundles.configurate) } \ No newline at end of file diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudCommandHandler.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudCommandHandler.kt index 3f3f26a..e43dbd6 100644 --- a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudCommandHandler.kt +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudCommandHandler.kt @@ -1,610 +1,30 @@ package app.simplecloud.plugin.command.shared -import app.simplecloud.controller.api.ControllerApi -import app.simplecloud.controller.shared.group.Group -import build.buf.gen.simplecloud.controller.v1.ServerStopCause -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.minimessage.MiniMessage -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import app.simplecloud.api.CloudApi +import app.simplecloud.plugin.command.shared.commands.* import org.incendo.cloud.CommandManager import org.incendo.cloud.context.CommandContext -import org.incendo.cloud.parser.standard.LongParser.longParser -import org.incendo.cloud.parser.standard.StringParser.stringParser import org.incendo.cloud.permission.Permission -import org.incendo.cloud.suggestion.Suggestion -import org.incendo.cloud.suggestion.SuggestionProvider -import java.util.concurrent.CompletableFuture -// TODO: maybe move this into multiple classes? class CloudCommandHandler( private val commandManager: CommandManager, - val commandPlugin: CommandPlugin + private val commandPlugin: CommandPlugin ) { - - private val controllerApi = ControllerApi.createFutureApi() + private val api = CloudApi.create() fun createCloudCommand() { commandManager.command( commandManager.commandBuilder("cloud") .handler { context: CommandContext -> - - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudHelpTitle) - ) - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudStartCommand) - ) - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudStopCommand) - ) - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudServerInfoCommand) - ) - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudGroupInfoCommand) - ) - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudEditGroupCommand) - ) - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize(commandPlugin.messageConfiguration.cloudEditServerCommand) - ) - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize(commandPlugin.messageConfiguration.cloudDeleteGroupCommand) - ) + context.sender().sendMessage(miniMessage(commandPlugin.messageConfiguration.cloudHelpMessage)) } .permission(Permission.permission("simplecloud.command.cloud")) .build() ) - - registerStartCommand() - registerStopCommand() - registerServerInfoCommand() - registerGroupInfoCommand() - registerDeleteGroupCommand() - registerEditGroupCommand() - registerEditServerCommand() - } - - private fun registerStartCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("start") - .required( - "group", - stringParser(), - SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - } - ) - .handler { context: CommandContext -> - val group = context.get("group") - - controllerApi.getServers().startServer(group).thenAccept { server -> - val message = MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.serverStarting, - Placeholder.component("group", Component.text(group)), - Placeholder.component("id", Component.text(server?.numericalId!!)) - ) - - context.sender().sendMessage(message) - } - } - .permission(Permission.permission("simplecloud.command.cloud.start")) - .build() - ) - } - - private fun registerStopCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("stop") - .required("group", stringParser(), SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - }) - .optional("id", longParser(), SuggestionProvider { _, _ -> - controllerApi.getServers().getAllServers().thenApply { servers -> - servers.map { server -> Suggestion.suggestion(server.numericalId.toString()) } - } - }) - .handler { context: CommandContext -> - val group = context.get("group") - val id = context.getOrDefault("id", null as Long?) - - if (id == null) { - val message = MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupServerStopped, - Placeholder.component("group", Component.text(group)), - ) - - controllerApi.getServers().getServersByGroup(group).thenAccept { servers -> - servers.forEach { server -> - controllerApi.getServers().stopServer( - server.group, - server.numericalId.toLong() - ) - } - } - - context.sender().sendMessage(message) - } else { - - val message = MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.serverStopped, - Placeholder.component("group", Component.text(group)), - Placeholder.component("id", Component.text(id.toString())) - ) - - controllerApi.getServers().stopServer(group, id) - context.sender().sendMessage(message) - } - } - .permission(Permission.permission("simplecloud.command.cloud.stop")) - .build() - ) - } - - private fun registerServerInfoCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("info", "get") - .literal("servers", "server") - .optional("group", stringParser(), SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - }) - .optional("id", longParser(), SuggestionProvider { _, _ -> - controllerApi.getServers().getAllServers().thenApply { servers -> - servers.map { server -> Suggestion.suggestion(server.numericalId.toString()) } - } - }) - .handler { context: CommandContext -> - val groupName = context.getOrDefault("group", null as String?) - val id = context.getOrDefault("id", null as Long?) - - when { - groupName != null && id != null -> { - controllerApi.getServers().getServerByNumerical(groupName, id).thenAccept { server -> - controllerApi.getGroups().getGroupByName(groupName).thenAccept { group -> - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize( - commandPlugin.messageConfiguration.serverInfoTitle, - Placeholder.component("servergroup", Component.text(server.group)), - Placeholder.component( - "serveramount", - Component.text( - controllerApi.getServers().getServersByGroup(groupName) - .get().size.toString() - ) - ), - ) - ) - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize( - commandPlugin.messageConfiguration.serverInfoType, - Placeholder.component("grouptype", Component.text(server.type.name)) - ) - ) - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize( - commandPlugin.messageConfiguration.serverInfoSoftware, - Placeholder.component( - "groupsoftware", - Component.text(group.properties["server-software"].toString()) - ) - ) - ) - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize( - commandPlugin.messageConfiguration.serverInfoMemory, - Placeholder.component("groupmemory", Component.text(server.maxMemory)) - ) - ) - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize( - commandPlugin.messageConfiguration.serverInfoPlayers, - Placeholder.component( - "groupplayers", - Component.text(server.playerCount) - ) - ) - ) - } - } - } - - groupName != null -> { - controllerApi.getServers().getServersByGroup(groupName).thenAccept { servers -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupServerListTitle, - Placeholder.component("servergroup", Component.text(groupName)) - ) - ) - servers.forEach { server -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupServerListEntry, - Placeholder.component("servergroup", Component.text(server.group)), - Placeholder.component( - "numericalid", - Component.text(server.numericalId.toString()) - ), - Placeholder.component( - "onlineplayers", - Component.text(server.playerCount) - ), - Placeholder.component("maxplayers", Component.text(server.maxPlayers)), - Placeholder.component("minmemory", Component.text(server.minMemory)), - Placeholder.component("maxmemory", Component.text(server.maxMemory)), - Placeholder.component("state", Component.text(server.state.name)), - ) - ) - } - } - } - - else -> { - controllerApi.getServers().getAllServers().thenAccept { servers -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.serverListTitle, - ) - ) - servers.forEach { server -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.serverListEntry, - Placeholder.component("servergroup", Component.text(server.group)), - Placeholder.component( - "numericalid", - Component.text(server.numericalId.toString()) - ), - Placeholder.component( - "onlineplayers", - Component.text(server.playerCount) - ), - Placeholder.component("maxplayers", Component.text(server.maxPlayers)), - Placeholder.component("minmemory", Component.text(server.minMemory)), - Placeholder.component("maxmemory", Component.text(server.maxMemory)), - Placeholder.component("state", Component.text(server.state.name)), - ) - ) - } - } - } - } - } - .permission(Permission.permission("simplecloud.command.cloud.get.servers")) - .build() - ) - } - - private fun registerGroupInfoCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("info", "get") - .literal("groups", "group") - .optional("group", stringParser(), SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - }) - .handler { context: CommandContext -> - val groupName = context.getOrDefault("group", null as String?) - if (groupName != null) { - controllerApi.getGroups().getGroupByName(groupName).thenAccept { group -> - controllerApi.getServers().getServersByGroup(groupName).thenAccept { servers -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupInfoTitle, - Placeholder.component("servergroup", Component.text(groupName)), - Placeholder.component("serveramount", Component.text(servers.size)) - ) - ) - - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupInfoType, - Placeholder.component("grouptype", Component.text(group.type.name)) - ) - ) - - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupInfoTemplate, - Placeholder.component( - "grouptemplate", - Component.text(group.properties.get("template-id").toString()) - ) - ) - ) - - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupInfoMemory, - Placeholder.component("minmemory", Component.text(group.minMemory)), - Placeholder.component("maxmemory", Component.text(group.maxMemory)) - ) - ) - - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupInfoPlayers, - Placeholder.component("maxplayers", Component.text(group.maxPlayers)) - ) - ) - } - } - } else { - controllerApi.getGroups().getAllGroups().thenAccept { groups -> - context.sender().sendMessage( - MiniMessage.miniMessage() - .deserialize(commandPlugin.messageConfiguration.groupsListTitle) - ) - groups.forEach { group -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupsListEntry, - Placeholder.component("servergroup", Component.text(group.name)), - Placeholder.component( - "onlinecount", - Component.text( - controllerApi.getServers().getServersByGroup(group) - .get().size.toString() - ) - ), - Placeholder.component( - "template", - Component.text(group.properties["template-id"].toString()) - ), - Placeholder.component("type", Component.text(group.type.name)), - Placeholder.component("maxcount", Component.text(group.maxOnlineCount)), - Placeholder.component("minmemory", Component.text(group.minMemory)), - Placeholder.component("maxmemory", Component.text(group.maxMemory)), - ) - ) - - } - } - } - } - .permission(Permission.permission("simplecloud.command.cloud.get.groups")) - .build() - ) - } - - private fun registerDeleteGroupCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("delete") - .literal("group") - .required("group", stringParser(), SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - }) - .handler { context: CommandContext -> - val group = context.get("group") - - val message = MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupDeleted, - Placeholder.component("group", Component.text(group)) - ) - - controllerApi.getServers().getServersByGroup(group).thenAccept { servers -> - servers.forEach { server -> - controllerApi.getServers().stopServer( - server.group, - server.numericalId.toLong() - ) - } - } - - controllerApi.getGroups().deleteGroup(group) - context.sender().sendMessage(message) - } - .permission(Permission.permission("simplecloud.command.cloud.delete.group")) - .build() - ) - } - - private fun registerEditGroupCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("edit") - .literal("group") - .required("group", stringParser(), SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - }) - .required("setting", stringParser(), SuggestionProvider { _, _ -> - CompletableFuture.completedFuture( - listOf( - "max-players", - "max-memory", - "max-online-count", - "min-memory", - "min-online-count", - "properties", - "server-url", - "start-port" - ).map { Suggestion.suggestion(it) } - ) - }) - .required("value", stringParser()) - .handler { context: CommandContext -> - val groupName = context.get("group") - val setting = context.get("setting") - val value = context.get("value") - - controllerApi.getGroups().getGroupByName(groupName).thenAccept { group -> - val updatedGroup = when (setting) { - "max-players" -> group.copy( - maxPlayers = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - "max-memory" -> group.copy( - maxMemory = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - "min-memory" -> group.copy( - minMemory = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - "max-online-count" -> group.copy( - maxOnlineCount = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - "min-online-count" -> group.copy( - minOnlineCount = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - "start-port" -> group.copy( - startPort = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - "server-url" -> group.copy(properties = group.properties + mapOf("server-url" to value)) - "properties" -> group.copy(properties = group.properties + mapOf("custom-property" to value)) - else -> { - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidSetting, - Placeholder.component("key", Component.text(setting)) - ) - ) - return@thenAccept - } - } - - controllerApi.getGroups().updateGroup(updatedGroup).thenAccept { group -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.groupUpdated, - Placeholder.component("group", Component.text(group.name)) - ) - ) - } - } - - - } - .permission(Permission.permission("simplecloud.command.cloud.edit.group")) - .build() - ) - } - - private fun registerEditServerCommand() { - commandManager.command( - commandManager.commandBuilder("cloud") - .literal("edit") - .literal("server") - .required("group", stringParser(), SuggestionProvider { _, _ -> - controllerApi.getGroups().getAllGroups().thenApply { groups -> - groups.map { group -> Suggestion.suggestion(group.name) } - } - }) - .required("id", longParser(), SuggestionProvider { _, _ -> - controllerApi.getServers().getAllServers().thenApply { servers -> - servers.map { server -> Suggestion.suggestion(server.numericalId.toString()) } - } - }) - .required("setting", stringParser(), SuggestionProvider { _, _ -> - CompletableFuture.completedFuture( - listOf("max-players").map { Suggestion.suggestion(it) } - ) - }) - .required("value", stringParser()) - .handler { context: CommandContext -> - val groupName = context.get("group") - val serverId = context.get("id") - val setting = context.get("setting") - val value = context.get("value") - - controllerApi.getServers().getServerByNumerical(groupName, serverId).thenAccept { server -> - val updatedServer = when (setting) { - "max-players" -> server.copy( - maxPlayers = value.toLongOrNull() ?: return@thenAccept context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidValue, - Placeholder.component("value", Component.text(value)), - Placeholder.component("key", Component.text(setting)) - ) - ) - ) - - else -> { - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.invalidSetting, - Placeholder.component("key", Component.text(setting)) - ) - ) - return@thenAccept - } - } - - controllerApi.getServers().updateServer(updatedServer).thenAccept { server -> - context.sender().sendMessage( - MiniMessage.miniMessage().deserialize( - commandPlugin.messageConfiguration.serverUpdated, - Placeholder.component("group", Component.text(server.group)), - Placeholder.component("numericalid", Component.text(server.numericalId.toString())) - ) - ) - } - } - } - .permission(Permission.permission("simplecloud.command.cloud.edit.server")) - .build() - ) + StopCommand(api, commandPlugin).register(commandManager) + StartCommand(api, commandPlugin).register(commandManager) + InfoCommand(api, commandPlugin).register(commandManager) + EditCommand(api, commandPlugin).register(commandManager) + DeleteCommand(api, commandPlugin).register(commandManager) } -} +} \ No newline at end of file diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudSender.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudSender.kt index 5a323f1..a2484d0 100644 --- a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudSender.kt +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CloudSender.kt @@ -8,4 +8,5 @@ import net.kyori.adventure.text.Component interface CloudSender { fun sendMessage(message: Component) + } \ No newline at end of file diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CommandPlugin.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CommandPlugin.kt index f412ad9..d397988 100644 --- a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CommandPlugin.kt +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/CommandPlugin.kt @@ -2,7 +2,6 @@ package app.simplecloud.plugin.command.shared import app.simplecloud.plugin.command.shared.config.MessageConfig import app.simplecloud.plugin.command.shared.config.YamlConfig -import net.kyori.adventure.text.minimessage.MiniMessage /** * @author Fynn Bauer in 2024 @@ -10,8 +9,7 @@ import net.kyori.adventure.text.minimessage.MiniMessage open class CommandPlugin( dirPath: String ) { - - val config = YamlConfig(dirPath); - val messageConfiguration = config.load("messages")!! - val prefix = MiniMessage.miniMessage().deserialize(" ") + val config = YamlConfig(dirPath) + val messageConfiguration: MessageConfig + get() = config.getCached("messages")!! } \ No newline at end of file diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/StringExtension.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/StringExtension.kt new file mode 100644 index 0000000..b7e4962 --- /dev/null +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/StringExtension.kt @@ -0,0 +1,7 @@ +package app.simplecloud.plugin.command.shared + +import net.kyori.adventure.text.minimessage.MiniMessage +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver + +fun miniMessage(message: String, vararg tagResolver: TagResolver) = + MiniMessage.miniMessage().deserialize(message, *tagResolver) \ No newline at end of file diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/DeleteCommand.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/DeleteCommand.kt new file mode 100644 index 0000000..d238681 --- /dev/null +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/DeleteCommand.kt @@ -0,0 +1,90 @@ +package app.simplecloud.plugin.command.shared.commands + +import app.simplecloud.api.CloudApi +import app.simplecloud.plugin.command.shared.CloudSender +import app.simplecloud.plugin.command.shared.CommandPlugin +import app.simplecloud.plugin.command.shared.miniMessage +import app.simplecloud.plugin.command.shared.resolver.GroupTagResolver +import app.simplecloud.plugin.command.shared.resolver.PersistentServerTagResolver +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import org.incendo.cloud.CommandManager +import org.incendo.cloud.parser.standard.StringParser.stringParser +import org.incendo.cloud.permission.Permission +import org.incendo.cloud.suggestion.Suggestion + +class DeleteCommand( + private val api: CloudApi, + private val plugin: CommandPlugin +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + fun register(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("delete") + .literal("group") + .required("group", stringParser()) { _, _ -> + api.group().allGroups.thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .handler { context -> + val groupName = context.get("group") + scope.launch { + try { + val group = api.group().getGroupByName(groupName).await() + val servers = api.server().getServersByGroup(groupName).await() + servers.forEach { + try { + api.server().stopServer(it.serverId).await() + } catch (_: Exception) { + } + } + repeat(30) { + val remaining = api.server().getServersByGroup(groupName).await() + if (remaining.isEmpty()) return@repeat + delay(1000) + } + api.group().deleteGroup(group.serverGroupId).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.groupDeleted, GroupTagResolver.of(group))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.delete.group")) + .build() + ) + + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("delete") + .literal("persistent") + .required("server", stringParser()) { _, _ -> + api.persistentServer().allPersistentServers.thenApply { servers -> + servers.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .handler { context -> + val serverName = context.get("server") + scope.launch { + try { + val persistent = api.persistentServer().getPersistentServerByName(serverName).await() + api.persistentServer().deletePersistentServer(persistent.persistentServerId).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.persistentServerDeleted, PersistentServerTagResolver.of(persistent))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.delete.persistent")) + .build() + ) + } +} diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/EditCommand.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/EditCommand.kt new file mode 100644 index 0000000..52b5b2e --- /dev/null +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/EditCommand.kt @@ -0,0 +1,285 @@ +package app.simplecloud.plugin.command.shared.commands + +import app.simplecloud.api.CloudApi +import app.simplecloud.api.group.DeploymentConfig +import app.simplecloud.api.group.DeploymentHost +import app.simplecloud.api.group.SourceConfig +import app.simplecloud.api.group.WorkflowsConfig +import app.simplecloud.api.group.WorkflowWhen +import app.simplecloud.api.group.UpdateGroupRequest +import app.simplecloud.api.group.ScalingConfig +import app.simplecloud.api.group.ScaleDownConfig +import app.simplecloud.api.persistentserver.PersistentServer +import app.simplecloud.api.persistentserver.UpdatePersistentServerRequest +import app.simplecloud.api.server.UpdateServerRequest +import app.simplecloud.plugin.command.shared.CloudSender +import app.simplecloud.plugin.command.shared.CommandPlugin +import app.simplecloud.plugin.command.shared.miniMessage +import app.simplecloud.plugin.command.shared.resolver.GroupTagResolver +import app.simplecloud.plugin.command.shared.resolver.PersistentServerTagResolver +import app.simplecloud.plugin.command.shared.resolver.ServerTagResolver +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import org.incendo.cloud.CommandManager +import org.incendo.cloud.parser.standard.IntegerParser.integerParser +import org.incendo.cloud.parser.standard.StringParser.stringParser +import org.incendo.cloud.permission.Permission +import org.incendo.cloud.suggestion.Suggestion +import java.util.concurrent.CompletableFuture + +class EditCommand( + private val api: CloudApi, + private val plugin: CommandPlugin +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + private val groupSettings = listOf("max-players", "min-memory", "max-memory") + private val serverSettings = listOf("max-players", "min-memory", "max-memory") + private val persistentSettings = listOf("max-players", "min-memory", "max-memory", "active") + + fun register(commandManager: CommandManager) { + registerEditGroup(commandManager) + registerEditServer(commandManager) + registerEditPersistent(commandManager) + } + + private fun registerEditGroup(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("edit") + .literal("group") + .required("group", stringParser()) { _, _ -> + api.group().allGroups.thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .required("setting", stringParser()) { _, _ -> + CompletableFuture.completedFuture(groupSettings.map { Suggestion.suggestion(it) }) + } + .required("value", stringParser()) + .handler { context -> + val groupName = context.get("group") + val setting = context.get("setting") + val value = context.get("value") + scope.launch { + try { + val group = api.group().getGroupByName(groupName).await() + val request = UpdateGroupRequest() + request.setName(group.name) + request.setType(group.type) + request.setMinMemory(group.minMemory) + request.setMaxMemory(group.maxMemory) + request.setMaxPlayers(group.maxPlayers) + group.deployment?.let { request.setDeployment(copyDeploymentConfig(it)) } + group.scaling?.let { request.setScaling(copyScalingConfig(it)) } + group.source?.let { request.setSource(copySourceConfig(it)) } + group.workflows?.let { request.setWorkflows(copyWorkflowsConfig(it)) } + request.setProperties(group.properties) + request.setTags(group.tags) + when (setting) { + "max-players" -> request.setMaxPlayers(parseIntOrError(value, setting, context.sender()) ?: return@launch) + "min-memory" -> request.setMinMemory(parseIntOrError(value, setting, context.sender()) ?: return@launch) + "max-memory" -> request.setMaxMemory(parseIntOrError(value, setting, context.sender()) ?: return@launch) + else -> { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.invalidSetting, Placeholder.unparsed("key", setting))) + return@launch + } + } + val updated = api.group().updateGroup(group.serverGroupId, request).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.groupUpdated, GroupTagResolver.of(updated))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.edit.group")) + .build() + ) + } + + private fun copyDeploymentConfig(original: DeploymentConfig): DeploymentConfig { + val copy = DeploymentConfig() + copy.strategy = original.strategy + original.hosts?.let { hosts -> + copy.hosts = hosts.map { host -> + DeploymentHost().apply { + name = host.name + priority = host.priority + } + }.toTypedArray() + } + return copy + } + + private fun copyScalingConfig(original: ScalingConfig): ScalingConfig { + val copy = ScalingConfig() + copy.availableSlots = original.availableSlots + copy.maxServers = original.maxServers + copy.minServers = original.minServers + copy.playerThreshold = original.playerThreshold + copy.scalingMode = original.scalingMode + original.scaleDown?.let { + val scaleDownCopy = ScaleDownConfig() + scaleDownCopy.idleTime = it.idleTime + scaleDownCopy.isIgnorePlayers = it.isIgnorePlayers + copy.scaleDown = scaleDownCopy + } + return copy + } + + private fun copySourceConfig(original: SourceConfig): SourceConfig { + val copy = SourceConfig() + copy.type = original.type + copy.blueprint = original.blueprint + copy.image = original.image + return copy + } + + private fun copyWorkflowsConfig(original: WorkflowsConfig): WorkflowsConfig { + val copy = WorkflowsConfig() + copy.manual = original.manual + original.`when`?.let { whenConfig -> + val whenCopy = WorkflowWhen() + whenCopy.start = whenConfig.start + whenCopy.stop = whenConfig.stop + copy.`when` = whenCopy + } + return copy + } + + private fun registerEditServer(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("edit") + .literal("server") + .required("group", stringParser()) { _, _ -> + api.group().allGroups.thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .required("id", integerParser()) { context, _ -> + try { + val group = context.get("group") + api.server().getServersByGroup(group).thenApply { servers -> + servers.map { Suggestion.suggestion(it.numericalId.toString()) } + }.exceptionally { emptyList() } + } catch (e: Exception) { + CompletableFuture.completedFuture(emptyList()) + } + } + .required("setting", stringParser()) { _, _ -> + CompletableFuture.completedFuture(serverSettings.map { Suggestion.suggestion(it) }) + } + .required("value", stringParser()) + .handler { context -> + val groupName = context.get("group") + val id = context.get("id") + val setting = context.get("setting") + val value = context.get("value") + scope.launch { + try { + val server = api.server().getServerByNumericalId(groupName, id).await() + val request = UpdateServerRequest().apply { + when (setting) { + "max-players" -> maxPlayers = parseIntOrError(value, setting, context.sender()) ?: return@launch + "min-memory" -> minMemory = parseIntOrError(value, setting, context.sender()) ?: return@launch + "max-memory" -> maxMemory = parseIntOrError(value, setting, context.sender()) ?: return@launch + else -> { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.invalidSetting, Placeholder.unparsed("key", setting))) + return@launch + } + } + } + val updated = api.server().updateServer(server.serverId, request).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.serverUpdated, ServerTagResolver.of(updated))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.edit.server")) + .build() + ) + } + + private fun registerEditPersistent(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("edit") + .literal("persistent") + .required("server", stringParser()) { _, _ -> + api.persistentServer().allPersistentServers.thenApply { servers -> + servers.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .required("setting", stringParser()) { _, _ -> + CompletableFuture.completedFuture(persistentSettings.map { Suggestion.suggestion(it) }) + } + .required("value", stringParser()) + .handler { context -> + val serverName = context.get("server") + val setting = context.get("setting") + val value = context.get("value") + scope.launch { + try { + val persistent = api.persistentServer().getPersistentServerByName(serverName).await() + val builder = persistentUpdateBuilder(persistent) + when (setting) { + "max-players" -> builder.maxPlayers(parseIntOrError(value, setting, context.sender()) ?: return@launch) + "min-memory" -> builder.minMemory(parseIntOrError(value, setting, context.sender()) ?: return@launch) + "max-memory" -> builder.maxMemory(parseIntOrError(value, setting, context.sender()) ?: return@launch) + "active" -> builder.active(parseBoolOrError(value, setting, context.sender()) ?: return@launch) + else -> { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.invalidSetting, Placeholder.unparsed("key", setting))) + return@launch + } + } + val updated = api.persistentServer().updatePersistentServer( + persistent.persistentServerId, builder.build() + ).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.persistentServerUpdated, PersistentServerTagResolver.of(updated))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.edit.persistent")) + .build() + ) + } + + private fun parseIntOrError(value: String, key: String, sender: CloudSender): Int? { + return value.toIntOrNull() ?: run { + sender.sendMessage(miniMessage(plugin.messageConfiguration.invalidValue, Placeholder.unparsed("value", value), Placeholder.unparsed("key", key))) + null + } + } + + private fun parseBoolOrError(value: String, key: String, sender: CloudSender): Boolean? { + return value.toBooleanStrictOrNull() ?: run { + sender.sendMessage(miniMessage(plugin.messageConfiguration.invalidValue, Placeholder.unparsed("value", value), Placeholder.unparsed("key", key))) + null + } + } + + companion object { + fun persistentUpdateBuilder(persistent: PersistentServer): UpdatePersistentServerRequest.Builder { + return UpdatePersistentServerRequest.builder() + .name(persistent.name) + .type(persistent.type) + .source(persistent.source) + .workflows(persistent.workflows) + .serverhostId(persistent.serverhostId) + .minMemory(persistent.minMemory) + .maxMemory(persistent.maxMemory) + .maxPlayers(persistent.maxPlayers) + .active(persistent.isActive) + .properties(persistent.properties) + .tags(persistent.tags) + } + } +} diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/InfoCommand.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/InfoCommand.kt new file mode 100644 index 0000000..069ce55 --- /dev/null +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/InfoCommand.kt @@ -0,0 +1,197 @@ +package app.simplecloud.plugin.command.shared.commands + +import app.simplecloud.api.CloudApi +import app.simplecloud.plugin.command.shared.CloudSender +import app.simplecloud.plugin.command.shared.CommandPlugin +import app.simplecloud.plugin.command.shared.miniMessage +import app.simplecloud.plugin.command.shared.resolver.GroupTagResolver +import app.simplecloud.plugin.command.shared.resolver.PersistentServerTagResolver +import app.simplecloud.plugin.command.shared.resolver.ServerTagResolver +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import org.incendo.cloud.CommandManager +import org.incendo.cloud.parser.standard.IntegerParser.integerParser +import org.incendo.cloud.parser.standard.StringParser.stringParser +import org.incendo.cloud.permission.Permission +import org.incendo.cloud.suggestion.Suggestion +import java.util.concurrent.CompletableFuture + +class InfoCommand( + private val api: CloudApi, + private val plugin: CommandPlugin +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + fun register(commandManager: CommandManager) { + registerServerInfo(commandManager) + registerGroupInfo(commandManager) + registerPersistentServerInfo(commandManager) + } + + private fun registerServerInfo(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("info") + .literal("servers", "server") + .optional("group", stringParser()) { _, _ -> + api.group().allGroups.thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .optional("id", integerParser()) { context, _ -> + try { + val group = context.get("group") + api.server().getServersByGroup(group).thenApply { servers -> + servers.map { Suggestion.suggestion(it.numericalId.toString()) } + }.exceptionally { emptyList() } + } catch (e: Exception) { + CompletableFuture.completedFuture(emptyList()) + } + } + .handler { context -> + val groupName = context.getOrDefault("group", null as String?) + val id = context.getOrDefault("id", null as Int?) + scope.launch { + try { + when { + groupName != null && id != null -> showServerDetail(context.sender(), groupName, id) + groupName != null -> showGroupServers(context.sender(), groupName) + else -> showAllServers(context.sender()) + } + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.info.servers")) + .build() + ) + } + + private suspend fun showServerDetail(sender: CloudSender, groupName: String, id: Int) { + val server = api.server().getServerByNumericalId(groupName, id).await() + val resolver = ServerTagResolver.of(server) + sender.sendMessage(miniMessage(plugin.messageConfiguration.serverInfoTitle, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.serverInfoState, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.serverInfoMemory, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.serverInfoPlayers, resolver)) + } + + private suspend fun showGroupServers(sender: CloudSender, groupName: String) { + val group = api.group().getGroupByName(groupName).await() + val servers = api.server().getServersByGroup(groupName).await() + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupServerListTitle, GroupTagResolver.of(group))) + servers.forEach { server -> + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupServerListEntry, ServerTagResolver.of(server))) + } + } + + private suspend fun showAllServers(sender: CloudSender) { + val servers = api.server().allServers.await() + sender.sendMessage(miniMessage(plugin.messageConfiguration.serverListTitle)) + servers.forEach { server -> + sender.sendMessage(miniMessage(plugin.messageConfiguration.serverListEntry, ServerTagResolver.of(server))) + } + } + + private fun registerGroupInfo(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("info") + .literal("groups", "group") + .optional("group", stringParser()) { _, _ -> + api.group().allGroups.thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .handler { context -> + val groupName = context.getOrDefault("group", null as String?) + scope.launch { + try { + if (groupName != null) { + showGroupDetail(context.sender(), groupName) + } else { + showAllGroups(context.sender()) + } + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.info.groups")) + .build() + ) + } + + private suspend fun showGroupDetail(sender: CloudSender, groupName: String) { + val group = api.group().getGroupByName(groupName).await() + val servers = api.server().getServersByGroup(groupName).await() + val resolver = GroupTagResolver.of(group) + val countPlaceholder = Placeholder.unparsed("server_count", servers.size.toString()) + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupInfoTitle, resolver, countPlaceholder)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupInfoType, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupInfoMemory, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupInfoPlayers, resolver)) + } + + private suspend fun showAllGroups(sender: CloudSender) { + val groups = api.group().allGroups.await() + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupsListTitle)) + groups.forEach { group -> + val servers = api.server().getServersByGroup(group.name).await() + sender.sendMessage(miniMessage(plugin.messageConfiguration.groupsListEntry, GroupTagResolver.of(group), Placeholder.unparsed("server_count", servers.size.toString()))) + } + } + + private fun registerPersistentServerInfo(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("info") + .literal("persistent") + .optional("server", stringParser()) { _, _ -> + api.persistentServer().allPersistentServers.thenApply { servers -> + servers.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .handler { context -> + val serverName = context.getOrDefault("server", null as String?) + scope.launch { + try { + if (serverName != null) { + showPersistentServerDetail(context.sender(), serverName) + } else { + showAllPersistentServers(context.sender()) + } + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.info.persistent")) + .build() + ) + } + + private suspend fun showPersistentServerDetail(sender: CloudSender, serverName: String) { + val persistent = api.persistentServer().getPersistentServerByName(serverName).await() + val resolver = PersistentServerTagResolver.of(persistent) + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServerInfoTitle, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServerInfoType, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServerInfoMemory, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServerInfoPlayers, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServerInfoActive, resolver)) + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServerInfoServerhost, resolver)) + } + + private suspend fun showAllPersistentServers(sender: CloudSender) { + val servers = api.persistentServer().allPersistentServers.await() + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServersListTitle)) + servers.forEach { server -> + sender.sendMessage(miniMessage(plugin.messageConfiguration.persistentServersListEntry, PersistentServerTagResolver.of(server))) + } + } +} diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/StartCommand.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/StartCommand.kt new file mode 100644 index 0000000..ea7b03b --- /dev/null +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/StartCommand.kt @@ -0,0 +1,92 @@ +package app.simplecloud.plugin.command.shared.commands + +import app.simplecloud.api.CloudApi +import app.simplecloud.api.server.StartServerRequest +import app.simplecloud.plugin.command.shared.CloudSender +import app.simplecloud.plugin.command.shared.CommandPlugin +import app.simplecloud.plugin.command.shared.miniMessage +import app.simplecloud.plugin.command.shared.resolver.GroupTagResolver +import app.simplecloud.plugin.command.shared.resolver.PersistentServerTagResolver +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import org.incendo.cloud.CommandManager +import org.incendo.cloud.parser.standard.StringParser.stringParser +import org.incendo.cloud.permission.Permission +import org.incendo.cloud.suggestion.Suggestion + +class StartCommand( + private val api: CloudApi, + private val plugin: CommandPlugin +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + fun register(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("start") + .literal("group") + .required("group", stringParser()) { _, _ -> + api.group().allGroups + .thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + } + .exceptionally { emptyList() } + } + .handler { context -> + val groupName = context.get("group") + scope.launch { + try { + val group = api.group().getGroupByName(groupName).await() + api.server().startServer(StartServerRequest(group.serverGroupId, group.name)) + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.serverStarting, GroupTagResolver.of(group))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.start.group")) + .build() + ) + + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("start") + .literal("persistent") + .required("server", stringParser()) { _, _ -> + api.persistentServer().allPersistentServers + .thenApply { servers -> + servers.map { Suggestion.suggestion(it.name) } + } + .exceptionally { emptyList() } + } + .handler { context -> + val serverName = context.get("server") + scope.launch { + try { + val persistent = api.persistentServer().getPersistentServerByName(serverName).await() + api.persistentServer().updatePersistentServer( + persistent.persistentServerId, + EditCommand.persistentUpdateBuilder(persistent) + .active(true) + .build() + ).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.persistentServerActivated, PersistentServerTagResolver.of(persistent))) + } catch (e: Exception) { + context.sender().sendMessage( + miniMessage( + plugin.messageConfiguration.errorMessage, + Placeholder.unparsed("error", e.message ?: "Unknown error") + ) + ) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.start.persistent")) + .build() + ) + } +} \ No newline at end of file diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/StopCommand.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/StopCommand.kt new file mode 100644 index 0000000..4a6b089 --- /dev/null +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/commands/StopCommand.kt @@ -0,0 +1,103 @@ +package app.simplecloud.plugin.command.shared.commands + +import app.simplecloud.api.CloudApi +import app.simplecloud.plugin.command.shared.CloudSender +import app.simplecloud.plugin.command.shared.CommandPlugin +import app.simplecloud.plugin.command.shared.miniMessage +import app.simplecloud.plugin.command.shared.resolver.GroupTagResolver +import app.simplecloud.plugin.command.shared.resolver.PersistentServerTagResolver +import app.simplecloud.plugin.command.shared.resolver.ServerTagResolver +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.future.await +import kotlinx.coroutines.launch +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder +import org.incendo.cloud.CommandManager +import org.incendo.cloud.parser.standard.IntegerParser.integerParser +import org.incendo.cloud.parser.standard.StringParser.stringParser +import org.incendo.cloud.permission.Permission +import org.incendo.cloud.suggestion.Suggestion +import java.util.concurrent.CompletableFuture + +class StopCommand( + private val api: CloudApi, + private val plugin: CommandPlugin +) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + fun register(commandManager: CommandManager) { + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("stop") + .literal("group") + .required("group", stringParser()) { _, _ -> + api.group().allGroups.thenApply { groups -> + groups.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .optional("id", integerParser()) { context, _ -> + try { + val group = context.get("group") + api.server().getServersByGroup(group).thenApply { servers -> + servers.map { Suggestion.suggestion(it.numericalId.toString()) } + }.exceptionally { emptyList() } + } catch (e: Exception) { + CompletableFuture.completedFuture(emptyList()) + } + } + .handler { context -> + val groupName = context.get("group") + val id = context.getOrDefault("id", null as Int?) + scope.launch { + try { + if (id != null) { + val server = api.server().getServerByNumericalId(groupName, id).await() + api.server().stopServer(server.serverId).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.serverStopped, ServerTagResolver.of(server))) + } else { + val group = api.group().getGroupByName(groupName).await() + val servers = api.server().getServersByGroup(groupName).await() + servers.forEach { api.server().stopServer(it.serverId) } + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.groupServersStopped, GroupTagResolver.of(group))) + } + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.stop.group")) + .build() + ) + + commandManager.command( + commandManager.commandBuilder("cloud") + .literal("stop") + .literal("persistent") + .required("server", stringParser()) { _, _ -> + api.persistentServer().allPersistentServers.thenApply { servers -> + servers.map { Suggestion.suggestion(it.name) } + }.exceptionally { emptyList() } + } + .handler { context -> + val serverName = context.get("server") + scope.launch { + try { + val persistent = api.persistentServer().getPersistentServerByName(serverName).await() + api.persistentServer().updatePersistentServer( + persistent.persistentServerId, + EditCommand.persistentUpdateBuilder(persistent) + .active(false) + .build() + ).await() + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.persistentServerDeactivated, PersistentServerTagResolver.of(persistent))) + } catch (e: Exception) { + context.sender().sendMessage(miniMessage(plugin.messageConfiguration.errorMessage, Placeholder.unparsed("error", e.message ?: "Unknown error"))) + } + } + } + .permission(Permission.permission("simplecloud.command.cloud.stop.persistent")) + .build() + ) + } +} diff --git a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/config/MessageConfig.kt b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/config/MessageConfig.kt index b5dc7bb..ee71180 100644 --- a/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/config/MessageConfig.kt +++ b/command-shared/src/main/kotlin/app/simplecloud/plugin/command/shared/config/MessageConfig.kt @@ -2,51 +2,68 @@ package app.simplecloud.plugin.command.shared.config import org.spongepowered.configurate.objectmapping.ConfigSerializable -/** - * @author Fynn Bauer in 2024 - */ - @ConfigSerializable data class MessageConfig( - val serverStarting: String = " A new server of group is starting ( )", - val serverStopped: String = " Server was stopped.", - val groupServerStopped: String = " Servers of group were stopped.", - val groupDeleted: String = " Server group was deleted.", - - val cloudHelpTitle: String = " Commands of Cloud Command Plugin", - val cloudStartCommand: String = " /cloud start ", - val cloudStopCommand: String = " /cloud stop ", - val cloudServerInfoCommand: String = " /cloud info servers [serverGroup] [Numerical ID]", - val cloudGroupInfoCommand: String = " /cloud info groups [groupName] [Numerical ID]", - val cloudDeleteGroupCommand: String = " /cloud delete group ", - val cloudEditGroupCommand: String = " /cloud edit group ", - val cloudEditServerCommand: String = " /cloud edit server ", - - val serverInfoTitle: String = " Information of server Online", - val serverInfoType: String = " Type: ", - val serverInfoSoftware: String = " Software: ", - val serverInfoMemory: String = " Memory: ", - val serverInfoPlayers: String = " Players: ", - - val groupInfoTitle: String = " Information of group Online", - val groupInfoType: String = " Type: ", - val groupInfoTemplate: String = " Template: ", - val groupInfoMemory: String = " Memory: -", - val groupInfoPlayers: String = " Players: ", + val cloudHelpMessage: String = """ + Commands of Cloud Command Plugin + /cloud start group + /cloud start persistent + /cloud stop group [id] + /cloud stop persistent + /cloud info servers [group] [id] + /cloud info groups [group] + /cloud info persistent [server] + /cloud delete group + /cloud delete persistent + /cloud edit group + /cloud edit server + /cloud edit persistent + """.trimIndent(), - val groupsListTitle: String = " List of every server group", - val groupsListEntry: String = " Online (