From c9c16d548e0725db8a8ae1be3085ac694cbe0546 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Fri, 4 Sep 2026 15:48:47 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat(api):=20introduce=20new=20?= =?UTF-8?q?chat=20signature=20and=20message=20handling=20features?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add SignatureUpdater interface for updating signatures - implement LastSeenTrackedEntry for tracking message signatures - create RemoteChatSession for managing chat sessions with public keys - add MessageSignatureCache for efficient signature management - introduce SignedMessageLink for linking signed messages - enhance RemoteSignedMessage to support signed message verification --- gradle/libs.versions.toml | 9 +- surf-api-minestom/api/surf-api-minestom.api | 2077 ++++++++++++++++- surf-api-minestom/build.gradle.kts | 5 +- .../api/minestom/SurfApiMinestomEntrypoint.kt | 2 +- .../api/minestom/SurfApiMinestomPlugin.kt | 4 +- .../surf/api/minestom/chat/AsyncChatEvent.kt | 83 + .../surf/api/minestom/chat/ChatRenderer.kt | 74 + .../api/minestom/chat/RemoteChatSender.kt | 16 + .../api/minestom/chat/RemoteSignedMessage.kt | 37 + .../chat/ViewerUnawareChatRenderer.kt | 36 + .../chat/signature/LastSeenMessages.kt | 67 + .../signature/LastSeenMessagesValidator.kt | 88 + .../chat/signature/LastSeenTrackedEntry.kt | 11 + .../chat/signature/MessageSignatureCache.kt | 76 + .../chat/signature/PlayerChatMessage.kt | 129 + .../chat/signature/ProfilePublicKey.kt | 60 + .../chat/signature/RemoteChatSession.kt | 30 + .../chat/signature/SignatureUpdater.kt | 10 + .../chat/signature/SignatureValidator.kt | 32 + .../chat/signature/SignedMessageBody.kt | 34 + .../chat/signature/SignedMessageChain.kt | 123 + .../chat/signature/SignedMessageLink.kt | 31 + .../api/minestom/chat/signature/Signer.kt | 24 + .../chat/signature/filter-mask-ext.kt | 12 + .../chat/signature/message-signature-ext.kt | 26 + .../api/minestom/command/CommandRegistrar.kt | 13 + .../command/args/MiniMessageArgument.kt | 14 +- .../minestom/command/commandapi/CommandAPI.kt | 62 + .../command/commandapi/CommandAPICommand.kt | 390 ++++ .../command/commandapi/CommandMetadata.kt | 28 + .../command/commandapi/CommandTree.kt | 112 + .../command/commandapi/RegisteredCommand.kt | 34 + .../command/commandapi/argument/Argument.kt | 332 +++ .../commandapi/argument/CompositeArguments.kt | 250 ++ .../commandapi/argument/EntityArguments.kt | 151 ++ .../commandapi/argument/MinecraftArguments.kt | 76 + .../commandapi/argument/PositionArguments.kt | 73 + .../commandapi/argument/PrimitiveArguments.kt | 152 ++ .../commandapi/argument/RegistryArguments.kt | 88 + .../argument/SignedMessageArgument.kt | 15 + .../commandapi/argument/StringArguments.kt | 108 + .../argument/parser/CoordinateParsers.kt | 270 +++ .../argument/parser/EntitySelector.kt | 83 + .../argument/parser/EntitySelectorParser.kt | 631 +++++ .../argument/parser/FixedSetParser.kt | 43 + .../argument/parser/InstanceParser.kt | 76 + .../argument/parser/ParticleParser.kt | 41 + .../argument/parser/RegistryParser.kt | 47 + .../argument/parser/ResourceLocationParser.kt | 56 + .../argument/parser/ScalarParsers.kt | 211 ++ .../commandapi/argument/parser/Suggesting.kt | 20 + .../command/commandapi/dsl/ArgumentDsl.kt | 869 +++++++ .../command/commandapi/dsl/CommandDsl.kt | 31 + .../command/commandapi/dsl/ExecutorDsl.kt | 206 ++ .../command/commandapi/dsl/SuggestionDsl.kt | 119 + .../exception/CommandSyntaxException.kt | 35 + .../exception/CommandValidationException.kt | 18 + .../commandapi/exception/ComponentMessage.kt | 18 + .../commandapi/executor/CommandArguments.kt | 90 + .../command/commandapi/executor/Executors.kt | 64 + .../commandapi/executor/SuspendExecutors.kt | 88 + .../commandapi/internal/CommandAPIPlatform.kt | 15 + .../suggestion/ArgumentSuggestions.kt | 108 + .../commandapi/suggestion/SafeSuggestions.kt | 70 + .../suggestion/SuggestionsBranch.kt | 177 ++ .../command/commandapi/suggestion/Tooltip.kt | 32 + .../minestom/coroutine/MinestomDispatchers.kt | 65 + .../coroutine/MinestomScopeProvider.kt | 30 + .../dialog/callback/DialogCallbackListener.kt | 4 +- .../surf/api/minestom/event/EventRegistrar.kt | 25 + .../api/minestom/event/SuspendingEventNode.kt | 54 + .../surf/api/minestom/extension/events.kt | 11 + .../surf/api/minestom/extension/server.kt | 96 + .../framework/MinestomInventoryLoader.kt | 4 +- .../surf/api/minestom/player/SurfPlayer.kt | 71 + .../minestom/player/connection-manager-ext.kt | 50 + .../surf/api/minestom/player/player-ext.kt | 18 + .../api/minestom/plugin/MinestomPlugin.kt | 104 + .../plugin/MinestomPluginEntrypoint.kt | 9 + .../plugin/annotation/DataDirectory.kt | 29 + .../plugin/annotation/MinestomPluginMeta.kt | 43 + .../slne/surf/api/minestom/util/uuid-ext.kt | 9 + .../signature/MessageSignatureCacheTest.kt | 107 + 83 files changed, 9115 insertions(+), 26 deletions(-) create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ChatRenderer.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteChatSender.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ViewerUnawareChatRenderer.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessages.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCache.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/ProfilePublicKey.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/RemoteChatSession.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureUpdater.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureValidator.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageBody.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageChain.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageLink.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/Signer.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/filter-mask-ext.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/message-signature-ext.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/CommandRegistrar.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPI.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPICommand.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandMetadata.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandTree.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/RegisteredCommand.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/Argument.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/CompositeArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/EntityArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/MinecraftArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PositionArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PrimitiveArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/RegistryArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/SignedMessageArgument.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/StringArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/CoordinateParsers.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelector.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelectorParser.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/FixedSetParser.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/InstanceParser.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ParticleParser.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/RegistryParser.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ResourceLocationParser.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ScalarParsers.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/Suggesting.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ArgumentDsl.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/CommandDsl.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ExecutorDsl.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/SuggestionDsl.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/ComponentMessage.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/Executors.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/SuspendExecutors.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomDispatchers.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomScopeProvider.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/EventRegistrar.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/SuspendingEventNode.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/events.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/server.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPlugin.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/DataDirectory.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta.kt create mode 100644 surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/util/uuid-ext.kt create mode 100644 surf-api-minestom/src/test/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCacheTest.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 804cda9c5..0d3cbcdc8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,11 @@ packetevents-plugin = "2.13.0" # Command API commandapi = "12.0.0" +# Minestom +minestom = "2026.08.16-26.2" +mojang-brigadier = "1.3.10" # matches the version minestom ships with +guice = "7.0.0" + # LuckPerms luckperms = "5.5" luckpermsplugin-bukkit = "v5.5.71-bukkit" # "luckpermsplugin" is written without a separating "-" between "luckperms" and "plugin", because Gradle interprets the version catalog key as a hierarchical alias and would split it into a nested accessor (libs.luckperms.plugin.bukkit), which conflicts with the existing libs.luckperms alias for the API dependency. @@ -87,7 +92,9 @@ paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paper-api" } canvas-api = { module = "io.canvasmc.canvas:canvas-api", version.ref = "canvas-api" } # Minestom -surf-minestom-lobby-api = { module = "dev.slne.minestom.lobby:surf-minestom-lobby-api", version = "+" } +minestom = { module = "net.minestom:minestom", version.ref = "minestom" } +mojang-brigadier = { module = "com.mojang:brigadier", version.ref = "mojang-brigadier" } +guice = { module = "com.google.inject:guice", version.ref = "guice" } # Kotlin kotlinxCoroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } diff --git a/surf-api-minestom/api/surf-api-minestom.api b/surf-api-minestom/api/surf-api-minestom.api index 11c1141f5..cacd88ac9 100644 --- a/surf-api-minestom/api/surf-api-minestom.api +++ b/surf-api-minestom/api/surf-api-minestom.api @@ -20,18 +20,1954 @@ public final class dev/slne/surf/api/minestom/builder/ItemDslKt { public abstract interface annotation class dev/slne/surf/api/minestom/builder/ItemDslMarker : java/lang/annotation/Annotation { } -public class dev/slne/surf/api/minestom/command/args/MiniMessageArgument : dev/slne/minestom/lobby/api/command/commandapi/argument/CustomArgument { +public final class dev/slne/surf/api/minestom/chat/AsyncChatEvent { + public static final field Companion Ldev/slne/surf/api/minestom/chat/AsyncChatEvent$Companion; + public fun (Ldev/slne/surf/api/minestom/player/SurfPlayer;Ljava/util/Set;Ldev/slne/surf/api/minestom/chat/ChatRenderer;Lnet/kyori/adventure/text/Component;Lnet/kyori/adventure/text/Component;Lnet/kyori/adventure/chat/SignedMessage;)V + public final fun getMessage ()Lnet/kyori/adventure/text/Component; + public final fun getOriginalMessage ()Lnet/kyori/adventure/text/Component; + public final fun getPlayer ()Ldev/slne/surf/api/minestom/player/SurfPlayer; + public final fun getRenderer ()Ldev/slne/surf/api/minestom/chat/ChatRenderer; + public final fun getSignedMessage ()Lnet/kyori/adventure/chat/SignedMessage; + public final fun getViewers ()Ljava/util/Set; + public final fun isCancelled ()Z + public final fun setCancelled (Z)V + public final fun setMessage (Lnet/kyori/adventure/text/Component;)V + public final fun setRenderer (Ldev/slne/surf/api/minestom/chat/ChatRenderer;)V +} + +public final class dev/slne/surf/api/minestom/chat/AsyncChatEvent$Companion { + public final fun addListener (ILkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/event/SuspendingEventNode$Registration; + public static synthetic fun addListener$default (Ldev/slne/surf/api/minestom/chat/AsyncChatEvent$Companion;ILkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/event/SuspendingEventNode$Registration; + public final fun getNode ()Ldev/slne/surf/api/minestom/event/SuspendingEventNode; +} + +public abstract interface class dev/slne/surf/api/minestom/chat/ChatRenderer { + public static final field Companion Ldev/slne/surf/api/minestom/chat/ChatRenderer$Companion; + public abstract fun render (Lnet/minestom/server/entity/Player;Lnet/kyori/adventure/text/Component;Lnet/kyori/adventure/text/Component;Lnet/kyori/adventure/audience/Audience;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/chat/ChatRenderer$Companion { + public final fun defaultRenderer ()Ldev/slne/surf/api/minestom/chat/ChatRenderer; + public final fun viewerUnaware (Ldev/slne/surf/api/minestom/chat/ChatRenderer$ViewerUnaware;)Ldev/slne/surf/api/minestom/chat/ChatRenderer; +} + +public abstract interface class dev/slne/surf/api/minestom/chat/ChatRenderer$Default : dev/slne/surf/api/minestom/chat/ChatRenderer, dev/slne/surf/api/minestom/chat/ChatRenderer$ViewerUnaware { +} + +public abstract interface class dev/slne/surf/api/minestom/chat/ChatRenderer$ViewerUnaware { + public abstract fun render (Lnet/minestom/server/entity/Player;Lnet/kyori/adventure/text/Component;Lnet/kyori/adventure/text/Component;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/chat/RemoteChatSender { + public fun (Ljava/util/UUID;Ljava/lang/String;Lnet/minestom/server/crypto/ChatSession;)V + public final fun component1 ()Ljava/util/UUID; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Lnet/minestom/server/crypto/ChatSession; + public final fun copy (Ljava/util/UUID;Ljava/lang/String;Lnet/minestom/server/crypto/ChatSession;)Ldev/slne/surf/api/minestom/chat/RemoteChatSender; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/RemoteChatSender;Ljava/util/UUID;Ljava/lang/String;Lnet/minestom/server/crypto/ChatSession;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/RemoteChatSender; + public fun equals (Ljava/lang/Object;)Z + public final fun getSession ()Lnet/minestom/server/crypto/ChatSession; + public final fun getUsername ()Ljava/lang/String; + public final fun getUuid ()Ljava/util/UUID; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/chat/RemoteSignedMessage { + public fun (Ljava/util/UUID;Ljava/util/UUID;ILnet/minestom/server/crypto/MessageSignature;Ljava/lang/String;Ljava/time/Instant;JLjava/util/List;Lnet/kyori/adventure/text/Component;)V + public final fun component1 ()Ljava/util/UUID; + public final fun component2 ()Ljava/util/UUID; + public final fun component3 ()I + public final fun component4 ()Lnet/minestom/server/crypto/MessageSignature; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/time/Instant; + public final fun component7 ()J + public final fun component8 ()Ljava/util/List; + public final fun component9 ()Lnet/kyori/adventure/text/Component; + public final fun copy (Ljava/util/UUID;Ljava/util/UUID;ILnet/minestom/server/crypto/MessageSignature;Ljava/lang/String;Ljava/time/Instant;JLjava/util/List;Lnet/kyori/adventure/text/Component;)Ldev/slne/surf/api/minestom/chat/RemoteSignedMessage; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/RemoteSignedMessage;Ljava/util/UUID;Ljava/util/UUID;ILnet/minestom/server/crypto/MessageSignature;Ljava/lang/String;Ljava/time/Instant;JLjava/util/List;Lnet/kyori/adventure/text/Component;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/RemoteSignedMessage; + public fun equals (Ljava/lang/Object;)Z + public final fun getContent ()Ljava/lang/String; + public final fun getIndex ()I + public final fun getLastSeen ()Ljava/util/List; + public final fun getSalt ()J + public final fun getSender ()Ljava/util/UUID; + public final fun getSessionId ()Ljava/util/UUID; + public final fun getSignature ()Lnet/minestom/server/crypto/MessageSignature; + public final fun getTimestamp ()Ljava/time/Instant; + public final fun getUnsignedContent ()Lnet/kyori/adventure/text/Component; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/chat/signature/Filter_mask_extKt { + public static final fun getFILTER_MASK_FULLY_FILTERED ()Lnet/minestom/server/crypto/FilterMask; + public static final fun getFILTER_MASK_PASS_THROUGH ()Lnet/minestom/server/crypto/FilterMask; + public static final fun isFullyFiltered (Lnet/minestom/server/crypto/FilterMask;)Z + public static final fun isPassThrough (Lnet/minestom/server/crypto/FilterMask;)Z +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessages { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Companion; + public static final field LAST_SEEN_MESSAGES_MAX_LENGTH I + public static final synthetic fun box-impl (Ljava/util/List;)Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages; + public static final fun computeChecksum-impl (Ljava/util/List;)B + public static fun constructor-impl (Ljava/util/List;)Ljava/util/List; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/util/List;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/util/List;Ljava/util/List;)Z + public final fun getEntries ()Ljava/util/List; + public fun hashCode ()I + public static fun hashCode-impl (Ljava/util/List;)I + public static final fun pack-impl (Ljava/util/List;Ldev/slne/surf/api/minestom/chat/signature/MessageSignatureCache;)Lnet/minestom/server/crypto/LastSeenMessages$Packed; + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/util/List;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/util/List; + public static final fun updateSignature-impl (Ljava/util/List;Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater$Output;)V +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Companion { + public final fun getEMPTY-fGxXxUo ()Ljava/util/List; +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update$Companion; + public static final field IGNORE_CHECKSUM B + public fun (ILjava/util/BitSet;B)V + public final fun component1 ()I + public final fun component2 ()Ljava/util/BitSet; + public final fun component3 ()B + public final fun copy (ILjava/util/BitSet;B)Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update;ILjava/util/BitSet;BILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update; + public fun equals (Ljava/lang/Object;)Z + public final fun getAcknowledged ()Ljava/util/BitSet; + public final fun getChecksum ()B + public final fun getOffset ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; + public final fun verifyChecksum-IId_2HM (Ljava/util/List;)Z +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update$Companion { + public final fun fromPacket (Lnet/minestom/server/network/packet/client/play/ClientChatMessagePacket;)Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update; + public final fun fromPacket (Lnet/minestom/server/network/packet/client/play/ClientSignedCommandChatPacket;)Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update; +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator { + public fun ()V + public fun (I)V + public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun addPending (Lnet/minestom/server/crypto/MessageSignature;)V + public final fun applyOffset (I)V + public final fun applyUpdate-utm7GzM (Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessages$Update;)Ljava/util/List; + public final fun getTrackedMessagesCount ()I +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator$ValidationException : java/lang/Exception { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator$ValidationException$Companion; + public fun (Ljava/lang/String;)V +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator$ValidationException$Companion { +} + +public final class dev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry { + public fun (Lnet/minestom/server/crypto/MessageSignature;Z)V + public final fun acknowledge ()Ldev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry; + public final fun component1 ()Lnet/minestom/server/crypto/MessageSignature; + public final fun component2 ()Z + public final fun copy (Lnet/minestom/server/crypto/MessageSignature;Z)Ldev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry;Lnet/minestom/server/crypto/MessageSignature;ZILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry; + public fun equals (Ljava/lang/Object;)Z + public final fun getPending ()Z + public final fun getSignature ()Lnet/minestom/server/crypto/MessageSignature; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/chat/signature/MessageSignatureCache { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/MessageSignatureCache$Companion; + public static final field NOT_FOUND I + public fun ()V + public fun (I)V + public synthetic fun (IILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun pack (Lnet/minestom/server/crypto/MessageSignature;)I + public final fun push (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;Lnet/minestom/server/crypto/MessageSignature;)V + public final fun unpack (I)Lnet/minestom/server/crypto/MessageSignature; +} + +public final class dev/slne/surf/api/minestom/chat/signature/MessageSignatureCache$Companion { + public final fun createDefault ()Ldev/slne/surf/api/minestom/chat/signature/MessageSignatureCache; +} + +public final class dev/slne/surf/api/minestom/chat/signature/Message_signature_extKt { + public static final fun adventure (Lnet/minestom/server/crypto/MessageSignature;)Lnet/kyori/adventure/chat/SignedMessage$Signature; + public static final fun checksum (Lnet/minestom/server/crypto/MessageSignature;)I + public static final fun describe (Lnet/minestom/server/crypto/MessageSignature;)Ljava/lang/String; + public static final fun pack (Lnet/minestom/server/crypto/MessageSignature;Ldev/slne/surf/api/minestom/chat/signature/MessageSignatureCache;)Lnet/minestom/server/crypto/MessageSignature$Packed; + public static final fun verify (Lnet/minestom/server/crypto/MessageSignature;Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator;Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater;)Z +} + +public final class dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage$Companion; + public fun (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink;Lnet/minestom/server/crypto/MessageSignature;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;Lnet/kyori/adventure/text/Component;Lnet/minestom/server/crypto/FilterMask;)V + public final fun adventureView ()Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage$AdventureView; + public final fun component1 ()Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; + public final fun component2 ()Lnet/minestom/server/crypto/MessageSignature; + public final fun component3 ()Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody; + public final fun component4 ()Lnet/kyori/adventure/text/Component; + public final fun component5 ()Lnet/minestom/server/crypto/FilterMask; + public final fun copy (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink;Lnet/minestom/server/crypto/MessageSignature;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;Lnet/kyori/adventure/text/Component;Lnet/minestom/server/crypto/FilterMask;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink;Lnet/minestom/server/crypto/MessageSignature;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;Lnet/kyori/adventure/text/Component;Lnet/minestom/server/crypto/FilterMask;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun decoratedContent ()Lnet/kyori/adventure/text/Component; + public final fun describeSigned ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun filter (Lnet/minestom/server/crypto/FilterMask;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun filter (Z)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun getFilterMask ()Lnet/minestom/server/crypto/FilterMask; + public final fun getLink ()Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; + public final fun getSignature ()Lnet/minestom/server/crypto/MessageSignature; + public final fun getSignedBody ()Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody; + public final fun getUnsignedContent ()Lnet/kyori/adventure/text/Component; + public final fun hasExpiredClient (Ljava/time/Instant;)Z + public final fun hasExpiredServer (Ljava/time/Instant;)Z + public final fun hasSignature ()Z + public final fun hasSignatureFrom (Ljava/util/UUID;)Z + public fun hashCode ()I + public final fun isFullyFiltered ()Z + public final fun isSystem ()Z + public final fun removeSignature ()Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun removeUnsignedContent ()Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun salt ()J + public final fun sender ()Ljava/util/UUID; + public final fun signedContent ()Ljava/lang/String; + public final fun timeStamp ()Ljava/time/Instant; + public fun toString ()Ljava/lang/String; + public final fun verify (Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator;)Z + public final fun withUnsignedContent (Lnet/kyori/adventure/text/Component;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; +} + +public final class dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage$AdventureView : net/kyori/adventure/chat/SignedMessage { + public fun (Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage;)V + public final fun getPlayerChatMessage ()Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public fun identity ()Lnet/kyori/adventure/identity/Identity; + public fun message ()Ljava/lang/String; + public fun salt ()J + public fun signature ()Lnet/kyori/adventure/chat/SignedMessage$Signature; + public fun timestamp ()Ljava/time/Instant; + public fun unsignedContent ()Lnet/kyori/adventure/text/Component; +} + +public final class dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage$Companion { + public final fun getMESSAGE_EXPIRES_AFTER_CLIENT ()Ljava/time/Duration; + public final fun getMESSAGE_EXPIRES_AFTER_SERVER ()Ljava/time/Duration; + public final fun system (Ljava/lang/String;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun unsigned (Ljava/util/UUID;Ljava/lang/String;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; + public final fun updateSignature (Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater$Output;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;)V +} + +public final class dev/slne/surf/api/minestom/chat/signature/ProfilePublicKeyKt { + public static final fun createSignatureValidator (Lnet/minestom/server/crypto/PlayerPublicKey;)Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator; + public static final fun createValidated (Lnet/minestom/server/crypto/PlayerPublicKey;Lnet/minestom/server/crypto/SignatureValidator;Ljava/util/UUID;)Lnet/minestom/server/crypto/PlayerPublicKey; + public static final fun getEXPIRED_PROFILE_PUBLIC_KEY ()Lnet/kyori/adventure/text/Component; + public static final fun getINVALID_PROFILE_PUBLIC_KEY_SIGNATURE ()Lnet/kyori/adventure/text/Component; + public static final fun hasExpired (Lnet/minestom/server/crypto/PlayerPublicKey;)Z + public static final fun validateSignature (Lnet/minestom/server/crypto/PlayerPublicKey;Lnet/minestom/server/crypto/SignatureValidator;Ljava/util/UUID;)Z +} + +public final class dev/slne/surf/api/minestom/chat/signature/ProfilePublicKeyValidationException : java/lang/Exception { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/ProfilePublicKeyValidationException$Companion; + public fun (Lnet/kyori/adventure/text/Component;)V + public final fun getComponent ()Lnet/kyori/adventure/text/Component; +} + +public final class dev/slne/surf/api/minestom/chat/signature/ProfilePublicKeyValidationException$Companion { +} + +public final class dev/slne/surf/api/minestom/chat/signature/RemoteChatSession { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/RemoteChatSession$Companion; + public fun (Ljava/util/UUID;Lnet/minestom/server/crypto/PlayerPublicKey;)V + public final fun asData ()Lnet/minestom/server/crypto/ChatSession; + public final fun component1 ()Ljava/util/UUID; + public final fun component2 ()Lnet/minestom/server/crypto/PlayerPublicKey; + public final fun copy (Ljava/util/UUID;Lnet/minestom/server/crypto/PlayerPublicKey;)Ldev/slne/surf/api/minestom/chat/signature/RemoteChatSession; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/signature/RemoteChatSession;Ljava/util/UUID;Lnet/minestom/server/crypto/PlayerPublicKey;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/signature/RemoteChatSession; + public final fun createMessageDecoder (Ljava/util/UUID;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder; + public fun equals (Ljava/lang/Object;)Z + public final fun getProfilePublicKey ()Lnet/minestom/server/crypto/PlayerPublicKey; + public final fun getSessionId ()Ljava/util/UUID; + public final fun hasExpired ()Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/chat/signature/RemoteChatSession$Companion { + public final fun validate (Lnet/minestom/server/crypto/ChatSession;Ljava/util/UUID;Lnet/minestom/server/crypto/SignatureValidator;)Ldev/slne/surf/api/minestom/chat/signature/RemoteChatSession; +} + +public abstract interface class dev/slne/surf/api/minestom/chat/signature/SignatureUpdater { + public abstract fun update (Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater$Output;)V +} + +public abstract interface class dev/slne/surf/api/minestom/chat/signature/SignatureUpdater$Output { + public abstract fun update ([B)V +} + +public abstract interface class dev/slne/surf/api/minestom/chat/signature/SignatureValidator { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator$Companion; + public abstract fun validate (Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater;[B)Z + public fun validate ([B[B)Z +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignatureValidator$Companion { + public final fun from (Ljava/security/PublicKey;Ljava/lang/String;)Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator; + public final fun getNO_VALIDATION ()Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignatureValidator$DefaultImpls { + public static fun validate (Ldev/slne/surf/api/minestom/chat/signature/SignatureValidator;[B[B)Z +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageBody { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody$Companion; + public synthetic fun (Ljava/lang/String;Ljava/time/Instant;JLjava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/time/Instant; + public final fun component3 ()J + public final fun component4-fGxXxUo ()Ljava/util/List; + public final fun copy-twXwbeM (Ljava/lang/String;Ljava/time/Instant;JLjava/util/List;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody; + public static synthetic fun copy-twXwbeM$default (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;Ljava/lang/String;Ljava/time/Instant;JLjava/util/List;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody; + public fun equals (Ljava/lang/Object;)Z + public final fun getContent ()Ljava/lang/String; + public final fun getLastSeen-fGxXxUo ()Ljava/util/List; + public final fun getSalt ()J + public final fun getTimeStamp ()Ljava/time/Instant; + public fun hashCode ()I + public final fun pack (Ldev/slne/surf/api/minestom/chat/signature/MessageSignatureCache;)Lnet/minestom/server/crypto/SignedMessageBody$Packed; + public fun toString ()Ljava/lang/String; + public final fun updateSignature (Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater$Output;)V +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageBody$Companion { + public final fun unsigned (Ljava/lang/String;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Companion; + public fun (Ljava/util/UUID;Ljava/util/UUID;)V + public final fun decoder (Lnet/minestom/server/crypto/PlayerPublicKey;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder; + public final fun encoder (Ldev/slne/surf/api/minestom/chat/signature/Signer;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Encoder; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Companion { +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$DecodeException : java/lang/Exception { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$DecodeException$Companion; + public fun (Lnet/kyori/adventure/text/Component;)V + public final fun getComponent ()Lnet/kyori/adventure/text/Component; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$DecodeException$Companion { + public final fun getCHAIN_BROKEN ()Lnet/kyori/adventure/text/Component; + public final fun getEXPIRED_PROFILE_KEY ()Lnet/kyori/adventure/text/Component; + public final fun getINVALID_SIGNATURE ()Lnet/kyori/adventure/text/Component; + public final fun getMISSING_PROFILE_KEY ()Lnet/kyori/adventure/text/Component; + public final fun getOUT_OF_ORDER_CHAT ()Lnet/kyori/adventure/text/Component; +} + +public abstract interface class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder$Companion; + public fun setChainBroken ()V + public abstract fun unpack (Lnet/minestom/server/crypto/MessageSignature;Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;)Ldev/slne/surf/api/minestom/chat/signature/PlayerChatMessage; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder$Companion { + public final fun unsigned (Ljava/util/UUID;Ljava/util/function/BooleanSupplier;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder$DefaultImpls { + public static fun setChainBroken (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Decoder;)V +} + +public abstract interface class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Encoder { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Encoder$Companion; + public abstract fun pack (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageBody;)Lnet/minestom/server/crypto/MessageSignature; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Encoder$Companion { + public final fun getUNSIGNED ()Ldev/slne/surf/api/minestom/chat/signature/SignedMessageChain$Encoder; +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageLink { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink$Companion; + public fun (ILjava/util/UUID;Ljava/util/UUID;)V + public final fun advance ()Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; + public final fun component1 ()I + public final fun component2 ()Ljava/util/UUID; + public final fun component3 ()Ljava/util/UUID; + public final fun copy (ILjava/util/UUID;Ljava/util/UUID;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink;ILjava/util/UUID;Ljava/util/UUID;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; + public fun equals (Ljava/lang/Object;)Z + public final fun getIndex ()I + public final fun getSender ()Ljava/util/UUID; + public final fun getSessionId ()Ljava/util/UUID; + public fun hashCode ()I + public final fun isDescendantOf (Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink;)Z + public fun toString ()Ljava/lang/String; + public final fun updateSignature (Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater$Output;)V +} + +public final class dev/slne/surf/api/minestom/chat/signature/SignedMessageLink$Companion { + public final fun root (Ljava/util/UUID;Ljava/util/UUID;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; + public final fun unsigned (Ljava/util/UUID;)Ldev/slne/surf/api/minestom/chat/signature/SignedMessageLink; +} + +public abstract interface class dev/slne/surf/api/minestom/chat/signature/Signer { + public static final field Companion Ldev/slne/surf/api/minestom/chat/signature/Signer$Companion; + public abstract fun sign (Ldev/slne/surf/api/minestom/chat/signature/SignatureUpdater;)[B + public fun sign ([B)[B +} + +public final class dev/slne/surf/api/minestom/chat/signature/Signer$Companion { + public final fun from (Ljava/security/PrivateKey;Ljava/lang/String;)Ldev/slne/surf/api/minestom/chat/signature/Signer; +} + +public final class dev/slne/surf/api/minestom/chat/signature/Signer$DefaultImpls { + public static fun sign (Ldev/slne/surf/api/minestom/chat/signature/Signer;[B)[B +} + +public abstract interface class dev/slne/surf/api/minestom/command/CommandRegistrar { + public abstract fun register ()V +} + +public class dev/slne/surf/api/minestom/command/args/MiniMessageArgument : dev/slne/surf/api/minestom/command/commandapi/argument/CustomArgument { + public fun (Ljava/lang/String;Z)V + public synthetic fun (Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class dev/slne/surf/api/minestom/command/args/MiniMessageArgumentKt { + public static final fun miniMessageArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun miniMessageArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun miniMessageArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun miniMessageArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun miniMessageArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun miniMessageArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandAPI { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/CommandAPI; + public final fun execute (Lnet/minestom/server/command/CommandSender;Ljava/lang/String;)I + public final fun failWithMessage (Lnet/kyori/adventure/text/Component;)Ljava/lang/Void; + public final fun failWithString (Ljava/lang/String;)Ljava/lang/Void; + public final fun installPlatform (Ldev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform;)V + public final fun register (Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition;Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public final fun uninstallPlatform (Ldev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform;)V + public final fun unregister (Ljava/lang/String;)Z +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandAPICommand : dev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable { + public fun (Ljava/lang/String;)V + public fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public synthetic fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public synthetic fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public synthetic fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public synthetic fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public final fun getName ()Ljava/lang/String; + public final fun register (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static synthetic fun register$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public final fun toDefinition ()Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition; + public final fun withAliases ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withArguments ([Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withFullDescription ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withHelp (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withOptionalArguments ([Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withPermission (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withRequirement (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withShortDescription (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withSubcommand (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withSubcommands ([Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public final fun withUsage ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandDefinition { + public fun (Ljava/lang/String;Ljava/util/Set;Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata;Ljava/util/List;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/util/Set; + public final fun component3 ()Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata; + public final fun component4 ()Ljava/util/List; + public final fun copy (Ljava/lang/String;Ljava/util/Set;Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata;Ljava/util/List;)Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition;Ljava/lang/String;Ljava/util/Set;Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata;Ljava/util/List;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition; + public fun equals (Ljava/lang/Object;)Z + public final fun getAliases ()Ljava/util/Set; + public final fun getMetadata ()Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata; + public final fun getName ()Ljava/lang/String; + public final fun getPaths ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandMetadata { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata$Companion; + public fun ()V + public fun (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/util/List; + public final fun component3 ()Ljava/util/List; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata; + public fun equals (Ljava/lang/Object;)Z + public final fun getFullDescription ()Ljava/util/List; + public final fun getHelp ()Ljava/lang/String; + public final fun getShortDescription ()Ljava/lang/String; + public final fun getUsage ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandMetadata$Companion { + public final fun snapshot (Ljava/lang/String;Ljava/util/Collection;Ljava/util/Collection;Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandMetadata; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandPath { + public fun (Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Ljava/util/List; + public final fun component3 ()Ljava/util/Set; + public final fun component4 ()Ljava/util/List; + public final fun copy (Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;)Ldev/slne/surf/api/minestom/command/commandapi/CommandPath; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandPath;Ljava/util/List;Ljava/util/List;Ljava/util/Set;Ljava/util/List;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandPath; + public fun equals (Ljava/lang/Object;)Z + public final fun getArguments ()Ljava/util/List; + public final fun getExecutors ()Ljava/util/List; + public final fun getPermissions ()Ljava/util/Set; + public final fun getRequirements ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/CommandTree : dev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable { + public fun (Ljava/lang/String;)V + public fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public synthetic fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public synthetic fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public synthetic fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public synthetic fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public final fun getName ()Ljava/lang/String; + public final fun register (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static synthetic fun register$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public final fun then (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun toDefinition ()Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition; + public final fun withAliases ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun withFullDescription ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun withHelp (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun withPermission (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun withRequirement (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun withShortDescription (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public final fun withUsage ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/RegisteredCommand { + public fun (Ljava/lang/String;Ljava/util/Collection;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/util/Collection;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getAliases ()Ljava/util/Set; + public final fun getName ()Ljava/lang/String; + public final fun getNamespace ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/AngleArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public abstract class dev/slne/surf/api/minestom/command/commandapi/argument/Argument : dev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable { + public fun (Ljava/lang/String;)V + public fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public synthetic fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public synthetic fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public synthetic fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public synthetic fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + protected fun getGreedy ()Z + protected abstract fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + protected fun getListDelimiter ()Ljava/lang/Character; + public final fun getNodeName ()Ljava/lang/String; + protected abstract fun getRawType ()Lcom/mojang/brigadier/arguments/ArgumentType; + public final fun includeSafeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun includeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun replaceSafeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun replaceSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun setOptional (Ljava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun setOptional (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun setOptional (Z)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + protected abstract fun stringify (Ljava/lang/Object;)Ljava/lang/String; + public final fun then (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun toDefinition ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public final fun withPermission (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public final fun withRequirement (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition { + public fun (Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind;ZLkotlin/jvm/functions/Function1;Ljava/util/Set;Ljava/util/List;Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode;ZLcom/mojang/brigadier/arguments/ArgumentType;Lkotlin/jvm/functions/Function1;Ljava/lang/Character;)V + public synthetic fun (Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind;ZLkotlin/jvm/functions/Function1;Ljava/util/Set;Ljava/util/List;Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode;ZLcom/mojang/brigadier/arguments/ArgumentType;Lkotlin/jvm/functions/Function1;Ljava/lang/Character;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component10 ()Lkotlin/jvm/functions/Function1; + public final fun component11 ()Ljava/lang/Character; + public final fun component2 ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public final fun component3 ()Z + public final fun component4 ()Lkotlin/jvm/functions/Function1; + public final fun component5 ()Ljava/util/Set; + public final fun component6 ()Ljava/util/List; + public final fun component7 ()Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode; + public final fun component8 ()Z + public final fun component9 ()Lcom/mojang/brigadier/arguments/ArgumentType; + public final fun copy (Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind;ZLkotlin/jvm/functions/Function1;Ljava/util/Set;Ljava/util/List;Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode;ZLcom/mojang/brigadier/arguments/ArgumentType;Lkotlin/jvm/functions/Function1;Ljava/lang/Character;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind;ZLkotlin/jvm/functions/Function1;Ljava/util/Set;Ljava/util/List;Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode;ZLcom/mojang/brigadier/arguments/ArgumentType;Lkotlin/jvm/functions/Function1;Ljava/lang/Character;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public fun equals (Ljava/lang/Object;)Z + public final fun getDefaultValue ()Lkotlin/jvm/functions/Function1; + public final fun getGreedy ()Z + public final fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public final fun getListDelimiter ()Ljava/lang/Character; + public final fun getNodeName ()Ljava/lang/String; + public final fun getOptional ()Z + public final fun getPermissions ()Ljava/util/Set; + public final fun getRawType ()Lcom/mojang/brigadier/arguments/ArgumentType; + public final fun getRequirements ()Ljava/util/List; + public final fun getStringify ()Lkotlin/jvm/functions/Function1; + public final fun getSuggestions ()Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Angle : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Angle; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Axis : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Axis; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Biome : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Biome; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$BlockPosition : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$BlockPosition; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Boolean : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Boolean; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Command : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Command; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Custom : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;Lkotlin/jvm/functions/Function1;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public final fun component2 ()Lkotlin/jvm/functions/Function1; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Custom; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Custom;Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Custom; + public fun equals (Ljava/lang/Object;)Z + public final fun getBase ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public final fun getParser ()Lkotlin/jvm/functions/Function1; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Double : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (DD)V + public final fun component1 ()D + public final fun component2 ()D + public final fun copy (DD)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Double; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Double;DDILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Double; + public fun equals (Ljava/lang/Object;)Z + public final fun getMax ()D + public final fun getMin ()D + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Enchantment : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Enchantment; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Entities : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Z)V + public final fun component1 ()Z + public final fun copy (Z)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Entities; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Entities;ZILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Entities; + public fun equals (Ljava/lang/Object;)Z + public final fun getAllowEmpty ()Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Entity : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Entity; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$EntityType : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$EntityType; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Enum : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Ljava/util/EnumSet;Lkotlin/jvm/functions/Function1;)V + public final fun component1 ()Ljava/util/EnumSet; + public final fun component2 ()Lkotlin/jvm/functions/Function1; + public final fun copy (Ljava/util/EnumSet;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Enum; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Enum;Ljava/util/EnumSet;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Enum; + public fun equals (Ljava/lang/Object;)Z + public final fun getFormatter ()Lkotlin/jvm/functions/Function1; + public final fun getValues ()Ljava/util/EnumSet; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Float : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (FF)V + public final fun component1 ()F + public final fun component2 ()F + public final fun copy (FF)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Float; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Float;FFILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Float; + public fun equals (Ljava/lang/Object;)Z + public final fun getMax ()F + public final fun getMin ()F + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$FloatRange : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$FloatRange; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$GameMode : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$GameMode; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$GreedyString : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$GreedyString; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Instance : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Instance; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Integer : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (II)V + public final fun component1 ()I + public final fun component2 ()I + public final fun copy (II)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Integer; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Integer;IIILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Integer; + public fun equals (Ljava/lang/Object;)Z + public final fun getMax ()I + public final fun getMin ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$IntegerRange : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$IntegerRange; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$List : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;CZ)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public final fun component2 ()C + public final fun component3 ()Z + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;CZ)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$List; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$List;Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition;CZILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$List; + public fun equals (Ljava/lang/Object;)Z + public final fun getAllowEmpty ()Z + public final fun getDelimiter ()C + public final fun getElement ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentDefinition; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Literal : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Literal; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Literal;Ljava/lang/String;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Literal; + public fun equals (Ljava/lang/Object;)Z + public final fun getLiteral ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Long : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (JJ)V + public final fun component1 ()J + public final fun component2 ()J + public final fun copy (JJ)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Long; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Long;JJILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Long; + public fun equals (Ljava/lang/Object;)Z + public final fun getMax ()J + public final fun getMin ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$MultiLiteral : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Ljava/util/List;)V + public final fun component1 ()Ljava/util/List; + public final fun copy (Ljava/util/List;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$MultiLiteral; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$MultiLiteral;Ljava/util/List;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$MultiLiteral; + public fun equals (Ljava/lang/Object;)Z + public final fun getLiterals ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Particle : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Particle; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Player : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Player; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Players : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Z)V + public final fun component1 ()Z + public final fun copy (Z)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Players; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Players;ZILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Players; + public fun equals (Ljava/lang/Object;)Z + public final fun getAllowEmpty ()Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Position : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Position; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Position2D : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Position2D; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$PotionEffect : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$PotionEffect; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Resource : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public fun (Ljava/lang/String;Lnet/minestom/server/registry/Registry;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Lnet/minestom/server/registry/Registry; + public final fun copy (Ljava/lang/String;Lnet/minestom/server/registry/Registry;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Resource; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Resource;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Resource; + public fun equals (Ljava/lang/Object;)Z + public final fun getIdentifier ()Ljava/lang/String; + public final fun getRegistry ()Lnet/minestom/server/registry/Registry; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$ResourceLocation : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$ResourceLocation; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Rotation : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Rotation; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$SignedMessage : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$SignedMessage; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Sound : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Sound; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$TeamColor : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$TeamColor; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Text : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Text; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Time : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Time; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Uuid : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Uuid; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Word : dev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind$Word; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/Axis : java/lang/Enum { + public static final field X Ldev/slne/surf/api/minestom/command/commandapi/argument/Axis; + public static final field Y Ldev/slne/surf/api/minestom/command/commandapi/argument/Axis; + public static final field Z Ldev/slne/surf/api/minestom/command/commandapi/argument/Axis; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Axis; + public static fun values ()[Ldev/slne/surf/api/minestom/command/commandapi/argument/Axis; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/AxisArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/BiomeArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/BlockPositionArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/BooleanArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/CommandArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/CompositeArgumentsKt { + public static final fun filter (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun map (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; +} + +public class dev/slne/surf/api/minestom/command/commandapi/argument/CustomArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)V + protected fun getGreedy ()Z + protected fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + protected fun getListDelimiter ()Ljava/lang/Character; + protected fun getRawType ()Lcom/mojang/brigadier/arguments/ArgumentType; + protected fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/CustomArgumentInfo { + public fun (Lnet/minestom/server/command/CommandSender;Ljava/lang/String;Ljava/lang/Object;)V + public final fun component1 ()Lnet/minestom/server/command/CommandSender; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/Object; + public final fun copy (Lnet/minestom/server/command/CommandSender;Ljava/lang/String;Ljava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/CustomArgumentInfo; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/CustomArgumentInfo;Lnet/minestom/server/command/CommandSender;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/CustomArgumentInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getBaseValue ()Ljava/lang/Object; + public final fun getCurrentInput ()Ljava/lang/String; + public final fun getSender ()Lnet/minestom/server/command/CommandSender; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/DoubleArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;DD)V + public synthetic fun (Ljava/lang/String;DDILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/EnchantmentArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/EntitiesArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { public fun (Ljava/lang/String;Z)V public synthetic fun (Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getAllowEmpty ()Z + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; } -public final class dev/slne/surf/api/minestom/command/args/MiniMessageArgumentKt { - public static final fun miniMessageArgument (Ldev/slne/minestom/lobby/api/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/minestom/lobby/api/command/commandapi/CommandAPICommand; - public static final fun miniMessageArgument (Ldev/slne/minestom/lobby/api/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/minestom/lobby/api/command/commandapi/CommandTree; - public static final fun miniMessageArgument (Ldev/slne/minestom/lobby/api/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/minestom/lobby/api/command/commandapi/argument/Argument; - public static synthetic fun miniMessageArgument$default (Ldev/slne/minestom/lobby/api/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/minestom/lobby/api/command/commandapi/CommandAPICommand; - public static synthetic fun miniMessageArgument$default (Ldev/slne/minestom/lobby/api/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/minestom/lobby/api/command/commandapi/CommandTree; - public static synthetic fun miniMessageArgument$default (Ldev/slne/minestom/lobby/api/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/minestom/lobby/api/command/commandapi/argument/Argument; +public final class dev/slne/surf/api/minestom/command/commandapi/argument/EntityArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/EntityTypeArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/EnumArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;)V + public synthetic fun (Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/FloatArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;FF)V + public synthetic fun (Ljava/lang/String;FFILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/FloatRangeArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/GameModeArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/GreedyStringArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/InstanceArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/IntegerArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;II)V + public synthetic fun (Ljava/lang/String;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/IntegerRangeArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ListArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZ)V + public synthetic fun (Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getAllowEmpty ()Z + public final fun getDelimiter ()C + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/LiteralArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public final fun getLiteral ()Ljava/lang/String; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/LongArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;JJ)V + public synthetic fun (Ljava/lang/String;JJILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/MultiLiteralArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;[Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ParticleArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/PlayerArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/PlayersArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;Z)V + public synthetic fun (Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getAllowEmpty ()Z + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/Position2DArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/PositionArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/PotionEffectArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ResourceArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/ResourceLocationArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/Rotation { + public fun (FF)V + public final fun component1 ()F + public final fun component2 ()F + public final fun copy (FF)Ldev/slne/surf/api/minestom/command/commandapi/argument/Rotation; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Rotation;FFILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Rotation; + public fun equals (Ljava/lang/Object;)Z + public final fun getPitch ()F + public final fun getYaw ()F + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/RotationArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SignedMessageArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SoundArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/StringArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode { +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$BuiltIns : dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode { + public static final field INSTANCE Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$BuiltIns; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Include : dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Include; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Include;Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Include; + public fun equals (Ljava/lang/Object;)Z + public final fun getProvider ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$IncludeSafe : dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$IncludeSafe; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$IncludeSafe;Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$IncludeSafe; + public fun equals (Ljava/lang/Object;)Z + public final fun getProvider ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Replace : dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Replace; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Replace;Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$Replace; + public fun equals (Ljava/lang/Object;)Z + public final fun getProvider ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$ReplaceSafe : dev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$ReplaceSafe; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$ReplaceSafe;Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/SuggestionMode$ReplaceSafe; + public fun equals (Ljava/lang/Object;)Z + public final fun getProvider ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/TeamColorArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/TextArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/TimeArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/UUIDArgument : dev/slne/surf/api/minestom/command/commandapi/argument/Argument { + public fun (Ljava/lang/String;)V + public synthetic fun getKind ()Ldev/slne/surf/api/minestom/command/commandapi/argument/ArgumentKind; + public synthetic fun stringify (Ljava/lang/Object;)Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/argument/UnsupportedArgumentType : com/mojang/brigadier/arguments/ArgumentType { + public fun (Ljava/lang/String;)V + public fun parse (Lcom/mojang/brigadier/StringReader;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/dsl/ArgumentDslKt { + public static final fun angleArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun angleArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun angleArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun angleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun angleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun angleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun axisArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun axisArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun axisArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun axisArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun axisArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun axisArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun biomeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun biomeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun biomeArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun biomeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun biomeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun biomeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun blockPositionArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun blockPositionArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun blockPositionArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun blockPositionArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun blockPositionArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun blockPositionArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun booleanArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun booleanArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun booleanArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun booleanArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun booleanArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun booleanArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun commandArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun commandArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun commandArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun commandArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun commandArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun commandArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun customArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;Ljava/lang/Boolean;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun customArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;Ljava/lang/Boolean;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun customArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;Ljava/lang/Boolean;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun customArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;Ljava/lang/Boolean;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun customArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;Ljava/lang/Boolean;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun customArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;Ljava/lang/Boolean;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun doubleArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;DDZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun doubleArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;DDZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun doubleArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;DDZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun doubleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;DDZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun doubleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;DDZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun doubleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;DDZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun enchantmentArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun enchantmentArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun enchantmentArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun enchantmentArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun enchantmentArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun enchantmentArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun entitiesArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun entitiesArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun entitiesArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun entitiesArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun entitiesArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun entitiesArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun entityArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun entityArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun entityArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun entityArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun entityArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun entityArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun entityTypeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun entityTypeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun entityTypeArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun entityTypeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun entityTypeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun entityTypeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun enumArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun enumArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun enumArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun enumArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun enumArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun enumArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ljava/util/Collection;Lkotlin/jvm/functions/Function1;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun floatArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;FFZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun floatArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;FFZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun floatArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;FFZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun floatArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;FFZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun floatArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;FFZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun floatArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;FFZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun floatRangeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun floatRangeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun floatRangeArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun floatRangeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun floatRangeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun floatRangeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun gameModeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun gameModeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun gameModeArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun gameModeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun gameModeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun gameModeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun greedyStringArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun greedyStringArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun greedyStringArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun greedyStringArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun greedyStringArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun greedyStringArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun instanceArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun instanceArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun instanceArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun instanceArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun instanceArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun instanceArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun integerArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;IIZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun integerArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;IIZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun integerArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;IIZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun integerArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;IIZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun integerArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;IIZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun integerArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;IIZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun integerRangeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun integerRangeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun integerRangeArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun integerRangeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun integerRangeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun integerRangeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun listArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun listArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun listArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun listArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun listArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun listArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;CZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun literalArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun literalArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun literalArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun literalArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun literalArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun literalArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun location2DArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun location2DArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun location2DArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun location2DArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun location2DArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun location2DArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun locationArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun locationArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun locationArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun locationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun locationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun locationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun longArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;JJZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun longArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;JJZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun longArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;JJZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun longArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;JJZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun longArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;JJZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun longArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;JJZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun multiLiteralArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun multiLiteralArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun multiLiteralArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun multiLiteralArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun multiLiteralArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun multiLiteralArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun particleArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun particleArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun particleArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun particleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun particleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun particleArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun playerArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun playerArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun playerArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun playerArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun playerArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun playerArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun playersArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun playersArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun playersArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun playersArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun playersArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun playersArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun potionEffectArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun potionEffectArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun potionEffectArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun potionEffectArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun potionEffectArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun potionEffectArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun resourceArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun resourceArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun resourceArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun resourceArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun resourceArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun resourceArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;Ljava/lang/String;Lnet/minestom/server/registry/Registry;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun resourceLocationArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun resourceLocationArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun resourceLocationArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun resourceLocationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun resourceLocationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun resourceLocationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun rotationArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun rotationArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun rotationArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun rotationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun rotationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun rotationArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun signedMessageArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun signedMessageArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun signedMessageArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun signedMessageArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun signedMessageArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun signedMessageArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun soundArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun soundArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun soundArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun soundArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun soundArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun soundArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun stringArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun stringArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun stringArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun stringArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun stringArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun stringArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun teamColorArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun teamColorArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun teamColorArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun teamColorArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun teamColorArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun teamColorArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun textArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun textArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun textArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun textArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun textArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun textArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun timeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun timeArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun timeArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun timeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun timeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun timeArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun uuidArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static final fun uuidArgument (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static final fun uuidArgument (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static synthetic fun uuidArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun uuidArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/CommandTree;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandTree; + public static synthetic fun uuidArgument$default (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/dsl/CommandDslKt { + public static final fun commandAPICommand (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static final fun commandAPICommand (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static synthetic fun commandAPICommand$default (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static synthetic fun commandAPICommand$default (Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static final fun commandTree (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static final fun commandTree (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static synthetic fun commandTree$default (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static synthetic fun commandTree$default (Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public static final fun subcommand (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; + public static synthetic fun subcommand$default (Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/CommandAPICommand; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/dsl/ExecutorDslKt { + public static final fun anyExecutionInfo (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyExecutionInfoExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyExecutionInfoExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static synthetic fun anyExecutionInfoExecutorSuspend$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function4;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function4;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static synthetic fun anyExecutorSuspend$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function4;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyResultingExecutionInfo (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun anyResultingExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleExecutionInfo (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleExecutionInfoExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleExecutionInfoExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static synthetic fun consoleExecutionInfoExecutorSuspend$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function4;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function4;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static synthetic fun consoleExecutorSuspend$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function4;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleResultingExecutionInfo (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun consoleResultingExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerExecutionInfo (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerExecutionInfoExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerExecutionInfoExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static synthetic fun playerExecutionInfoExecutorSuspend$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function4;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerExecutorSuspend (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function4;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static synthetic fun playerExecutorSuspend$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function4;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerResultingExecutionInfo (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static final fun playerResultingExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/dsl/SuggestionDslKt { + public static final fun includeSafeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSafeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ljava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSafeSuggestionsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSafeSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSafeSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ldev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSafeSuggestionsWithTooltipsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestionsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun includeSuggestionsWithTooltipsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSafeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSafeSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ljava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSafeSuggestionsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSafeSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSafeSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ldev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSafeSuggestionsWithTooltipsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestions (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestionsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestionsWithTooltips (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;[Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; + public static final fun replaceSuggestionsWithTooltipsAsync (Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/argument/Argument; +} + +public class dev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException : java/lang/RuntimeException { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException$Companion; + public fun (Lnet/kyori/adventure/text/Component;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Throwable;)V + public synthetic fun (Lnet/kyori/adventure/text/Component;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getComponent ()Lnet/kyori/adventure/text/Component; + public final fun getCursor ()Ljava/lang/Integer; + public final fun getInput ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException$Companion { +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException : java/lang/IllegalArgumentException { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException$Companion; + public fun (Ljava/lang/String;)V +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException$Companion { +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/ComponentMessage : com/mojang/brigadier/Message { + public fun (Lnet/kyori/adventure/text/Component;)V + public final fun getComponent ()Lnet/kyori/adventure/text/Component; + public fun getString ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/ComponentMessageKt { + public static final fun componentOrNull (Lcom/mojang/brigadier/Message;)Lnet/kyori/adventure/text/Component; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/WrapperCommandSyntaxException : java/lang/RuntimeException { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/exception/WrapperCommandSyntaxException$Companion; + public fun (Ldev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException;)V + public final fun getComponent ()Lnet/kyori/adventure/text/Component; + public final fun getCursor ()Ljava/lang/Integer; + public final fun getException ()Ldev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException; + public final fun getInput ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/exception/WrapperCommandSyntaxException$Companion { +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments$Companion; + public final fun contains (Ljava/lang/String;)Z + public final fun get (I)Ljava/lang/Object; + public final fun getRaw (I)Ljava/lang/String; + public final fun getRaw (Ljava/lang/String;)Ljava/lang/String; + public final fun rawArguments ()Ljava/util/List; + public final fun typed (Ljava/lang/String;Lkotlin/reflect/KClass;Z)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments$Companion { + public final fun empty ()Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments; + public final fun of (Ljava/util/List;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments; +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable { + public abstract fun addExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executes (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesConsole (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public fun executesPlayer (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable$DefaultImpls { + public static fun executes (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static fun executesConsole (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; + public static fun executesPlayer (Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable;Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandExecutable; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/ExecutionInfo { + public fun (Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;)V + public final fun component1 ()Lnet/minestom/server/command/CommandSender; + public final fun component2 ()Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments; + public final fun component3 ()Ljava/lang/String; + public final fun copy (Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutionInfo; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutionInfo;Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutionInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getArgs ()Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments; + public final fun getInput ()Ljava/lang/String; + public final fun getSender ()Lnet/minestom/server/command/CommandSender; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition { + public abstract fun getType ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Normal : dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function1;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public final fun component2 ()Lkotlin/jvm/functions/Function1; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Normal; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Normal;Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Normal; + public fun equals (Ljava/lang/Object;)Z + public final fun getExecutor ()Lkotlin/jvm/functions/Function1; + public fun getType ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Resulting : dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function1;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public final fun component2 ()Lkotlin/jvm/functions/Function1; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Resulting; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Resulting;Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Resulting; + public fun equals (Ljava/lang/Object;)Z + public final fun getExecutor ()Lkotlin/jvm/functions/Function1; + public fun getType ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Suspending : dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition { + public fun (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;)V + public final fun component1 ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public final fun component2 ()Lkotlin/jvm/functions/Function0; + public final fun component3 ()Lkotlin/jvm/functions/Function3; + public final fun copy (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Suspending; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Suspending;Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Suspending; + public fun equals (Ljava/lang/Object;)Z + public final fun getExecutor ()Lkotlin/jvm/functions/Function3; + public final fun getScopeProvider ()Lkotlin/jvm/functions/Function0; + public fun getType ()Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType : java/lang/Enum { + public static final field ANY Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public static final field CONSOLE Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public static final field PLAYER Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; + public static fun values ()[Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorType; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/ParsedArgument { + public fun (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Z)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/Object; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Z + public final fun copy (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;Z)Ldev/slne/surf/api/minestom/command/commandapi/executor/ParsedArgument; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/executor/ParsedArgument;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/String;ZILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/executor/ParsedArgument; + public fun equals (Ljava/lang/Object;)Z + public final fun getName ()Ljava/lang/String; + public final fun getPresent ()Z + public final fun getRaw ()Ljava/lang/String; + public final fun getValue ()Ljava/lang/Object; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/executor/SuspendExecutorsKt { + public static final fun getGENERIC_COMMAND_FAILURE ()Lnet/kyori/adventure/text/Component; + public static final fun handleCommandExecutorFailure (Lnet/minestom/server/command/CommandSender;Ljava/lang/String;Ljava/lang/Throwable;)V + public static final fun launchCommandExecutor (Ldev/slne/surf/api/minestom/command/commandapi/executor/ExecutorDefinition$Suspending;Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;)Lkotlinx/coroutines/Job; +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform { + public abstract fun execute (Lnet/minestom/server/command/CommandSender;Ljava/lang/String;)I + public abstract fun register (Ldev/slne/surf/api/minestom/command/commandapi/CommandDefinition;Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/RegisteredCommand; + public abstract fun unregister (Ljava/lang/String;)Z +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions$Companion; + public fun getFilterPolicy ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter; + public abstract fun suggest (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionInfo;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions$Companion { + public final fun branch (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun empty ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun merge ([Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringCollection (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringCollectionAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun strings (Ljava/util/Collection;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun strings (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun strings ([Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsWithTooltips (Ljava/util/Collection;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsWithTooltips (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsWithTooltips ([Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsWithTooltipsAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsWithTooltipsCollection (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun stringsWithTooltipsCollectionAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; + public final fun unfiltered (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions$DefaultImpls { + public static fun getFilterPolicy (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter; +} + +public abstract interface class dev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions$Companion; + public abstract fun suggest (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionInfo;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions$Companion { + public final fun empty ()Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun suggest (Ljava/util/Collection;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun suggest (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun suggest ([Ljava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun suggestAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun suggestCollection (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun suggestCollectionAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun tooltipCollection (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun tooltipCollectionAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun tooltips (Ljava/util/Collection;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun tooltips (Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun tooltips ([Ldev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; + public final fun tooltipsAsync (Lkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip$Companion; + public fun (Ljava/lang/String;Lnet/kyori/adventure/text/Component;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Lnet/kyori/adventure/text/Component; + public final fun copy (Ljava/lang/String;Lnet/kyori/adventure/text/Component;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip;Ljava/lang/String;Lnet/kyori/adventure/text/Component;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip; + public fun equals (Ljava/lang/Object;)Z + public final fun getSuggestion ()Ljava/lang/String; + public final fun getTooltip ()Lnet/kyori/adventure/text/Component; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip$Companion { + public final fun ofString (Ljava/lang/String;Lnet/kyori/adventure/text/Component;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip; + public static synthetic fun ofString$default (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip$Companion;Ljava/lang/String;Lnet/kyori/adventure/text/Component;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/StringTooltip; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter : java/lang/Enum { + public static final field NONE Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter; + public static final field PREFIX Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter; + public static fun values ()[Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionFilter; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionInfo { + public fun (Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Lnet/minestom/server/command/CommandSender; + public final fun component2 ()Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;Ljava/lang/String;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionInfo; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionInfo;Lnet/minestom/server/command/CommandSender;Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getCurrentArg ()Ljava/lang/String; + public final fun getCurrentInput ()Ljava/lang/String; + public final fun getPreviousArgs ()Ldev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments; + public final fun getSender ()Lnet/minestom/server/command/CommandSender; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch { + public static final field Companion Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch$Companion; + public final fun branch ([Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch; + public final fun enforceReplacements (Lnet/minestom/server/command/CommandSender;[Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun getNextSuggestion (Lnet/minestom/server/command/CommandSender;[Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch$Companion { + public final fun suggest ([Ldev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch; +} + +public final class dev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip { + public fun (Ljava/lang/Object;Lnet/kyori/adventure/text/Component;)V + public final fun component1 ()Ljava/lang/Object; + public final fun component2 ()Lnet/kyori/adventure/text/Component; + public final fun copy (Ljava/lang/Object;Lnet/kyori/adventure/text/Component;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip; + public static synthetic fun copy$default (Ldev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip;Ljava/lang/Object;Lnet/kyori/adventure/text/Component;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip; + public fun equals (Ljava/lang/Object;)Z + public final fun getSuggestion ()Ljava/lang/Object; + public final fun getTooltip ()Lnet/kyori/adventure/text/Component; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/coroutine/MinestomDispatchers { + public static final field INSTANCE Ldev/slne/surf/api/minestom/coroutine/MinestomDispatchers; + public final fun getBlocking ()Lkotlinx/coroutines/CoroutineDispatcher; + public final fun getMain ()Lkotlinx/coroutines/CoroutineDispatcher; +} + +public final class dev/slne/surf/api/minestom/coroutine/MinestomScopeProviderKt { + public static final fun getMinestomAsyncScope ()Lkotlinx/coroutines/CoroutineScope; + public static final fun getMinestomBlockingScope ()Lkotlinx/coroutines/CoroutineScope; + public static final fun getMinestomScope ()Lkotlinx/coroutines/CoroutineScope; } public final class dev/slne/surf/api/minestom/dialog/CommonDialogsKt { @@ -372,7 +2308,7 @@ public final class dev/slne/surf/api/minestom/dialog/callback/DialogCallbackCont public fun toString ()Ljava/lang/String; } -public final class dev/slne/surf/api/minestom/dialog/callback/DialogCallbackListener : dev/slne/minestom/lobby/api/event/EventRegistrar { +public final class dev/slne/surf/api/minestom/dialog/callback/DialogCallbackListener : dev/slne/surf/api/minestom/event/EventRegistrar { public fun ()V public fun register (Lnet/minestom/server/event/EventNode;)V } @@ -476,7 +2412,59 @@ public final class dev/slne/surf/api/minestom/dialog/search/SearchInput { public fun toString ()Ljava/lang/String; } -public final class dev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader : dev/slne/minestom/lobby/api/event/EventRegistrar { +public abstract interface class dev/slne/surf/api/minestom/event/EventRegistrar { + public abstract fun register (Lnet/minestom/server/event/EventNode;)V +} + +public final class dev/slne/surf/api/minestom/event/SuspendingEventNode { + public static final field Companion Ldev/slne/surf/api/minestom/event/SuspendingEventNode$Companion; + public fun (Ljava/lang/String;)V + public final fun addListener (ILkotlin/jvm/functions/Function2;)Ldev/slne/surf/api/minestom/event/SuspendingEventNode$Registration; + public static synthetic fun addListener$default (Ldev/slne/surf/api/minestom/event/SuspendingEventNode;ILkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ldev/slne/surf/api/minestom/event/SuspendingEventNode$Registration; + public final fun call (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/event/SuspendingEventNode$Companion { +} + +public final class dev/slne/surf/api/minestom/event/SuspendingEventNode$Registration : java/lang/AutoCloseable { + public fun close ()V +} + +public final class dev/slne/surf/api/minestom/extension/ServerKt { + public static final fun getAdvancementManager ()Lnet/minestom/server/advancements/AdvancementManager; + public static final fun getBannerPatternRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getBiomeRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getBlockManager ()Lnet/minestom/server/instance/block/BlockManager; + public static final fun getBossBarManager ()Lnet/minestom/server/adventure/bossbar/BossBarManager; + public static final fun getChatTypeRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getCommandManager ()Lnet/minestom/server/command/CommandManager; + public static final fun getConnectionManager ()Lnet/minestom/server/network/ConnectionManager; + public static final fun getDamageTypeRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getDimensionTypeRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getEnchantmentEntityEffects ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getEnchantmentLevelBasedValues ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getEnchantmentLocationEffects ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getEnchantmentRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getEnchantmentValueEffects ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getExceptionManager ()Lnet/minestom/server/exception/ExceptionManager; + public static final fun getGlobalEventHandler ()Lnet/minestom/server/event/GlobalEventHandler; + public static final fun getInstanceManager ()Lnet/minestom/server/instance/InstanceManager; + public static final fun getInstrumentRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getJukeboxSongRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getPacketListenerManager ()Lnet/minestom/server/listener/manager/PacketListenerManager; + public static final fun getPacketParser ()Lnet/minestom/server/network/packet/PacketParser; + public static final fun getPaintingVariantRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getRecipeManager ()Lnet/minestom/server/recipe/RecipeManager; + public static final fun getSchedulerManager ()Lnet/minestom/server/timer/SchedulerManager; + public static final fun getServer ()Lnet/minestom/server/ServerProcess; + public static final fun getTeamManager ()Lnet/minestom/server/scoreboard/TeamManager; + public static final fun getTrimMaterialRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getTrimPatternRegistry ()Lnet/minestom/server/registry/DynamicRegistry; + public static final fun getWolfVariantRegistry ()Lnet/minestom/server/registry/DynamicRegistry; +} + +public final class dev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader : dev/slne/surf/api/minestom/event/EventRegistrar { public static final field Companion Ldev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader$Companion; public fun ()V public final fun disable ()V @@ -1295,3 +3283,72 @@ public final class dev/slne/surf/api/minestom/inventory/framework/view/util/Glyp public static final fun shift (I)Ljava/lang/String; } +public final class dev/slne/surf/api/minestom/player/Connection_manager_extKt { + public static final fun findOnlineSurfPlayer (Lnet/minestom/server/network/ConnectionManager;Ljava/lang/String;)Ldev/slne/surf/api/minestom/player/SurfPlayer; + public static final fun getConfigSurfPlayers (Lnet/minestom/server/network/ConnectionManager;)Ljava/util/Collection; + public static final fun getOnlineSurfPlayerByUsername (Lnet/minestom/server/network/ConnectionManager;Ljava/lang/String;)Ldev/slne/surf/api/minestom/player/SurfPlayer; + public static final fun getOnlineSurfPlayerByUuid (Lnet/minestom/server/network/ConnectionManager;Ljava/util/UUID;)Ldev/slne/surf/api/minestom/player/SurfPlayer; + public static final fun getOnlineSurfPlayers (Lnet/minestom/server/network/ConnectionManager;)Ljava/util/Collection; + public static final fun getSurfPlayer (Lnet/minestom/server/network/ConnectionManager;Ljava/util/UUID;)Ldev/slne/surf/api/minestom/player/SurfPlayer; + public static final fun getSurfPlayer (Lnet/minestom/server/network/ConnectionManager;Lnet/minestom/server/network/player/PlayerConnection;)Ldev/slne/surf/api/minestom/player/SurfPlayer; +} + +public final class dev/slne/surf/api/minestom/player/Player_extKt { + public static final fun getSurfPlayer (Lnet/minestom/server/event/trait/PlayerEvent;)Ldev/slne/surf/api/minestom/player/SurfPlayer; + public static final fun requireSurfPlayer (Lnet/minestom/server/entity/Player;)Ldev/slne/surf/api/minestom/player/SurfPlayer; +} + +public abstract class dev/slne/surf/api/minestom/player/SurfPlayer : net/minestom/server/entity/Player { + protected fun (Lnet/minestom/server/network/player/PlayerConnection;Lnet/minestom/server/network/player/GameProfile;)V + public abstract fun captureSignedMessage (Lnet/kyori/adventure/chat/SignedMessage;Lnet/kyori/adventure/text/Component;)Ldev/slne/surf/api/minestom/chat/RemoteSignedMessage; + public abstract fun chatSession ()Lnet/minestom/server/crypto/ChatSession; + public final fun displayName ()Lnet/kyori/adventure/text/Component; + public abstract fun hasPermission (Ljava/lang/String;)Z + public abstract fun sendRemoteSignedMessage (Ldev/slne/surf/api/minestom/chat/RemoteChatSender;Ldev/slne/surf/api/minestom/chat/RemoteSignedMessage;Lnet/kyori/adventure/text/Component;)V + public abstract fun sendSignedMessage (Lnet/kyori/adventure/chat/SignedMessage;Lnet/kyori/adventure/text/Component;Lnet/kyori/adventure/text/Component;)V +} + +public abstract class dev/slne/surf/api/minestom/plugin/MinestomPlugin : com/google/inject/AbstractModule { + public fun (Ljava/lang/Class;)V + protected final fun bindCommandRegistrar (Ljava/lang/Class;)V + protected final fun bindEventRegistrar (Ljava/lang/Class;)V + protected final fun configure ()V + protected fun configurePlugin ()V + public final fun getCommandRegistrars ()Ljava/util/Set; + public final fun getEntrypoint ()Ljava/lang/Class; + public final fun getEventRegistrars ()Ljava/util/Set; + public final fun getMeta ()Ldev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta; +} + +public abstract interface class dev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint { + public fun afterStart (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun start (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public fun stop (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class dev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint$DefaultImpls { + public static fun afterStart (Ldev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static fun stop (Ldev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public abstract interface annotation class dev/slne/surf/api/minestom/plugin/annotation/DataDirectory : java/lang/annotation/Annotation { +} + +public abstract interface annotation class dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta : java/lang/annotation/Annotation { + public static final field Companion Ldev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta$Companion; + public abstract fun dependsOn ()[Ljava/lang/String; + public abstract fun id ()Ljava/lang/String; +} + +public final class dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta$Companion { + public final fun getID_PATTERN ()Lkotlin/text/Regex; +} + +public abstract interface annotation class dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta$Companion$MinestomPluginIdPattern : java/lang/annotation/Annotation { +} + +public final class dev/slne/surf/api/minestom/util/Uuid_extKt { + public static final fun getNIL_UUID ()Ljava/util/UUID; + public static final fun toByteArray (Ljava/util/UUID;)[B +} + diff --git a/surf-api-minestom/build.gradle.kts b/surf-api-minestom/build.gradle.kts index ad51a80c1..4aace0813 100644 --- a/surf-api-minestom/build.gradle.kts +++ b/surf-api-minestom/build.gradle.kts @@ -10,7 +10,10 @@ dependencies { } implementation(projects.surfApiCore.surfApiCoreServer) - compileOnlyApi(libs.surf.minestom.lobby.api) + + compileOnlyApi(libs.minestom) + compileOnlyApi(libs.mojang.brigadier) + compileOnly(libs.guice) api(libs.guava) api(libs.dazzleconf) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomEntrypoint.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomEntrypoint.kt index 9cbcc784f..7a6fa40c9 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomEntrypoint.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomEntrypoint.kt @@ -3,7 +3,7 @@ package dev.slne.surf.api.minestom import com.github.retrooper.packetevents.PacketEvents import com.google.inject.Inject import com.google.inject.Singleton -import dev.slne.minestom.lobby.api.plugin.MinestomPluginEntrypoint +import dev.slne.surf.api.minestom.plugin.MinestomPluginEntrypoint import dev.slne.surf.api.core.extensions.packetEvents import dev.slne.surf.api.core.server.packet.NoopPacketEvents import dev.slne.surf.api.minestom.impl.SurfMinestomInstance diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomPlugin.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomPlugin.kt index e2b5b3202..718b29bd0 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomPlugin.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/SurfApiMinestomPlugin.kt @@ -1,8 +1,8 @@ package dev.slne.surf.api.minestom import com.google.auto.service.AutoService -import dev.slne.minestom.lobby.api.plugin.MinestomPlugin -import dev.slne.minestom.lobby.api.plugin.annotation.MinestomPluginMeta +import dev.slne.surf.api.minestom.plugin.MinestomPlugin +import dev.slne.surf.api.minestom.plugin.annotation.MinestomPluginMeta import dev.slne.surf.api.minestom.dialog.callback.DialogCallbackListener import dev.slne.surf.api.minestom.impl.inventory.framework.MinestomInventoryLoader diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt new file mode 100644 index 000000000..7433f44c4 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt @@ -0,0 +1,83 @@ +package dev.slne.surf.api.minestom.chat + +import dev.slne.surf.api.minestom.event.SuspendingEventNode +import dev.slne.surf.api.minestom.player.SurfPlayer +import net.kyori.adventure.audience.Audience +import net.kyori.adventure.chat.SignedMessage +import net.kyori.adventure.text.Component +import org.jetbrains.annotations.ApiStatus + +/** + * Fired when a [SurfPlayer] sends a chat message. + * + * Listeners run off the tick thread on + * a virtual thread, so they may suspend *and* they may block + * without affecting the server's tick rate. + * + * Messages from one player are processed strictly in order, so a slow listener delays that player's + * next message. + * + * ``` + * AsyncChatEvent.addListener { event -> + * val prefix = database.loadPrefix(event.player.uuid) // suspending or blocking, both fine + * event.renderer = ChatRenderer.viewerUnaware { _, name, message -> + * Component.text().append(prefix).append(name).append(Component.text(": ")).append(message).build() + * } + * } + * ``` + */ +class AsyncChatEvent @ApiStatus.Internal constructor( + + val player: SurfPlayer, + + /** + * The [Audience]s that this chat message will be displayed to. + * + * Can be modified to add and remove viewers. + */ + val viewers: MutableSet, + + /** + * The renderer used to turn [message] into the component every viewer sees. + */ + var renderer: ChatRenderer, + + /** + * The user-supplied message. + */ + var message: Component, + + /** + * The original and unmodified user-supplied message. + * + * The value will **not** reflect changes made through [message]. + */ + val originalMessage: Component, + + /** + * The signed message backing this event. + * + * Changes made in this event will **not** update the signed message. + */ + val signedMessage: SignedMessage, +) { + + var isCancelled = false + + companion object { + @ApiStatus.Internal + val node = SuspendingEventNode("async-chat") + + typealias AsyncChatEventListener = suspend (AsyncChatEvent) -> Unit + + /** + * Registers a chat listener. Lower [priority] runs first. + * + * @see SuspendingEventNode.addListener + */ + fun addListener( + priority: Int = 0, + listener: AsyncChatEventListener + ) = node.addListener(priority, listener) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ChatRenderer.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ChatRenderer.kt new file mode 100644 index 000000000..a7d507e1f --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ChatRenderer.kt @@ -0,0 +1,74 @@ +package dev.slne.surf.api.minestom.chat + +import net.kyori.adventure.audience.Audience +import net.kyori.adventure.text.Component +import net.minestom.server.entity.Player +import org.jetbrains.annotations.ApiStatus + +/** + * A chat renderer is responsible for rendering chat messages sent by [Player]s to the server. + */ +fun interface ChatRenderer { + + /** + * Renders a chat message. This will be called once for each receiving [Audience]. + * + * @param source the message source + * @param sourceDisplayName the display name of the source player + * @param message the chat message + * @param viewer the receiving [Audience] + * @return a rendered chat message + */ + @ApiStatus.OverrideOnly + suspend fun render( + source: Player, + sourceDisplayName: Component, + message: Component, + viewer: Audience + ): Component + + /** + * Marker for the renderer returned by [defaultRenderer]. + */ + @ApiStatus.Internal + sealed interface Default : ChatRenderer, ViewerUnaware + + /** + * Similar to [ChatRenderer], but without knowledge of the message viewer. + * + * @see viewerUnaware + */ + fun interface ViewerUnaware { + + /** + * Renders a chat message. + * + * @param source the message source + * @param sourceDisplayName the display name of the source player + * @param message the chat message + * @return a rendered chat message + */ + @ApiStatus.OverrideOnly + suspend fun render(source: Player, sourceDisplayName: Component, message: Component): Component + } + + companion object { + + /** + * Creates a new instance of the default [ChatRenderer]. + */ + fun defaultRenderer(): ChatRenderer = + ViewerUnawareChatRenderer.Default { _, sourceDisplayName, message -> + Component.translatable("chat.type.text", sourceDisplayName, message) + } + + /** + * Creates a new viewer-unaware [ChatRenderer], which will render the chat message a single + * time, displaying the same rendered message to every viewing [Audience]. + * + * @param renderer the viewer unaware renderer + */ + fun viewerUnaware(renderer: ViewerUnaware): ChatRenderer = + ViewerUnawareChatRenderer.Impl(renderer) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteChatSender.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteChatSender.kt new file mode 100644 index 000000000..0e26aaee9 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteChatSender.kt @@ -0,0 +1,16 @@ +package dev.slne.surf.api.minestom.chat + +import net.minestom.server.crypto.ChatSession +import java.util.UUID + +/** + * The player a [RemoteSignedMessage] came from, as far as the receiving server knows them. + * + * [session] is the chat session the message was signed under. It is `null` for a sender that had + * none, in which case the message is shown as unsigned. + */ +data class RemoteChatSender( + val uuid: UUID, + val username: String, + val session: ChatSession?, +) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt new file mode 100644 index 000000000..4cb0bdfa6 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt @@ -0,0 +1,37 @@ +package dev.slne.surf.api.minestom.chat + +import net.kyori.adventure.text.Component +import net.minestom.server.crypto.MessageSignature +import java.time.Instant +import java.util.UUID + +/** + * A signed chat message in a form that survives leaving this server. + * + * It carries everything a client needs to verify the signature, so a server that never saw the + * sender can still show the message as signed. A message from a sender without a chat session has no + * [signature], a nil [sessionId] and is shown as unsigned. + * + * @see dev.slne.surf.api.minestom.player.SurfPlayer.captureSignedMessage + * @see dev.slne.surf.api.minestom.player.SurfPlayer.sendRemoteSignedMessage + */ +data class RemoteSignedMessage( + val sender: UUID, + val sessionId: UUID, + + /** The position of the message in the signature chain of its session. */ + val index: Int, + + val signature: MessageSignature?, + + /** The message as it was signed, which is the plain text the sender typed. */ + val content: String, + val timestamp: Instant, + val salt: Long, + + /** The signatures of the messages the sender had seen, which the signature also covers. */ + val lastSeen: List, + + /** What the receiver sees instead of [content]. */ + val unsignedContent: Component?, +) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ViewerUnawareChatRenderer.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ViewerUnawareChatRenderer.kt new file mode 100644 index 000000000..43390a565 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/ViewerUnawareChatRenderer.kt @@ -0,0 +1,36 @@ +package dev.slne.surf.api.minestom.chat + +import net.kyori.adventure.audience.Audience +import net.kyori.adventure.text.Component +import net.minestom.server.entity.Player + +/** + * Adapts a [ChatRenderer.ViewerUnaware] to a full [ChatRenderer], rendering the message only once + * and reusing the result for every viewer. + */ +internal sealed class ViewerUnawareChatRenderer( + private val unaware: ChatRenderer.ViewerUnaware +) : ChatRenderer, ChatRenderer.ViewerUnaware { + + private var rendered: Component? = null + + override suspend fun render( + source: Player, + sourceDisplayName: Component, + message: Component, + viewer: Audience + ): Component = render(source, sourceDisplayName, message) + + override suspend fun render( + source: Player, + sourceDisplayName: Component, + message: Component + ): Component = rendered ?: unaware.render(source, sourceDisplayName, message).also { + rendered = it + } + + class Impl(unaware: ChatRenderer.ViewerUnaware) : ViewerUnawareChatRenderer(unaware) + + class Default(unaware: ChatRenderer.ViewerUnaware) : + ViewerUnawareChatRenderer(unaware), ChatRenderer.Default +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessages.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessages.kt new file mode 100644 index 000000000..b42e2cd33 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessages.kt @@ -0,0 +1,67 @@ +package dev.slne.surf.api.minestom.chat.signature + +import com.google.common.primitives.Ints +import dev.slne.surf.api.minestom.chat.signature.LastSeenMessages.Update.Companion.IGNORE_CHECKSUM +import net.minestom.server.crypto.MessageSignature +import net.minestom.server.network.packet.client.play.ClientChatMessagePacket +import net.minestom.server.network.packet.client.play.ClientSignedCommandChatPacket +import java.util.BitSet +import net.minestom.server.crypto.LastSeenMessages as NetworkLastSeenMessages + +@JvmInline +value class LastSeenMessages(val entries: List) { + + companion object { + const val LAST_SEEN_MESSAGES_MAX_LENGTH = 20 + + val EMPTY = LastSeenMessages(emptyList()) + } + + fun computeChecksum(): Byte { + var checksum = 1 + + for (entry in entries) { + checksum = 31 * checksum + entry.checksum() + } + + val checksumByte = checksum.toByte() + + return if (checksumByte == IGNORE_CHECKSUM) 1 else checksumByte + } + + fun updateSignature(output: SignatureUpdater.Output) { + output.update(Ints.toByteArray(entries.size)) + + for (entry in entries) { + output.update(entry.signature()) + } + } + + fun pack(cache: MessageSignatureCache): NetworkLastSeenMessages.Packed = + NetworkLastSeenMessages.Packed(entries.map { it.pack(cache) }) + + data class Update( + val offset: Int, + val acknowledged: BitSet, + val checksum: Byte + ) { + companion object { + const val IGNORE_CHECKSUM = 0.toByte() + + fun fromPacket(packet: ClientChatMessagePacket) = Update( + offset = packet.ackOffset(), + acknowledged = packet.ackList(), + checksum = packet.checksum() + ) + + fun fromPacket(packet: ClientSignedCommandChatPacket) = Update( + offset = packet.lastSeenMessages().offset(), + acknowledged = packet.lastSeenMessages().acknowledged(), + checksum = packet.checksum() + ) + } + + fun verifyChecksum(lastSeen: LastSeenMessages): Boolean = + checksum == IGNORE_CHECKSUM || checksum == lastSeen.computeChecksum() + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator.kt new file mode 100644 index 000000000..5a41a9a26 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenMessagesValidator.kt @@ -0,0 +1,88 @@ +package dev.slne.surf.api.minestom.chat.signature + +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import net.minestom.server.crypto.MessageSignature +import java.io.Serial + +class LastSeenMessagesValidator( + private val lastSeenCount: Int = LastSeenMessages.LAST_SEEN_MESSAGES_MAX_LENGTH +) { + + private val trackedMessages = ObjectArrayList().apply { + repeat(lastSeenCount) { add(null) } + } + + private var lastPendingMessage: MessageSignature? = null + + val trackedMessagesCount get() = trackedMessages.size + + fun addPending(message: MessageSignature) { + if (message != lastPendingMessage) { + trackedMessages.add(LastSeenTrackedEntry(message, true)) + lastPendingMessage = message + } + } + + fun applyOffset(offset: Int) { + val maxOffset = trackedMessages.size - lastSeenCount + if (offset !in 0..maxOffset) { + throw ValidationException( + "Advanced last seen window by $offset messages, but expected at most $maxOffset" + ) + } + + trackedMessages.removeElements(0, offset) + } + + fun applyUpdate(update: LastSeenMessages.Update): LastSeenMessages { + applyOffset(update.offset) + + val lastSeenEntries = ObjectArrayList(update.acknowledged.cardinality()) + val ackLength = update.acknowledged.length() + if (ackLength > lastSeenCount) { + throw ValidationException( + "Last seen update contained $ackLength messages, but maximum window size is $lastSeenCount" + ) + } + + for (i in 0 until lastSeenCount) { + val acknowledged = update.acknowledged.get(i) + val message = trackedMessages[i] + + if (acknowledged) { + if (message == null) { + throw ValidationException( + "Last seen update acknowledged unknown or previously ignored message at index $i" + ) + } + + trackedMessages[i] = message.acknowledge() + lastSeenEntries.add(message.signature) + } else { + if (message != null && !message.pending) { + throw ValidationException( + "Last seen update ignored previously acknowledged message at index $i and signature ${message.signature}" + ) + } + + trackedMessages[i] = null + } + } + + val lastSeen = LastSeenMessages(lastSeenEntries) + if (!update.verifyChecksum(lastSeen)) { + throw ValidationException( + "Checksum mismatch on last seen update: the client and server must have desynced" + ) + } + + return lastSeen + } + + class ValidationException(message: String) : Exception(message, null, false, false) { + companion object { + @Serial + private const val serialVersionUID: Long = -5942795035956998806L + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry.kt new file mode 100644 index 000000000..c458dbcf5 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/LastSeenTrackedEntry.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.minestom.server.crypto.MessageSignature + + +data class LastSeenTrackedEntry( + val signature: MessageSignature, + val pending: Boolean +) { + fun acknowledge(): LastSeenTrackedEntry = if (!pending) this else copy(pending = false) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCache.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCache.kt new file mode 100644 index 000000000..c20efc2df --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCache.kt @@ -0,0 +1,76 @@ +package dev.slne.surf.api.minestom.chat.signature + +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet +import net.minestom.server.crypto.MessageSignature + + +class MessageSignatureCache(capacity: Int = DEFAULT_CAPACITY) { + + private class Entry(val signature: MessageSignature) { + val hash = signature.hashCode() + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Entry) return false + + if (hash != other.hash) return false + if (signature != other.signature) return false + + return true + } + + override fun hashCode(): Int { + return hash + } + } + + private val entries = arrayOfNulls(capacity) + + fun pack(signature: MessageSignature): Int { + val hash = signature.hashCode() + + for (index in entries.indices) { + val entry = entries[index] ?: continue + if (entry.hash == hash && entry.signature == signature) return index + } + + return NOT_FOUND + } + + fun unpack(id: Int): MessageSignature? = entries[id]?.signature + + fun push(body: SignedMessageBody, signature: MessageSignature?) { + val lastSeen = body.lastSeen.entries + val queue = ArrayDeque(lastSeen.size + 1) + lastSeen.forEach { entry -> queue.addLast(Entry(entry)) } + + if (signature != null) { + queue.addLast(Entry(signature)) + } + + push(queue) + } + + private fun push(queue: ArrayDeque) { + val newEntries = ObjectOpenHashSet(queue) + + var index = 0 + while (queue.isNotEmpty() && index < entries.size) { + val previous = entries[index] + entries[index] = queue.removeLast() + + if (previous != null && !newEntries.contains(previous)) { + queue.addFirst(previous) + } + + index++ + } + } + + companion object { + const val NOT_FOUND = -1 + private const val DEFAULT_CAPACITY = 128 + + fun createDefault() = MessageSignatureCache(DEFAULT_CAPACITY) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage.kt new file mode 100644 index 000000000..106877081 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/PlayerChatMessage.kt @@ -0,0 +1,129 @@ +package dev.slne.surf.api.minestom.chat.signature + +import com.google.common.primitives.Ints +import dev.slne.surf.api.minestom.util.NIL_UUID +import net.kyori.adventure.chat.SignedMessage +import net.kyori.adventure.identity.Identity +import net.kyori.adventure.text.Component +import net.minestom.server.crypto.FilterMask +import net.minestom.server.crypto.MessageSignature +import java.time.Duration +import java.time.Instant +import java.util.UUID + + +data class PlayerChatMessage( + val link: SignedMessageLink, + val signature: MessageSignature?, + val signedBody: SignedMessageBody, + val unsignedContent: Component?, + val filterMask: FilterMask +) { + companion object { + private val SYSTEM_SENDER = NIL_UUID + + val MESSAGE_EXPIRES_AFTER_SERVER: Duration = Duration.ofMinutes(5L) + val MESSAGE_EXPIRES_AFTER_CLIENT: Duration = + MESSAGE_EXPIRES_AFTER_SERVER.plus(Duration.ofMinutes(2L)) + + fun system(content: String) = unsigned(SYSTEM_SENDER, content) + + fun unsigned(sender: UUID, content: String) = PlayerChatMessage( + link = SignedMessageLink.unsigned(sender), + signature = null, + signedBody = SignedMessageBody.unsigned(content), + unsignedContent = null, + filterMask = FILTER_MASK_PASS_THROUGH + ) + + fun updateSignature( + output: SignatureUpdater.Output, + link: SignedMessageLink, + body: SignedMessageBody + ) { + output.update(Ints.toByteArray(1)) + link.updateSignature(output) + body.updateSignature(output) + } + } + + fun withUnsignedContent(content: Component) = + copy(unsignedContent = if (content != Component.text(signedContent())) content else null) + + fun removeUnsignedContent() = + if (unsignedContent != null) copy(unsignedContent = null) else this + + fun filter(filterMask: FilterMask) = + if (this.filterMask == filterMask) this else copy(filterMask = filterMask) + + fun filter(filtered: Boolean) = filter(if (filtered) filterMask else FILTER_MASK_PASS_THROUGH) + + fun removeSignature() = PlayerChatMessage( + link = SignedMessageLink.unsigned(sender()), + signature = null, + signedBody = SignedMessageBody.unsigned(signedContent()), + unsignedContent = unsignedContent, + filterMask = filterMask + ) + + fun verify(signatureValidator: SignatureValidator): Boolean = + signature != null && signature.verify(signatureValidator) { output -> + updateSignature(output, link, signedBody) + } + + fun signedContent() = signedBody.content + + fun decoratedContent(): Component = unsignedContent ?: Component.text(signedContent()) + + fun timeStamp() = signedBody.timeStamp + + fun salt() = signedBody.salt + + fun hasExpiredServer(now: Instant): Boolean = + now.isAfter(timeStamp().plus(MESSAGE_EXPIRES_AFTER_SERVER)) + + fun hasExpiredClient(now: Instant): Boolean = + now.isAfter(timeStamp().plus(MESSAGE_EXPIRES_AFTER_CLIENT)) + + fun sender() = link.sender + + fun isSystem() = sender() == SYSTEM_SENDER + + fun hasSignature() = signature != null + + fun hasSignatureFrom(profileId: UUID) = hasSignature() && link.sender == profileId + + fun isFullyFiltered() = filterMask.isFullyFiltered() + + fun describeSigned(): String = buildString { + append("'").append(signedBody.content).append("' @ ").append(signedBody.timeStamp) + append("\n - From: ").append(link.sender).append("/").append(link.sessionId) + append(", message #").append(link.index) + append("\n - Salt: ").append(signedBody.salt) + append("\n - Signature: ").append(signature.describe()) + append("\n - Last Seen: [\n") + for (entry in signedBody.lastSeen.entries) { + append(" ").append(entry.describe()).append("\n") + } + append(" ]\n") + } + + fun adventureView() = AdventureView() + + inner class AdventureView : SignedMessage { + override fun timestamp(): Instant = this@PlayerChatMessage.timeStamp() + + override fun salt(): Long = this@PlayerChatMessage.salt() + + override fun signature(): SignedMessage.Signature? = + this@PlayerChatMessage.signature?.adventure() + + override fun unsignedContent(): Component? = this@PlayerChatMessage.unsignedContent + + override fun message(): String = this@PlayerChatMessage.signedContent() + + override fun identity(): Identity = Identity.identity(sender()) + + val playerChatMessage get() = this@PlayerChatMessage + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/ProfilePublicKey.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/ProfilePublicKey.kt new file mode 100644 index 000000000..7e10bc56d --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/ProfilePublicKey.kt @@ -0,0 +1,60 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.kyori.adventure.text.Component +import net.minestom.server.crypto.PlayerPublicKey +import net.minestom.server.utils.crypto.KeyUtils +import java.io.Serial +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.time.Instant +import java.util.UUID +import net.minestom.server.crypto.SignatureValidator as ServiceSignatureValidator + +val EXPIRED_PROFILE_PUBLIC_KEY: Component = + Component.translatable("multiplayer.disconnect.expired_public_key") + +val INVALID_PROFILE_PUBLIC_KEY_SIGNATURE: Component = + Component.translatable("multiplayer.disconnect.invalid_public_key_signature") + + +class ProfilePublicKeyValidationException(val component: Component) : Exception(null, null, false, false) { + companion object { + @Serial + private const val serialVersionUID: Long = -4832597595024741094L + } +} + +fun PlayerPublicKey.createValidated( + validator: ServiceSignatureValidator, + profileId: UUID +): PlayerPublicKey { + if (!validateSignature(validator, profileId)) { + throw ProfilePublicKeyValidationException(INVALID_PROFILE_PUBLIC_KEY_SIGNATURE) + } + + return this +} + +@Suppress("UnstableApiUsage") +fun PlayerPublicKey.createSignatureValidator(): SignatureValidator = + SignatureValidator.from(publicKey(), KeyUtils.SignatureAlgorithm.SHA256withRSA.name) + +fun PlayerPublicKey.hasExpired() = expiresAt().isBefore(Instant.now()) + +fun PlayerPublicKey.validateSignature( + validator: ServiceSignatureValidator, + profileId: UUID +): Boolean = validator.validate(signedPayload(profileId), signature()) + +private fun PlayerPublicKey.signedPayload(profileId: UUID): ByteArray { + val keyBytes = publicKey().encoded + val signedPayload = ByteArray(24 + keyBytes.size) + + ByteBuffer.wrap(signedPayload).order(ByteOrder.BIG_ENDIAN) + .putLong(profileId.mostSignificantBits) + .putLong(profileId.leastSignificantBits) + .putLong(expiresAt().toEpochMilli()) + .put(keyBytes) + + return signedPayload +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/RemoteChatSession.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/RemoteChatSession.kt new file mode 100644 index 000000000..640310577 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/RemoteChatSession.kt @@ -0,0 +1,30 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.minestom.server.crypto.ChatSession +import net.minestom.server.crypto.PlayerPublicKey +import java.util.UUID +import net.minestom.server.crypto.SignatureValidator as ServiceSignatureValidator + +data class RemoteChatSession( + val sessionId: UUID, + val profilePublicKey: PlayerPublicKey +) { + + companion object { + fun validate( + data: ChatSession, + profileId: UUID, + serviceSignatureValidator: ServiceSignatureValidator + ) = RemoteChatSession( + sessionId = data.sessionId(), + profilePublicKey = data.publicKey().createValidated(serviceSignatureValidator, profileId) + ) + } + + fun createMessageDecoder(profileId: UUID): SignedMessageChain.Decoder = + SignedMessageChain(profileId, sessionId).decoder(profilePublicKey) + + fun hasExpired() = profilePublicKey.hasExpired() + + fun asData(): ChatSession = ChatSession(sessionId, profilePublicKey) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureUpdater.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureUpdater.kt new file mode 100644 index 000000000..2780a0dc8 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureUpdater.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.api.minestom.chat.signature + + +fun interface SignatureUpdater { + fun update(output: Output) + + fun interface Output { + fun update(payload: ByteArray) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureValidator.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureValidator.kt new file mode 100644 index 000000000..b42ce3da3 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignatureValidator.kt @@ -0,0 +1,32 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.kyori.adventure.text.logger.slf4j.ComponentLogger +import java.security.PublicKey +import java.security.Signature + +fun interface SignatureValidator { + + fun validate(updater: SignatureUpdater, signature: ByteArray): Boolean + + fun validate(payload: ByteArray, signature: ByteArray): Boolean = + validate({ output -> output.update(payload) }, signature) + + companion object { + private val LOGGER = ComponentLogger.logger() + + val NO_VALIDATION = SignatureValidator { _, _ -> true } + + fun from(publicKey: PublicKey, algorithm: String) = + SignatureValidator { updater, signature -> + try { + val verifier = Signature.getInstance(algorithm) + verifier.initVerify(publicKey) + updater.update(verifier::update) + verifier.verify(signature) + } catch (e: Exception) { + LOGGER.error("Failed to verify signature", e) + false + } + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageBody.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageBody.kt new file mode 100644 index 000000000..93c74dbf4 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageBody.kt @@ -0,0 +1,34 @@ +package dev.slne.surf.api.minestom.chat.signature + +import com.google.common.primitives.Ints +import com.google.common.primitives.Longs +import java.time.Instant +import net.minestom.server.crypto.SignedMessageBody as NetworkSignedMessageBody + + +data class SignedMessageBody( + val content: String, + val timeStamp: Instant, + val salt: Long, + val lastSeen: LastSeenMessages +) { + + companion object { + fun unsigned(content: String) = + SignedMessageBody(content, Instant.now(), 0L, LastSeenMessages.EMPTY) + } + + fun updateSignature(output: SignatureUpdater.Output) { + output.update(Longs.toByteArray(salt)) + output.update(Longs.toByteArray(timeStamp.epochSecond)) + + val contentBytes = content.toByteArray() + output.update(Ints.toByteArray(contentBytes.size)) + output.update(contentBytes) + + lastSeen.updateSignature(output) + } + + fun pack(cache: MessageSignatureCache): NetworkSignedMessageBody.Packed = + NetworkSignedMessageBody.Packed(content, timeStamp, salt, lastSeen.pack(cache)) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageChain.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageChain.kt new file mode 100644 index 000000000..cbd3e1e85 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageChain.kt @@ -0,0 +1,123 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.Component.translatable +import net.kyori.adventure.text.logger.slf4j.ComponentLogger +import net.minestom.server.crypto.MessageSignature +import net.minestom.server.crypto.PlayerPublicKey +import java.io.Serial +import java.time.Instant +import java.util.UUID +import java.util.function.BooleanSupplier + +class SignedMessageChain(profileId: UUID, sessionId: UUID) { + + companion object { + private val LOGGER = ComponentLogger.logger() + } + + private var nextLink: SignedMessageLink? = SignedMessageLink.root(profileId, sessionId) + private var lastTimeStamp: Instant = Instant.EPOCH + + fun encoder(signer: Signer) = Encoder { body -> + val link = nextLink ?: return@Encoder null + nextLink = link.advance() + + MessageSignature(signer.sign { output -> + PlayerChatMessage.updateSignature(output, link, body) + }) + } + + fun decoder(profilePublicKey: PlayerPublicKey): Decoder { + val signatureValidator = profilePublicKey.createSignatureValidator() + + return object : Decoder { + override fun unpack( + signature: MessageSignature?, + body: SignedMessageBody + ): PlayerChatMessage { + if (signature == null) { + throw DecodeException(DecodeException.MISSING_PROFILE_KEY) + } + + if (profilePublicKey.hasExpired()) { + throw DecodeException(DecodeException.EXPIRED_PROFILE_KEY) + } + + val link = nextLink ?: throw DecodeException(DecodeException.CHAIN_BROKEN) + + if (body.timeStamp.isBefore(lastTimeStamp)) { + setChainBroken() + throw DecodeException(DecodeException.OUT_OF_ORDER_CHAT) + } + + lastTimeStamp = body.timeStamp + + val unpacked = PlayerChatMessage( + link = link, + signature = signature, + signedBody = body, + unsignedContent = null, + filterMask = FILTER_MASK_PASS_THROUGH + ) + + if (!unpacked.verify(signatureValidator)) { + setChainBroken() + throw DecodeException(DecodeException.INVALID_SIGNATURE) + } + + if (unpacked.hasExpiredServer(Instant.now())) { + LOGGER.warn( + "Received expired chat: '{}'. Is the client/server system time unsynchronized?", + body.content + ) + } + + nextLink = link.advance() + return unpacked + } + + override fun setChainBroken() { + nextLink = null + } + } + } + + class DecodeException(val component: Component) : Exception(null, null, false, false) { + companion object { + @Serial + private const val serialVersionUID: Long = 6432477898999865178L + + val MISSING_PROFILE_KEY: Component = translatable("chat.disabled.missingProfileKey") + val CHAIN_BROKEN: Component = translatable("chat.disabled.chain_broken") + val EXPIRED_PROFILE_KEY: Component = translatable("chat.disabled.expiredProfileKey") + val INVALID_SIGNATURE: Component = translatable("chat.disabled.invalid_signature") + val OUT_OF_ORDER_CHAT: Component = translatable("chat.disabled.out_of_order_chat") + } + } + + fun interface Decoder { + fun unpack(signature: MessageSignature?, body: SignedMessageBody): PlayerChatMessage + + fun setChainBroken() {} + + companion object { + fun unsigned(profileId: UUID, enforcesSecureChat: BooleanSupplier) = + Decoder { _, body -> + if (enforcesSecureChat.asBoolean) { + throw DecodeException(DecodeException.MISSING_PROFILE_KEY) + } + + PlayerChatMessage.unsigned(profileId, body.content) + } + } + } + + fun interface Encoder { + fun pack(body: SignedMessageBody): MessageSignature? + + companion object { + val UNSIGNED = Encoder { null } + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageLink.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageLink.kt new file mode 100644 index 000000000..58e4cb681 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/SignedMessageLink.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.api.minestom.chat.signature + +import com.google.common.primitives.Ints +import dev.slne.surf.api.minestom.util.NIL_UUID +import dev.slne.surf.api.minestom.util.toByteArray +import java.util.UUID + +data class SignedMessageLink( + val index: Int, + val sender: UUID, + val sessionId: UUID +) { + + companion object { + fun unsigned(sender: UUID) = root(sender, NIL_UUID) + + fun root(sender: UUID, sessionId: UUID) = SignedMessageLink(0, sender, sessionId) + } + + fun isDescendantOf(link: SignedMessageLink): Boolean = + index > link.index && sender == link.sender && sessionId == link.sessionId + + fun advance(): SignedMessageLink? = + if (index == Int.MAX_VALUE) null else copy(index = index + 1) + + fun updateSignature(output: SignatureUpdater.Output) { + output.update(sender.toByteArray()) + output.update(sessionId.toByteArray()) + output.update(Ints.toByteArray(index)) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/Signer.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/Signer.kt new file mode 100644 index 000000000..07b6b852a --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/Signer.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.api.minestom.chat.signature + +import java.security.PrivateKey +import java.security.Signature + + +fun interface Signer { + fun sign(updater: SignatureUpdater): ByteArray + + fun sign(payload: ByteArray): ByteArray = sign { output -> output.update(payload) } + + companion object { + fun from(privateKey: PrivateKey, algorithm: String) = Signer { updater -> + try { + val signer = Signature.getInstance(algorithm) + signer.initSign(privateKey) + updater.update(signer::update) + signer.sign() + } catch (e: Exception) { + throw IllegalStateException("Failed to sign message", e) + } + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/filter-mask-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/filter-mask-ext.kt new file mode 100644 index 000000000..27f2792e1 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/filter-mask-ext.kt @@ -0,0 +1,12 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.minestom.server.crypto.FilterMask +import java.util.* + +val FILTER_MASK_PASS_THROUGH: FilterMask = FilterMask(FilterMask.Type.PASS_THROUGH, BitSet(0)) + +val FILTER_MASK_FULLY_FILTERED: FilterMask = FilterMask(FilterMask.Type.FULLY_FILTERED, BitSet(0)) + +fun FilterMask.isPassThrough(): Boolean = type() == FilterMask.Type.PASS_THROUGH + +fun FilterMask.isFullyFiltered(): Boolean = type() == FilterMask.Type.FULLY_FILTERED diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/message-signature-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/message-signature-ext.kt new file mode 100644 index 000000000..7d700f3b9 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/signature/message-signature-ext.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.kyori.adventure.chat.SignedMessage +import net.minestom.server.crypto.MessageSignature +import java.util.Base64 + + +fun MessageSignature.checksum(): Int = signature().contentHashCode() + +fun MessageSignature.adventure(): SignedMessage.Signature = SignedMessage.signature(signature()) + +fun MessageSignature.verify(validator: SignatureValidator, updater: SignatureUpdater): Boolean = + validator.validate(updater, signature()) + + +fun MessageSignature.pack(cache: MessageSignatureCache): MessageSignature.Packed { + val packedId = cache.pack(this) + return if (packedId != MessageSignatureCache.NOT_FOUND) { + MessageSignature.Packed(packedId, null) + } else { + MessageSignature.Packed(this) + } +} + +fun MessageSignature?.describe(): String = + if (this == null) "" else Base64.getEncoder().encodeToString(signature()) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/CommandRegistrar.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/CommandRegistrar.kt new file mode 100644 index 000000000..0f52e9f5b --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/CommandRegistrar.kt @@ -0,0 +1,13 @@ +package dev.slne.surf.api.minestom.command + +/** + * Registers commands once the command API is ready to accept them. + * + * Implementations build their commands with `CommandAPICommand` or `CommandTree` and register + * them from [register]. Registering outside of this callback is unsupported, because the backing + * platform is only installed for the duration of the server's lifecycle. + */ +interface CommandRegistrar { + + fun register() +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/args/MiniMessageArgument.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/args/MiniMessageArgument.kt index 462923412..3644baaf8 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/args/MiniMessageArgument.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/args/MiniMessageArgument.kt @@ -1,12 +1,12 @@ package dev.slne.surf.api.minestom.command.args -import dev.slne.minestom.lobby.api.command.commandapi.CommandAPI -import dev.slne.minestom.lobby.api.command.commandapi.CommandAPICommand -import dev.slne.minestom.lobby.api.command.commandapi.CommandTree -import dev.slne.minestom.lobby.api.command.commandapi.argument.Argument -import dev.slne.minestom.lobby.api.command.commandapi.argument.CustomArgument -import dev.slne.minestom.lobby.api.command.commandapi.argument.GreedyStringArgument -import dev.slne.minestom.lobby.api.command.commandapi.argument.TextArgument +import dev.slne.surf.api.minestom.command.commandapi.CommandAPI +import dev.slne.surf.api.minestom.command.commandapi.CommandAPICommand +import dev.slne.surf.api.minestom.command.commandapi.CommandTree +import dev.slne.surf.api.minestom.command.commandapi.argument.Argument +import dev.slne.surf.api.minestom.command.commandapi.argument.CustomArgument +import dev.slne.surf.api.minestom.command.commandapi.argument.GreedyStringArgument +import dev.slne.surf.api.minestom.command.commandapi.argument.TextArgument import dev.slne.surf.api.core.command.builder.CommandExceptionBuilder import dev.slne.surf.api.core.minimessage.miniMessage import net.kyori.adventure.text.Component diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPI.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPI.kt new file mode 100644 index 000000000..35d5ee68d --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPI.kt @@ -0,0 +1,62 @@ +package dev.slne.surf.api.minestom.command.commandapi + +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandSyntaxException +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandValidationException +import dev.slne.surf.api.minestom.command.commandapi.internal.CommandAPIPlatform +import net.kyori.adventure.text.Component +import net.minestom.server.command.CommandSender +import org.jetbrains.annotations.ApiStatus +import java.util.concurrent.atomic.AtomicReference + +object CommandAPI { + private val platform = AtomicReference() + + @ApiStatus.Internal + fun installPlatform(value: CommandAPIPlatform) { + check(platform.compareAndSet(null, value)) { + "The CommandAPI platform is already installed" + } + } + + @ApiStatus.Internal + fun uninstallPlatform(value: CommandAPIPlatform) { + platform.compareAndSet(value, null) + } + + @ApiStatus.Internal + fun register(definition: CommandDefinition, namespace: String?): RegisteredCommand { + validateNamespace(namespace) + return installedPlatform().register(definition, namespace) + } + + fun unregister(name: String): Boolean = installedPlatform().unregister(name) + + /** + * Dispatches [input] as [sender] and returns the executed command's result value. + * + * [input] carries no leading slash. Callers that must not throw check ownership first. + * + * @throws com.mojang.brigadier.exceptions.CommandSyntaxException when the command is unknown, an + * argument is rejected, or input remains after a complete syntax. + */ + fun execute(sender: CommandSender, input: String): Int = + installedPlatform().execute(sender, input) + + fun failWithString(message: String): Nothing = failWithMessage(Component.text(message)) + + fun failWithMessage(message: Component): Nothing = throw CommandSyntaxException(message) + + private fun installedPlatform(): CommandAPIPlatform = checkNotNull(platform.get()) { + "The CommandAPI platform has not been installed; register commands after server startup" + } + + private fun validateNamespace(namespace: String?) { + if (namespace != null && !NAMESPACE_PATTERN.matches(namespace)) { + throw CommandValidationException( + "Command namespace '$namespace' must contain only lowercase letters, digits, '.', '_' or '-'", + ) + } + } + + private val NAMESPACE_PATTERN = Regex("[a-z0-9_.-]+") +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPICommand.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPICommand.kt new file mode 100644 index 000000000..8acf39317 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandAPICommand.kt @@ -0,0 +1,390 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi + +import dev.slne.surf.api.minestom.command.commandapi.argument.* +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandValidationException +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandExecutable +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutorDefinition +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutorType +import it.unimi.dsi.fastutil.objects.* +import net.minestom.server.command.CommandSender +import org.jetbrains.annotations.ApiStatus +import java.util.* + +@ApiStatus.Internal +data class CommandDefinition( + val name: String, + val aliases: Set, + val metadata: CommandMetadata, + val paths: List, +) + +@ApiStatus.Internal +data class CommandPath( + val arguments: List>, + val executors: List, + val permissions: Set, + val requirements: List<(CommandSender) -> Boolean>, +) + +class CommandAPICommand(val name: String) : CommandExecutable { + private val aliases = ObjectArrayList() + private val permissions = ObjectLinkedOpenHashSet() + private val requirements = ObjectArrayList<(CommandSender) -> Boolean>() + private val arguments = ObjectArrayList>() + private val subcommands = ObjectArrayList() + private val executors = ObjectArrayList() + + private var shortDescription: String? = null + private val fullDescription = ObjectArrayList() + private val usage = ObjectArrayList() + private var help: String? = null + + fun withAliases(vararg aliases: String): CommandAPICommand = apply { + this.aliases += aliases + } + + fun withPermission(permission: String): CommandAPICommand = apply { + val normalized = permission.trim() + if (normalized.isBlank()) { + throw CommandValidationException("Command permission must not be blank") + } + permissions += normalized + } + + fun withRequirement(requirement: (CommandSender) -> Boolean): CommandAPICommand = apply { + requirements += requirement + } + + fun withArguments(vararg arguments: Argument<*>): CommandAPICommand = apply { + this.arguments += arguments + } + + fun withOptionalArguments(vararg arguments: Argument<*>): CommandAPICommand = apply { + arguments.forEach { argument -> argument.setOptional(true) } + this.arguments += arguments + } + + fun withSubcommand(subcommand: CommandAPICommand): CommandAPICommand = apply { + if (subcommand === this) { + throw CommandValidationException("A command cannot be its own subcommand") + } + subcommands += subcommand + } + + fun withSubcommands(vararg subcommands: CommandAPICommand): CommandAPICommand = apply { + subcommands.forEach(::withSubcommand) + } + + fun withShortDescription(description: String): CommandAPICommand = apply { + shortDescription = description + } + + fun withFullDescription(vararg description: String): CommandAPICommand = apply { + fullDescription.clear() + fullDescription += description + } + + fun withUsage(vararg usage: String): CommandAPICommand = apply { + this.usage.clear() + this.usage += usage + } + + fun withHelp(help: String): CommandAPICommand = apply { + this.help = help + } + + override fun addExecutor(definition: ExecutorDefinition): CommandAPICommand = apply { + executors += definition + } + + @ApiStatus.Internal + fun toDefinition(): CommandDefinition { + val stack = ReferenceOpenHashSet() + + validateCommandLabels(name, aliases) + + val output = ObjectArrayList() + val rootPermissions = immutableSet(permissions) + val rootRequirements = immutableList(requirements) + + if (arguments.isEmpty && executors.isNotEmpty()) { + output += commandPath(emptyList(), executors, rootPermissions, rootRequirements) + } + + val subcommandNodes = ObjectArrayList() + subcommands.forEach { subcommand -> + subcommandNodes.addAll(subcommand.toSubcommandNodes(stack)) + } + + val rootNodes = if (arguments.isEmpty) { + subcommandNodes + } else { + val argumentNodes = ObjectArrayList(arguments.size) + arguments.forEach { argument -> + argumentNodes += argument.toTreeNode() + } + + linearNodes(argumentNodes, executors, subcommandNodes) + } + rootNodes.forEach { node -> + flatten( + emptyList(), + rootPermissions, + rootRequirements, + node, + output + ) + } + + val paths = validateAndFreezePaths(output, name) + return CommandDefinition( + name = name, + aliases = immutableSet(aliases), + metadata = CommandMetadata.snapshot(shortDescription, fullDescription, usage, help), + paths = paths, + ) + } + + fun register(namespace: String? = null): RegisteredCommand = + CommandAPI.register(toDefinition(), namespace) + + private fun toSubcommandNodes( + stack: MutableSet, + ): List { + if (!stack.add(this)) { + throw CommandValidationException("Command '$name' contains a subcommand cycle") + } + + try { + validateCommandLabels(name, aliases) + + val nestedSubcommands = ObjectArrayList() + subcommands.forEach { subcommand -> + nestedSubcommands.addAll(subcommand.toSubcommandNodes(stack)) + } + + val body = if (arguments.isEmpty) { + emptyList() + } else { + val argumentNodes = ObjectArrayList(arguments.size) + arguments.forEach { argument -> + argumentNodes += argument.toTreeNode() + } + + linearNodes(argumentNodes, executors, nestedSubcommands) + } + + val result = ObjectArrayList(aliases.size + 1) + result += createSubcommandNode( + label = name, + nestedSubcommands = nestedSubcommands, + body = body, + ) + + aliases.forEach { alias -> + result += createSubcommandNode( + label = alias, + nestedSubcommands = nestedSubcommands, + body = body, + ) + } + + return ObjectLists.unmodifiable(result) + } finally { + stack.remove(this) + } + } + + private fun createSubcommandNode( + label: String, + nestedSubcommands: List, + body: List, + ): ArgumentTreeNode = ArgumentTreeNode( + argument = LiteralArgument(label).toDefinition(), + executors = if (arguments.isEmpty) immutableList(executors) else emptyList(), + children = if (arguments.isEmpty) nestedSubcommands else body, + permissions = immutableSet(permissions), + requirements = immutableList(requirements), + ) +} + +internal fun validateCommandLabels(name: String, aliases: Collection) { + validateCommandLabel(name, "name") + + val normalized = ObjectOpenHashSet(aliases.size + 1) + normalized += name.lowercase(Locale.ROOT) + + aliases.forEach { alias -> + validateCommandLabel(alias, "alias") + + if (!normalized.add(alias.lowercase(Locale.ROOT))) { + throw CommandValidationException("Command name and aliases must be unique") + } + } +} + +private fun validateCommandLabel(label: String, kind: String) { + if (!COMMAND_NAME_PATTERN.matches(label)) { + throw CommandValidationException( + "Command $kind '$label' must contain only letters, digits, '.', '_' or '-'", + ) + } +} + +internal fun linearNodes( + arguments: List, + terminalExecutors: Collection, + terminalChildren: List, +): List { + var suffix = terminalChildren + for (index in arguments.indices.reversed()) { + val node = arguments[index] + val executors = if (index == arguments.lastIndex) { + val combined = ObjectArrayList( + node.executors.size + terminalExecutors.size, + ) + + combined.addAll(node.executors) + combined.addAll(terminalExecutors) + + immutableList(combined) + } else { + node.executors + } + + val children = ObjectArrayList( + node.children.size + suffix.size, + ) + + children.addAll(node.children) + children.addAll(suffix) + + suffix = ObjectLists.singleton( + node.copy( + executors = executors, + children = immutableList(children), + ), + ) + } + return suffix +} + +internal fun flatten( + prefix: List>, + inheritedPermissions: Set, + inheritedRequirements: List<(CommandSender) -> Boolean>, + node: ArgumentTreeNode, + output: MutableList, +) { + val path = ObjectArrayList>(prefix.size + 1) + path.addAll(prefix) + path += node.argument + + val permissions = ObjectLinkedOpenHashSet( + inheritedPermissions.size + node.permissions.size, + ) + permissions.addAll(inheritedPermissions) + permissions.addAll(node.permissions) + + val requirements = ObjectArrayList<(CommandSender) -> Boolean>( + inheritedRequirements.size + node.requirements.size, + ) + requirements.addAll(inheritedRequirements) + requirements.addAll(node.requirements) + + val immutablePath = immutableList(path) + val immutablePermissions = immutableSet(permissions) + val immutableRequirements = immutableList(requirements) + + if (node.executors.isNotEmpty()) { + output += commandPath( + immutablePath, + node.executors, + immutablePermissions, + immutableRequirements + ) + } + node.children.forEach { child -> + flatten( + immutablePath, + immutablePermissions, + immutableRequirements, + child, + output + ) + } +} + +internal fun validateAndFreezePaths( + paths: List, + commandName: String +): List { + if (paths.isEmpty()) { + throw CommandValidationException("Command '$commandName' has no executable paths") + } + + paths.forEach { path -> + val names = ObjectOpenHashSet(path.arguments.size) + path.arguments.forEach { argument -> + if (argument.kind !is ArgumentKind.Literal && !names.add(argument.nodeName)) { + throw CommandValidationException( + "Executable path contains duplicate argument node names", + ) + } + } + + val firstOptional = path.arguments.indexOfFirst { argument -> argument.optional } + if ( + firstOptional >= 0 && + path.arguments + .subList(firstOptional, path.arguments.size) + .any { argument -> !argument.optional } + ) { + throw CommandValidationException("Required arguments cannot follow optional arguments") + } + val greedyIndex = path.arguments.indexOfFirst { argument -> argument.greedy } + if (greedyIndex >= 0 && greedyIndex != path.arguments.lastIndex) { + throw CommandValidationException("Greedy arguments must be terminal") + } + + val executorTypes = ObjectOpenHashSet(path.executors.size) + path.executors.forEach { executor -> + if (!executorTypes.add(executor.type)) { + throw CommandValidationException( + "Executable path contains equal-specificity executor conflicts", + ) + } + } + } + + return immutableList(paths) +} + +private fun commandPath( + arguments: Collection>, + executors: Collection, + permissions: Collection, + requirements: Collection<(CommandSender) -> Boolean>, +): CommandPath = CommandPath( + arguments = immutableList(arguments), + executors = immutableList(executors), + permissions = immutableSet(permissions), + requirements = immutableList(requirements), +) + +internal fun immutableList( + values: Collection, +): List = ObjectImmutableList(values) + +internal fun immutableSet( + values: Collection, +): Set = ObjectSets.unmodifiable( + ObjectLinkedOpenHashSet(values), +) + +private val COMMAND_NAME_PATTERN = Regex("""[\p{L}\p{N}_.-]+""") diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandMetadata.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandMetadata.kt new file mode 100644 index 000000000..4ede4fc5e --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandMetadata.kt @@ -0,0 +1,28 @@ +package dev.slne.surf.api.minestom.command.commandapi + +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectLists +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +data class CommandMetadata( + val shortDescription: String? = null, + val fullDescription: List = emptyList(), + val usage: List = emptyList(), + val help: String? = null, +) { + companion object { + @ApiStatus.Internal + fun snapshot( + shortDescription: String?, + fullDescription: Collection, + usage: Collection, + help: String?, + ): CommandMetadata = CommandMetadata( + shortDescription = shortDescription, + fullDescription = ObjectLists.unmodifiable(ObjectArrayList(fullDescription)), + usage = ObjectLists.unmodifiable(ObjectArrayList(usage)), + help = help, + ) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandTree.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandTree.kt new file mode 100644 index 000000000..59e1445b1 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/CommandTree.kt @@ -0,0 +1,112 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi + +import dev.slne.surf.api.minestom.command.commandapi.argument.Argument +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandValidationException +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandExecutable +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutorDefinition +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet +import net.minestom.server.command.CommandSender +import org.jetbrains.annotations.ApiStatus + +class CommandTree(val name: String) : CommandExecutable { + private val aliases = ObjectArrayList() + private val permissions = ObjectLinkedOpenHashSet() + private val requirements = ObjectArrayList<(CommandSender) -> Boolean>() + private val arguments = ObjectArrayList>() + private val executors = ObjectArrayList() + + private var shortDescription: String? = null + private val fullDescription = ObjectArrayList() + private val usage = ObjectArrayList() + private var help: String? = null + + fun withAliases(vararg aliases: String): CommandTree = apply { + this.aliases += aliases + } + + fun withPermission(permission: String): CommandTree = apply { + val normalized = permission.trim() + if (normalized.isBlank()) { + throw CommandValidationException("Command permission must not be blank") + } + permissions += normalized + } + + fun withRequirement(requirement: (CommandSender) -> Boolean): CommandTree = apply { + requirements += requirement + } + + fun withShortDescription(description: String): CommandTree = apply { + shortDescription = description + } + + fun withFullDescription(vararg description: String): CommandTree = apply { + fullDescription.clear() + fullDescription += description + } + + fun withUsage(vararg usage: String): CommandTree = apply { + this.usage.clear() + this.usage += usage + } + + fun withHelp(help: String): CommandTree = apply { + this.help = help + } + + fun then(argument: Argument<*>): CommandTree = apply { + arguments += argument + } + + /** + * Registers an executor for the tree root, which runs when the command is invoked with no + * arguments. Root executors are independent of the branches added through [then]; a tree may + * carry both. + */ + override fun addExecutor(definition: ExecutorDefinition): CommandTree = apply { + executors += definition + } + + @ApiStatus.Internal + fun toDefinition(): CommandDefinition { + validateCommandLabels(name, aliases) + + val output = ObjectArrayList() + val rootPermissions = immutableSet(permissions) + val rootRequirements = immutableList(requirements) + + if (executors.isNotEmpty()) { + output += CommandPath( + arguments = emptyList(), + executors = immutableList(executors), + permissions = rootPermissions, + requirements = rootRequirements, + ) + } + + arguments.forEach { argument -> + flatten( + prefix = emptyList(), + inheritedPermissions = rootPermissions, + inheritedRequirements = rootRequirements, + node = argument.toTreeNode(), + output = output, + ) + } + + return CommandDefinition( + name = name, + aliases = immutableSet(aliases), + metadata = CommandMetadata.snapshot(shortDescription, fullDescription, usage, help), + paths = validateAndFreezePaths(output, name), + ) + } + + fun register(namespace: String? = null): RegisteredCommand = CommandAPI.register(toDefinition(), namespace) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/RegisteredCommand.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/RegisteredCommand.kt new file mode 100644 index 000000000..b25ca78a3 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/RegisteredCommand.kt @@ -0,0 +1,34 @@ +package dev.slne.surf.api.minestom.command.commandapi + +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet +import it.unimi.dsi.fastutil.objects.ObjectSets + +class RegisteredCommand( + val name: String, + aliases: Collection = emptySet(), + val namespace: String? = null, +) { + val aliases: Set = ObjectSets.unmodifiable(ObjectLinkedOpenHashSet(aliases)) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is RegisteredCommand) return false + + if (name != other.name) return false + if (namespace != other.namespace) return false + if (aliases != other.aliases) return false + + return true + } + + override fun hashCode(): Int { + var result = name.hashCode() + result = 31 * result + namespace.hashCode() + result = 31 * result + aliases.hashCode() + return result + } + + override fun toString(): String { + return "RegisteredCommand(name='$name', namespace=$namespace, aliases=$aliases)" + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/Argument.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/Argument.kt new file mode 100644 index 000000000..a9ec9c6af --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/Argument.kt @@ -0,0 +1,332 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandValidationException +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandExecutable +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutorDefinition +import dev.slne.surf.api.minestom.command.commandapi.suggestion.ArgumentSuggestions +import dev.slne.surf.api.minestom.command.commandapi.suggestion.SafeSuggestions +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet +import it.unimi.dsi.fastutil.objects.ObjectLists +import it.unimi.dsi.fastutil.objects.ObjectSets +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet +import net.minestom.server.command.CommandSender +import net.minestom.server.utils.Range +import org.jetbrains.annotations.ApiStatus +import java.time.Duration +import java.util.* +import dev.slne.surf.api.minestom.command.commandapi.argument.Axis as AxisType +import dev.slne.surf.api.minestom.command.commandapi.argument.Rotation as RotationType +import net.kyori.adventure.chat.SignedMessage as AdventureSignedMessage +import net.kyori.adventure.key.Key as AdventureKey +import net.minestom.server.color.TeamColor as MinestomTeamColor +import net.minestom.server.coordinate.Vec as MinestomVec +import net.minestom.server.entity.Entity as MinestomEntity +import net.minestom.server.entity.EntityType as MinestomEntityType +import net.minestom.server.entity.GameMode as MinestomGameMode +import net.minestom.server.entity.Player as MinestomPlayer +import net.minestom.server.instance.Instance as MinestomInstance +import net.minestom.server.item.enchant.Enchantment as MinestomEnchantment +import net.minestom.server.particle.Particle as MinestomParticle +import net.minestom.server.potion.PotionEffect as MinestomPotionEffect +import net.minestom.server.registry.Registry as MinestomRegistry +import net.minestom.server.registry.RegistryKey as MinestomRegistryKey +import net.minestom.server.sound.SoundEvent as MinestomSoundEvent +import net.minestom.server.world.biome.Biome as MinestomBiome +import kotlin.Boolean as KBoolean +import kotlin.Double as KDouble +import kotlin.Enum as KEnum +import kotlin.Float as KFloat +import kotlin.Int as KInt +import kotlin.Long as KLong +import kotlin.collections.List as KList + +sealed interface ArgumentKind { + data object Boolean : ArgumentKind + + data class Integer(val min: KInt, val max: KInt) : ArgumentKind + + data class Long(val min: KLong, val max: KLong) : ArgumentKind + + data class Float(val min: KFloat, val max: KFloat) : ArgumentKind + + data class Double(val min: KDouble, val max: KDouble) : ArgumentKind + + data object Word : ArgumentKind + + data object Text : ArgumentKind + + data object GreedyString : ArgumentKind + + data class Literal(val literal: String) : ArgumentKind + + data class MultiLiteral(val literals: KList) : ArgumentKind + + data class Enum>( + val values: EnumSet, + val formatter: (E) -> String, + ) : ArgumentKind + + data object Uuid : ArgumentKind + + data object IntegerRange : ArgumentKind + + data object FloatRange : ArgumentKind + + data object Command : ArgumentKind + + data object SignedMessage : ArgumentKind + + data object Player : ArgumentKind + + data class Players(val allowEmpty: KBoolean) : ArgumentKind> + + data object Entity : ArgumentKind + + data class Entities(val allowEmpty: KBoolean) : ArgumentKind> + + data object EntityType : ArgumentKind + + data object Position : ArgumentKind + + data object Position2D : ArgumentKind + + data object BlockPosition : ArgumentKind + + data object Rotation : ArgumentKind + + data object Angle : ArgumentKind + + data object Axis : ArgumentKind> + + data object ResourceLocation : ArgumentKind + + data object Time : ArgumentKind + + data object TeamColor : ArgumentKind + + data object Particle : ArgumentKind + + data object GameMode : ArgumentKind + + data object Sound : ArgumentKind + + data object PotionEffect : ArgumentKind + + data object Biome : ArgumentKind> + + data object Enchantment : ArgumentKind> + + data class Resource( + val identifier: String, + val registry: MinestomRegistry, + ) : ArgumentKind> + + data object Instance : ArgumentKind + + data class Custom( + val base: ArgumentDefinition, + val parser: (CustomArgumentInfo) -> T, + ) : ArgumentKind + + data class List( + val element: ArgumentDefinition, + val delimiter: Char, + val allowEmpty: KBoolean, + ) : ArgumentKind> +} + +sealed interface SuggestionMode { + data object BuiltIns : SuggestionMode + + data class Include(val provider: ArgumentSuggestions) : SuggestionMode + + data class Replace(val provider: ArgumentSuggestions) : SuggestionMode + + data class IncludeSafe(val provider: SafeSuggestions) : SuggestionMode + + data class ReplaceSafe(val provider: SafeSuggestions) : SuggestionMode +} + +data class ArgumentDefinition( + val nodeName: String, + val kind: ArgumentKind, + val optional: KBoolean, + val defaultValue: ((CommandSender) -> T)?, + val permissions: Set, + val requirements: KList<(CommandSender) -> KBoolean>, + val suggestions: SuggestionMode, + val greedy: KBoolean, + val rawType: ArgumentType, + val stringify: (T) -> String, + val listDelimiter: Char? = null, +) + +/** + * A raw type for an argument whose parser has not been implemented. + * + * Rejecting the input keeps an unfinished argument from silently reading a value that means + * something else. + */ +@ApiStatus.Internal +class UnsupportedArgumentType(private val nodeName: String) : ArgumentType { + override fun parse(reader: StringReader): T = throw SimpleCommandExceptionType( + LiteralMessage("Argument '$nodeName' has no parser"), + ).createWithContext(reader) +} + +abstract class Argument(val nodeName: String) : CommandExecutable> { + protected abstract val kind: ArgumentKind + + /** + * The Brigadier type that reads this argument's value from the command line. + * + * Kinds Brigadier already provides return its type directly, so parsing, bounds and error + * messages match vanilla exactly. Every other kind supplies its own parser. + */ + protected abstract val rawType: ArgumentType + + /** + * Whether this argument consumes the rest of the command line. + * + * A greedy argument must be the last one on its path, and cannot be the element type of a list; + * registration throws [CommandValidationException] otherwise. + */ + protected open val greedy: KBoolean = false + + protected open val listDelimiter: Char? = null + + private var optional = false + private var defaultValue: ((CommandSender) -> T)? = null + private val permissions = ObjectLinkedOpenHashSet() + private val requirements = ObjectArrayList<(CommandSender) -> KBoolean>() + private var suggestions: SuggestionMode = SuggestionMode.BuiltIns + private val executors = ObjectArrayList() + private val children = ObjectArrayList>() + + init { + require(nodeName.isNotBlank()) { "Argument node name must not be blank" } + } + + protected abstract fun stringify(value: T): String + + /** + * Controls whether this argument is optional without assigning a default value. + * + * An optional argument cannot precede a required argument in the same registered path; + * registration throws [CommandValidationException] for that ordering. + * + * For a [BooleanArgument], use the named form `setOptional(optional = true)` to + * distinguish this operation from a constant Boolean default. + */ + fun setOptional(optional: KBoolean): Argument = apply { + this.optional = optional + if (!optional) { + defaultValue = null + } + } + + /** + * Makes this argument optional and assigns a constant default value. + * + * For a [BooleanArgument], use the named form `setOptional(default = true)` to + * distinguish the value from the optionality flag overload. + */ + fun setOptional(default: T): Argument = apply { + optional = true + defaultValue = { default } + } + + fun setOptional(default: (CommandSender) -> T): Argument = apply { + optional = true + defaultValue = default + } + + fun withPermission(permission: String): Argument = apply { + val normalized = permission.trim() + require(normalized.isNotBlank()) { "Argument permission must not be blank" } + permissions += normalized + } + + fun withRequirement(requirement: (CommandSender) -> KBoolean): Argument = apply { + requirements += requirement + } + + fun replaceSuggestions(suggestions: ArgumentSuggestions): Argument = apply { + this.suggestions = SuggestionMode.Replace(suggestions) + } + + fun includeSuggestions(suggestions: ArgumentSuggestions): Argument = apply { + this.suggestions = SuggestionMode.Include(suggestions) + } + + fun replaceSafeSuggestions(suggestions: SafeSuggestions): Argument = apply { + this.suggestions = SuggestionMode.ReplaceSafe(suggestions) + } + + fun includeSafeSuggestions(suggestions: SafeSuggestions): Argument = apply { + this.suggestions = SuggestionMode.IncludeSafe(suggestions) + } + + override fun addExecutor(definition: ExecutorDefinition): Argument = apply { + executors += definition + } + + fun then(child: Argument<*>): Argument = apply { + require(child !== this) { "An argument cannot be its own child" } + children += child + } + + @ApiStatus.Internal + internal fun toTreeNode(): ArgumentTreeNode = toTreeNode(ReferenceOpenHashSet()) + + private fun toTreeNode(stack: MutableSet>): ArgumentTreeNode { + if (!stack.add(this)) { + throw CommandValidationException("Argument '$nodeName' contains a child cycle") + } + try { + return ArgumentTreeNode( + argument = toDefinition(), + executors = ObjectLists.unmodifiable(ObjectArrayList(executors)), + children = ObjectLists.unmodifiable(children.mapTo(ObjectArrayList(children.size)) { child -> + child.toTreeNode(stack) + }), + ) + } finally { + stack.remove(this) + } + } + + @ApiStatus.Internal + fun toDefinition(): ArgumentDefinition = ArgumentDefinition( + nodeName = nodeName, + kind = kind, + optional = optional, + defaultValue = defaultValue, + permissions = ObjectSets.unmodifiable(ObjectLinkedOpenHashSet(permissions)), + requirements = ObjectLists.unmodifiable(ObjectArrayList(requirements)), + suggestions = suggestions, + greedy = greedy, + rawType = rawType, + stringify = ::stringify, + listDelimiter = listDelimiter, + ) +} + +@ApiStatus.Internal +internal data class ArgumentTreeNode( + val argument: ArgumentDefinition<*>, + val executors: KList, + val children: KList, + val permissions: Set = emptySet(), + val requirements: KList<(CommandSender) -> KBoolean> = emptyList(), +) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/CompositeArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/CompositeArguments.kt new file mode 100644 index 000000000..0c6ddd01f --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/CompositeArguments.kt @@ -0,0 +1,250 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import java.util.concurrent.CompletableFuture +import dev.slne.surf.api.minestom.command.commandapi.CommandAPI +import dev.slne.surf.api.minestom.command.commandapi.exception.ComponentMessage +import dev.slne.surf.api.minestom.command.commandapi.exception.WrapperCommandSyntaxException +import net.minestom.server.command.CommandSender +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandSyntaxException as ApiCommandSyntaxException + +data class CustomArgumentInfo( + val sender: CommandSender, + val currentInput: String, + val baseValue: B, +) + +open class CustomArgument internal constructor( + private val base: Argument, + private val formatter: (T) -> String, + private val parser: (CustomArgumentInfo) -> T, +) : Argument(base.nodeName) { + constructor( + base: Argument, + parser: (CustomArgumentInfo) -> T, + ) : this(base, { value -> value.toString() }, parser) + + init { + val baseDefinition = base.toDefinition() + val defaultValue = baseDefinition.defaultValue + when { + defaultValue != null -> setOptional { sender -> + parser(CustomArgumentInfo(sender, "", defaultValue(sender))) + } + + baseDefinition.optional -> setOptional(optional = true) + } + baseDefinition.permissions.forEach(::withPermission) + baseDefinition.requirements.forEach(::withRequirement) + } + + override val kind: ArgumentKind + get() = ArgumentKind.Custom(base.toDefinition(), parser) + + override val rawType: ArgumentType = CustomArgumentType(base.toDefinition().rawType, parser) + + override val greedy: Boolean + get() = base.toDefinition().greedy + + override val listDelimiter: Char? + get() = base.toDefinition().listDelimiter + + override fun stringify(value: T): String = formatter(value) +} + +private val CUSTOM_ARGUMENT_NEEDS_SENDER = SimpleCommandExceptionType( + LiteralMessage("A custom argument requires a command source to resolve"), +) + +/** + * Parses a value with [baseType], then hands it to [parser] wrapped in a [CustomArgumentInfo] + * carrying the sender, the exact text [baseType] consumed and the parsed base value. [parser] + * never sees the underlying [StringReader]; it composes on top of the already-parsed base value. + * + * A command source is required to build that info even when [parser] does not read it, so the + * source-less overload is rejected rather than fabricating one. + * + * A [CommandSyntaxException] thrown by [parser] passes through unchanged. This project's own + * [ApiCommandSyntaxException] - directly, or unwrapped from a [WrapperCommandSyntaxException] - is + * translated into one instead, with the reader's cursor reset to where this value started. + */ +private class CustomArgumentType( + private val baseType: ArgumentType, + private val parser: (CustomArgumentInfo) -> T, +) : ArgumentType { + override fun parse(reader: StringReader): T = throw CUSTOM_ARGUMENT_NEEDS_SENDER.createWithContext(reader) + + override fun parse(reader: StringReader, source: S): T { + val start = reader.cursor + val sender = source as? CommandSender ?: throw CUSTOM_ARGUMENT_NEEDS_SENDER.createWithContext(reader) + + val baseValue = baseType.parse(reader, source) + val consumed = reader.string.substring(start, reader.cursor) + val info = CustomArgumentInfo(sender, consumed, baseValue) + + return try { + parser(info) + } catch (failure: CommandSyntaxException) { + throw failure + } catch (failure: WrapperCommandSyntaxException) { + reader.cursor = start + throw failure.exception.toBrigadier(reader) + } catch (failure: ApiCommandSyntaxException) { + reader.cursor = start + throw failure.toBrigadier(reader) + } + } + + /** A custom argument reads exactly what its base reads, so it completes the same values. */ + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture = baseType.listSuggestions(context, builder) +} + +/** + * Rewrites this project's syntax failure as the Brigadier one the dispatcher expects, keeping the + * styled component so the sender sees the message the argument wrote rather than its plain form. + */ +private fun ApiCommandSyntaxException.toBrigadier(reader: StringReader): CommandSyntaxException { + val message = component + ?.let(::ComponentMessage) + ?: LiteralMessage(this.message ?: "Invalid argument") + + return SimpleCommandExceptionType(message).createWithContext(reader) +} + +class ListArgument( + nodeName: String, + private val element: Argument, + val delimiter: Char = ',', + val allowEmpty: Boolean = false, +) : Argument>(nodeName) { + init { + val elementDefinition = element.toDefinition() + require(!delimiter.isWhitespace() && delimiter != '\u0000') { + "List delimiter must be a visible non-whitespace character" + } + require(!elementDefinition.greedy) { "List elements cannot consume remaining input" } + elementDefinition.permissions.forEach(::withPermission) + elementDefinition.requirements.forEach(::withRequirement) + } + + override val kind: ArgumentKind> + get() = ArgumentKind.List(element.toDefinition(), delimiter, allowEmpty) + + override val rawType: ArgumentType> = + ListArgumentType(element.toDefinition().rawType, delimiter, allowEmpty) + + override val greedy = true + + override val listDelimiter: Char = delimiter + + override fun stringify(value: List): String { + val elementDefinition = element.toDefinition() + return value.joinToString(delimiter.toString(), transform = elementDefinition.stringify) + } +} + +private val LIST_ARGUMENT_EMPTY = SimpleCommandExceptionType(LiteralMessage("List must not be empty")) + +/** + * Reads elements with [elementType], separated by [delimiter] (whitespace around the delimiter, + * and leading or trailing whitespace around the whole list, is skipped). Rejects an empty list + * unless [allowEmpty] permits it. + * + * Also rejects an individual element that consumed no input at all - a leading, trailing, or + * doubled-up delimiter - unless [allowEmpty] permits it. This is checked here rather than left to + * [elementType], since some element types (a bare word, for instance) would otherwise accept an + * empty token silently instead of rejecting it. + */ +private class ListArgumentType( + private val elementType: ArgumentType, + private val delimiter: Char, + private val allowEmpty: Boolean, +) : ArgumentType> { + override fun parse(reader: StringReader): List = parseList(reader) { r -> elementType.parse(r) } + + override fun parse(reader: StringReader, source: S): List = + parseList(reader) { r -> elementType.parse(r, source) } + + /** + * Completes the element being typed, not the list: the offered entries replace the text after + * the last delimiter, so accepting one leaves the elements before it alone. + */ + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture { + val typed = builder.remaining + val elementStart = typed.lastIndexOf(delimiter) + 1 + val offset = builder.start + elementStart + typed.drop(elementStart).takeWhile(Char::isWhitespace).length + + return elementType.listSuggestions(context, builder.createOffset(offset)) + } + + private inline fun parseList(reader: StringReader, parseElement: (StringReader) -> T): List { + val start = reader.cursor + skipWhitespace(reader) + if (!reader.canRead()) { + if (allowEmpty) return emptyList() + reader.cursor = start + throw LIST_ARGUMENT_EMPTY.createWithContext(reader) + } + + val values = ArrayList() + while (true) { + val elementStart = reader.cursor + val value = parseElement(reader) + if (!allowEmpty && reader.cursor == elementStart) { + reader.cursor = elementStart + throw LIST_ARGUMENT_EMPTY.createWithContext(reader) + } + values += value + + skipWhitespace(reader) + if (reader.canRead() && reader.peek() == delimiter) { + reader.skip() + skipWhitespace(reader) + } else { + break + } + } + return values + } + + private fun skipWhitespace(reader: StringReader) { + while (reader.canRead() && reader.peek() == ' ') { + reader.skip() + } + } +} + +fun Argument.map(mapper: (T) -> R): Argument = + CustomArgument(this, parser = { info -> mapper(info.baseValue) }) + +fun Argument.filter(predicate: (T) -> Boolean): Argument { + val definition = toDefinition() + return CustomArgument( + base = this, + parser = { info -> + if (!predicate(info.baseValue)) { + CommandAPI.failWithString("Invalid value for $nodeName") + } + info.baseValue + }, + formatter = definition.stringify, + ) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/EntityArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/EntityArguments.kt new file mode 100644 index 000000000..08baaa94b --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/EntityArguments.kt @@ -0,0 +1,151 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.EntitySelectorParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.RegistryParser +import net.minestom.server.command.CommandSender +import net.minestom.server.entity.Entity +import net.minestom.server.entity.EntityType +import net.minestom.server.entity.Player +import java.util.concurrent.CompletableFuture + +class PlayerArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Player + override val rawType: ArgumentType = + SingleTargetType(maxResults = 1, playersOnly = true) { entities -> entities.filterIsInstance().singleOrNull() } + + override fun stringify(value: Player): String = value.username +} + +class PlayersArgument( + nodeName: String, + val allowEmpty: Boolean = false, +) : Argument>(nodeName) { + override val kind = ArgumentKind.Players(allowEmpty) + override val rawType: ArgumentType> = MultiTargetType( + maxResults = Int.MAX_VALUE, + playersOnly = true, + allowEmpty = allowEmpty, + ) { entities -> entities.filterIsInstance() } + + override fun stringify(value: List): String = + value.joinToString(",", transform = Player::getUsername) +} + +class EntityArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Entity + override val rawType: ArgumentType = + SingleTargetType(maxResults = 1, playersOnly = false) { entities -> entities.singleOrNull() } + + override fun stringify(value: Entity): String = value.uuid.toString() +} + +class EntitiesArgument( + nodeName: String, + val allowEmpty: Boolean = false, +) : Argument>(nodeName) { + override val kind = ArgumentKind.Entities(allowEmpty) + override val rawType: ArgumentType> = MultiTargetType( + maxResults = Int.MAX_VALUE, + playersOnly = false, + allowEmpty = allowEmpty, + ) { entities -> entities } + + override fun stringify(value: List): String = + value.joinToString(",") { entity -> entity.uuid.toString() } +} + +class EntityTypeArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.EntityType + override val rawType: ArgumentType = + RegistryParser("entity type") { key -> EntityType.fromKey(key) } + + override fun stringify(value: EntityType): String = value.key().asString() +} + +private val SELECTOR_NEEDS_SENDER = SimpleCommandExceptionType( + LiteralMessage("An entity selector requires a command source to resolve"), +) +private val NO_MATCH = SimpleCommandExceptionType(LiteralMessage("No entity matched the selector")) +private val NO_MATCHES = SimpleCommandExceptionType(LiteralMessage("No entities matched the selector")) + +/** + * Resolves an entity selector to exactly one entity of type [T], rejecting the input (rather than + * resolving it) when the selector could structurally match more than one, or when the selector's + * source is unavailable to resolve against. + */ +private class SingleTargetType( + maxResults: Int, + playersOnly: Boolean, + private val select: (List) -> T?, +) : ArgumentType { + private val selector = EntitySelectorParser(maxResults, playersOnly) + + override fun parse(reader: StringReader): T = throw SELECTOR_NEEDS_SENDER.createWithContext(reader) + + override fun parse(reader: StringReader, source: S): T { + val start = reader.cursor + val parsed = selector.parse(reader) + val sender = source as? CommandSender ?: run { + reader.cursor = start + throw SELECTOR_NEEDS_SENDER.createWithContext(reader) + } + + return select(parsed.find(sender)) ?: run { + reader.cursor = start + throw NO_MATCH.createWithContext(reader) + } + } + + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture = selector.listSuggestions(context, builder) +} + +/** + * Resolves an entity selector to every matching entity of type [T], rejecting an empty result + * unless [allowEmpty] permits it. + */ +private class MultiTargetType( + maxResults: Int, + playersOnly: Boolean, + private val allowEmpty: Boolean, + private val select: (List) -> List, +) : ArgumentType> { + private val selector = EntitySelectorParser(maxResults, playersOnly) + + override fun parse(reader: StringReader): List = throw SELECTOR_NEEDS_SENDER.createWithContext(reader) + + override fun parse(reader: StringReader, source: S): List { + val start = reader.cursor + val parsed = selector.parse(reader) + val sender = source as? CommandSender ?: run { + reader.cursor = start + throw SELECTOR_NEEDS_SENDER.createWithContext(reader) + } + + val results = select(parsed.find(sender)) + if (results.isEmpty() && !allowEmpty) { + reader.cursor = start + throw NO_MATCHES.createWithContext(reader) + } + return results + } + + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture = selector.listSuggestions(context, builder) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/MinecraftArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/MinecraftArguments.kt new file mode 100644 index 000000000..b13c400e0 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/MinecraftArguments.kt @@ -0,0 +1,76 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.arguments.ArgumentType +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.FixedSetParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.ParticleParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.ResourceLocationParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.TimeParser +import net.kyori.adventure.key.Key +import net.minestom.server.MinecraftServer +import net.minestom.server.color.TeamColor +import net.minestom.server.entity.GameMode +import net.minestom.server.particle.Particle +import java.time.Duration + +class ResourceLocationArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.ResourceLocation + override val rawType: ArgumentType = ResourceLocationParser + + override fun stringify(value: Key): String = value.asString() +} + +/** + * A duration parsed from vanilla's suffixed time syntax (`50d`, `25s`, `75t`, or a bare tick + * count). + */ +class TimeArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Time + override val rawType: ArgumentType = TimeParser + + override fun stringify(value: Duration): String = "${value.toMillis() / MinecraftServer.TICK_MS}t" +} + +/** + * A team color parsed from its vanilla name (`black`, `dark_blue`, ..., `white`); matching is + * case-sensitive, and suggestions are offered case-insensitively. + */ +class TeamColorArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.TeamColor + override val rawType: ArgumentType = FixedSetParser( + TeamColor.entries.associateBy(TeamColor::toString), + ) + + override fun stringify(value: TeamColor): String = value.toString() +} + +/** + * A particle resolved by its namespaced key. + * + * Only option-free particles (`flame`, `smoke`, and similar) are accepted; a particle whose kind + * carries options (`dust`, `block`, `vibration`, and similar) has no syntax to supply those options + * here and is rejected as unsupported. + */ +class ParticleArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Particle + override val rawType: ArgumentType = ParticleParser + + override fun stringify(value: Particle): String = value.name() +} + +/** + * A player game mode parsed from its vanilla name (`survival`, `creative`, `adventure`, or + * `spectator`); matching is case-sensitive, and suggestions are offered case-insensitively. + */ +class GameModeArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.GameMode + override val rawType: ArgumentType = FixedSetParser( + GameMode.entries.associateBy { mode -> mode.name.lowercase() }, + ) + + override fun stringify(value: GameMode): String = value.name.lowercase() +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PositionArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PositionArguments.kt new file mode 100644 index 000000000..12f67c5fa --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PositionArguments.kt @@ -0,0 +1,73 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.arguments.ArgumentType +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.AngleParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.AxisParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.PositionArgumentType +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.RotationArgumentType +import net.minestom.server.coordinate.Vec +import kotlin.math.floor + +/** + * A world axis, as used by swizzle arguments such as `/data get ... xyz`. + */ +enum class Axis { + X, + Y, + Z, +} + +/** + * A yaw/pitch view, as produced by [RotationArgument]. + */ +data class Rotation(val yaw: Float, val pitch: Float) + +class PositionArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Position + override val rawType: ArgumentType = + PositionArgumentType(blockAligned = false, twoDimensional = false) + override fun stringify(value: Vec): String = "${value.x()} ${value.y()} ${value.z()}" +} + +class Position2DArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Position2D + override val rawType: ArgumentType = + PositionArgumentType(blockAligned = false, twoDimensional = true) + override fun stringify(value: Vec): String = "${value.x()} ${value.z()}" +} + +class BlockPositionArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.BlockPosition + override val rawType: ArgumentType = + PositionArgumentType(blockAligned = true, twoDimensional = false) + override fun stringify(value: Vec): String = + "${floor(value.x()).toInt()} ${floor(value.y()).toInt()} ${floor(value.z()).toInt()}" +} + +class RotationArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Rotation + override val rawType: ArgumentType = RotationArgumentType + override fun stringify(value: Rotation): String = "${value.yaw} ${value.pitch}" +} + +/** + * An angle in degrees, absolute or relative to the sender's yaw with `~`, wrapped into + * `[-180, 180)`. + */ +class AngleArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Angle + override val rawType: ArgumentType = AngleParser + override fun stringify(value: Float): String = value.toString() +} + +class AxisArgument(nodeName: String) : Argument>(nodeName) { + override val kind = ArgumentKind.Axis + override val rawType: ArgumentType> = AxisParser + override fun stringify(value: Set): String = + value.joinToString("") { axis -> axis.name.lowercase() } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PrimitiveArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PrimitiveArguments.kt new file mode 100644 index 000000000..f03b5a73a --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/PrimitiveArguments.kt @@ -0,0 +1,152 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.arguments.BoolArgumentType +import com.mojang.brigadier.arguments.DoubleArgumentType +import com.mojang.brigadier.arguments.FloatArgumentType +import com.mojang.brigadier.arguments.IntegerArgumentType +import com.mojang.brigadier.arguments.LongArgumentType +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.FixedSetParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.FloatRangeParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.IntegerRangeParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.UuidParser +import net.minestom.server.utils.Range +import java.util.* + +class BooleanArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Boolean + override val rawType: ArgumentType = BoolArgumentType.bool() + override fun stringify(value: Boolean): String = value.toString() +} + +class IntegerArgument( + nodeName: String, + min: Int = Int.MIN_VALUE, + max: Int = Int.MAX_VALUE, +) : Argument(nodeName) { + override val kind = ArgumentKind.Integer(min, max) + override val rawType: ArgumentType = IntegerArgumentType.integer(min, max) + + init { + require(min <= max) { "Minimum integer value must not exceed maximum value" } + } + + override fun stringify(value: Int): String = value.toString() +} + +class LongArgument( + nodeName: String, + min: Long = Long.MIN_VALUE, + max: Long = Long.MAX_VALUE, +) : Argument(nodeName) { + override val kind = ArgumentKind.Long(min, max) + override val rawType: ArgumentType = LongArgumentType.longArg(min, max) + + init { + require(min <= max) { "Minimum long value must not exceed maximum value" } + } + + override fun stringify(value: Long): String = value.toString() +} + +class FloatArgument( + nodeName: String, + min: Float = -Float.MAX_VALUE, + max: Float = Float.MAX_VALUE, +) : Argument(nodeName) { + override val kind = ArgumentKind.Float(min, max) + override val rawType: ArgumentType = FloatArgumentType.floatArg(min, max) + + init { + require(!min.isNaN() && !max.isNaN() && min <= max) { + "Minimum float value must not exceed maximum value and bounds must not be NaN" + } + } + + override fun stringify(value: Float): String = value.toString() +} + +class DoubleArgument( + nodeName: String, + min: Double = -Double.MAX_VALUE, + max: Double = Double.MAX_VALUE, +) : Argument(nodeName) { + override val kind = ArgumentKind.Double(min, max) + override val rawType: ArgumentType = DoubleArgumentType.doubleArg(min, max) + + init { + require(!min.isNaN() && !max.isNaN() && min <= max) { + "Minimum double value must not exceed maximum value and bounds must not be NaN" + } + } + + override fun stringify(value: Double): String = value.toString() +} + +class EnumArgument>( + nodeName: String, + values: Collection, + private val formatter: (E) -> String = { value -> value.name.lowercase() }, +) : Argument(nodeName) { + private val values = EnumSet.copyOf(values) + + override val kind = ArgumentKind.Enum(this.values, formatter) + override val rawType: ArgumentType = FixedSetParser(this.values.associateBy(formatter)) + + init { + require(this.values.isNotEmpty()) { "Enum argument must contain at least one value" } + + val formattedValues = this.values.map(formatter) + + require(formattedValues.all(String::isNotBlank)) { "Formatted enum values must not be blank" } + require(formattedValues.distinct().size == formattedValues.size) { "Formatted enum values must be unique" } + } + + override fun stringify(value: E): String = formatter(value) +} + +/** + * A UUID parsed in its canonical dashed hex form. + */ +class UUIDArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Uuid + override val rawType: ArgumentType = UuidParser + override fun stringify(value: UUID): String = value.toString() +} + +/** + * An integer range parsed from vanilla's `min..max` syntax. + * + * Either bound may be omitted; an omitted bound resolves to `Int.MIN_VALUE` or `Int.MAX_VALUE` + * respectively. A bare value is shorthand for a range containing only that value. + */ +class IntegerRangeArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.IntegerRange + override val rawType: ArgumentType = IntegerRangeParser + override fun stringify(value: Range.Int): String = stringifyRange(value.min(), value.max()) +} + +/** + * A float range parsed from vanilla's `min..max` syntax. + * + * Either bound may be omitted; an omitted bound resolves to `-Float.MAX_VALUE` or + * `Float.MAX_VALUE` respectively. A bare value is shorthand for a range containing only that + * value. + */ +class FloatRangeArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.FloatRange + override val rawType: ArgumentType = FloatRangeParser + override fun stringify(value: Range.Float): String = stringifyRange(value.min(), value.max()) +} + +private fun stringifyRange(min: Number?, max: Number?): String = when { + min != null && min == max -> min.toString() + else -> "${min.orEmpty()}..${max.orEmpty()}" +} + +private fun Number?.orEmpty(): String = this?.toString().orEmpty() diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/RegistryArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/RegistryArguments.kt new file mode 100644 index 000000000..653432c98 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/RegistryArguments.kt @@ -0,0 +1,88 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.arguments.ArgumentType +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.InstanceParser +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.RegistryParser +import net.minestom.server.MinecraftServer +import net.minestom.server.instance.Instance +import net.minestom.server.item.enchant.Enchantment +import net.minestom.server.potion.PotionEffect +import net.minestom.server.registry.Registry +import net.minestom.server.registry.RegistryKey +import net.minestom.server.sound.SoundEvent +import net.minestom.server.world.biome.Biome + +class SoundArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Sound + override val rawType: ArgumentType = RegistryParser( + registryName = "sound event", + keys = { SoundEvent.values().map(SoundEvent::name) }, + ) { key -> SoundEvent.fromKey(key) } + + override fun stringify(value: SoundEvent): String = value.name() +} + +class PotionEffectArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.PotionEffect + override val rawType: ArgumentType = RegistryParser( + registryName = "potion effect", + keys = { PotionEffect.values().map { effect -> effect.key().asString() } }, + ) { key -> PotionEffect.fromKey(key) } + + override fun stringify(value: PotionEffect): String = value.key().asString() +} + +class BiomeArgument(nodeName: String) : Argument>(nodeName) { + override val kind = ArgumentKind.Biome + override val rawType: ArgumentType> = RegistryParser( + registryName = "biome", + keys = { MinecraftServer.getBiomeRegistry().keys().map(RegistryKey::name) }, + ) { key -> MinecraftServer.getBiomeRegistry().getKey(key) } + + override fun stringify(value: RegistryKey): String = value.name() +} + +class EnchantmentArgument(nodeName: String) : Argument>(nodeName) { + override val kind = ArgumentKind.Enchantment + override val rawType: ArgumentType> = RegistryParser( + registryName = "enchantment", + keys = { + MinecraftServer.getEnchantmentRegistry().keys().map(RegistryKey::name) + }, + ) { key -> MinecraftServer.getEnchantmentRegistry().getKey(key) } + + override fun stringify(value: RegistryKey): String = value.name() +} + +/** + * A resource resolved from an arbitrary [Registry] by namespaced key, advertised to the client + * under [identifier]. + */ +class ResourceArgument( + nodeName: String, + identifier: String, + registry: Registry, +) : Argument>(nodeName) { + override val kind = ArgumentKind.Resource(identifier, registry) + override val rawType: ArgumentType> = RegistryParser( + registryName = identifier, + keys = { registry.keys().map(RegistryKey::name) }, + ) { key -> registry.getKey(key) } + + override fun stringify(value: RegistryKey): String = value.name() +} + +/** + * A live [Instance], resolved by its UUID or by its dimension name when that name is unique + * among currently registered instances. + */ +class InstanceArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Instance + override val rawType: ArgumentType = InstanceParser + override fun stringify(value: Instance): String = value.uuid.toString() +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/SignedMessageArgument.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/SignedMessageArgument.kt new file mode 100644 index 000000000..e6646ed97 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/SignedMessageArgument.kt @@ -0,0 +1,15 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.arguments.ArgumentType +import net.kyori.adventure.chat.SignedMessage + +/** + * Reads the rest of the command line as a chat message the sender signed. + */ +class SignedMessageArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.SignedMessage + override val rawType: ArgumentType = UnsupportedArgumentType(nodeName) + override val greedy = true + + override fun stringify(value: SignedMessage): String = value.message() +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/StringArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/StringArguments.kt new file mode 100644 index 000000000..4f6283f7a --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/StringArguments.kt @@ -0,0 +1,108 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.argument + +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.arguments.StringArgumentType +import dev.slne.surf.api.minestom.command.commandapi.argument.parser.FixedSetParser +import it.unimi.dsi.fastutil.objects.ObjectList + +class StringArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Word + override val rawType: ArgumentType = StringArgumentType.word() + override fun stringify(value: String): String = value +} + +class TextArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Text + override val rawType: ArgumentType = StringArgumentType.string() + override fun stringify(value: String): String = value.asQuotablePhrase() +} + +class GreedyStringArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.GreedyString + override val rawType: ArgumentType = StringArgumentType.greedyString() + override val greedy = true + override fun stringify(value: String): String = value +} + +class LiteralArgument( + nodeName: String, + val literal: String = nodeName, +) : Argument(nodeName) { + override val kind = ArgumentKind.Literal(literal) + override val rawType: ArgumentType = UnsupportedArgumentType(nodeName) + + init { + require(literal.isNotBlank()) { "Literal value must not be blank" } + require(literal.none(Char::isWhitespace)) { "Literal value must be a single token" } + } + + override fun stringify(value: String): String = value +} + +class MultiLiteralArgument(nodeName: String, vararg literals: String) : Argument(nodeName) { + private val literals: List = ObjectList.of(*literals) + override val kind = ArgumentKind.MultiLiteral(this.literals) + override val rawType: ArgumentType = FixedSetParser(this.literals.associateWith { it }) + + init { + require(this.literals.isNotEmpty()) { "Multi-literal argument must contain at least one literal" } + require(this.literals.all(String::isNotBlank)) { "Literal values must not be blank" } + require(this.literals.none { literal -> literal.any(Char::isWhitespace) }) { + "Multi-literal values must be single tokens" + } + require(this.literals.distinct().size == this.literals.size) { "Literal values must be unique" } + } + + override fun stringify(value: String): String = value +} + +/** + * Reads the remainder of the input as a single string, the same way [GreedyStringArgument] does. + */ +class CommandArgument(nodeName: String) : Argument(nodeName) { + override val kind = ArgumentKind.Command + override val rawType: ArgumentType = StringArgumentType.greedyString() + override val greedy = true + + override fun stringify(value: String): String = value +} + +private fun String.asQuotablePhrase(): String { + if (none { character -> + character.isWhitespace() || + Character.isISOControl(character) || + character == '\'' || + character == '"' + } + ) { + return this + } + + return buildString(length + 2) { + append('"') + this@asQuotablePhrase.forEach { character -> + append( + when (character) { + '\\' -> "\\\\" + '"' -> "\\\"" + '\b' -> "\\b" + '\t' -> "\\t" + '\n' -> "\\n" + '\u000C' -> "\\f" + '\r' -> "\\r" + else -> if (Character.isISOControl(character)) { + "\\u${character.code.toString(16).padStart(4, '0')}" + } else { + character + } + }, + ) + } + append('"') + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/CoordinateParsers.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/CoordinateParsers.kt new file mode 100644 index 000000000..16e642714 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/CoordinateParsers.kt @@ -0,0 +1,270 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import dev.slne.surf.api.minestom.command.commandapi.argument.Axis +import dev.slne.surf.api.minestom.command.commandapi.argument.Rotation +import net.minestom.server.command.CommandSender +import net.minestom.server.coordinate.Pos +import net.minestom.server.coordinate.Vec +import net.minestom.server.entity.Entity +import net.minestom.server.utils.location.RelativeVec + +private val ERROR_MIXED_TYPE = SimpleCommandExceptionType( + LiteralMessage("Cannot mix world and local coordinates in a single position"), +) +private val ERROR_EXPECTED_VALUE = SimpleCommandExceptionType(LiteralMessage("Expected a coordinate value")) +private val ERROR_INCOMPLETE = SimpleCommandExceptionType(LiteralMessage("Incomplete coordinate")) +private val ERROR_INVALID_SWIZZLE = SimpleCommandExceptionType(LiteralMessage("Invalid swizzle")) +private val ERROR_REQUIRES_SENDER = SimpleCommandExceptionType( + LiteralMessage("A relative (~) or local (^) coordinate requires a command source to resolve"), +) + +private data class Component(val relative: Boolean, val value: Double) + +/** + * Reads one world-coordinate component: an optional `~` marking it relative to the sender, + * followed by an optional numeric offset that defaults to `0` when omitted. A leading `^` is + * rejected here, since a position's components must agree on whether they are local. + * + * Absolute (non-`~`) values are read as whole numbers when [blockAligned] is set; a `~` offset + * always accepts a decimal regardless of [blockAligned]. + */ +private fun readWorldComponent(reader: StringReader, blockAligned: Boolean): Component { + if (reader.canRead() && reader.peek() == '^') throw ERROR_MIXED_TYPE.createWithContext(reader) + if (!reader.canRead()) throw ERROR_EXPECTED_VALUE.createWithContext(reader) + + val relative = reader.peek() == '~' + if (relative) reader.skip() + + val hasNumber = reader.canRead() && reader.peek() != ' ' + val value = when { + !hasNumber -> 0.0 + blockAligned && !relative -> reader.readInt().toDouble() + else -> reader.readDouble() + } + return Component(relative, value) +} + +/** Reads one `^`-prefixed local coordinate component; any other leading character is a mixed type. */ +private fun readLocalComponent(reader: StringReader): Double { + if (!reader.canRead()) throw ERROR_EXPECTED_VALUE.createWithContext(reader) + if (reader.peek() != '^') throw ERROR_MIXED_TYPE.createWithContext(reader) + reader.skip() + return if (reader.canRead() && reader.peek() != ' ') reader.readDouble() else 0.0 +} + +private fun expectSeparator(reader: StringReader) { + if (reader.canRead() && reader.peek() == ' ') { + reader.skip() + } else { + throw ERROR_INCOMPLETE.createWithContext(reader) + } +} + +private fun coordinateTypeOf(vararg relative: Boolean): RelativeVec.CoordinateType = + if (relative.any { it }) RelativeVec.CoordinateType.RELATIVE else RelativeVec.CoordinateType.ABSOLUTE + +/** + * Rebuilds this exception at [start], since [SimpleCommandExceptionType.createWithContext] bakes + * the cursor in at construction time. + */ +private fun CommandSyntaxException.resetTo(reader: StringReader, start: Int): CommandSyntaxException { + reader.cursor = start + return CommandSyntaxException(type, rawMessage, reader.string, start) +} + +/** + * Returns [relative] unchanged when [sender] is present or when none of its components are + * relative or local; otherwise rejects it, since resolving a `~` or `^` component without a sender + * would silently substitute the origin for the sender's actual position or view. + */ +private fun requireResolvable( + relative: RelativeVec, + sender: CommandSender?, + reader: StringReader, + start: Int, +): RelativeVec { + if (sender == null && (relative.relativeX() || relative.relativeY() || relative.relativeZ())) { + reader.cursor = start + throw ERROR_REQUIRES_SENDER.createWithContext(reader) + } + return relative +} + +/** + * Reads a vanilla-style position: three components (or two, when [twoDimensional], leaving the + * middle component fixed at a non-relative `0`), each absolute, `~`-relative to the sender, or, + * for the three-component form only, `^`-relative to the sender's facing direction. All components + * must agree on whether they are local; mixing `^` with a bare or `~`-prefixed component is + * rejected, and the reader's cursor is reset to the position's start before the failure is thrown. + * + * [blockAligned] restricts absolute (non-`~`, non-`^`) components to whole numbers, matching a + * block position's grammar. + * + * The result is a Minestom [RelativeVec] carrying the parsed values and their relativity, ready to + * be resolved against a sender with [RelativeVec.fromSender] or [RelativeVec.from]. + */ +internal class PositionParser( + private val blockAligned: Boolean, + private val twoDimensional: Boolean, +) : ArgumentType { + override fun parse(reader: StringReader): RelativeVec { + val start = reader.cursor + try { + return if (!twoDimensional && reader.canRead() && reader.peek() == '^') { + parseLocal(reader) + } else if (twoDimensional) { + parseWorld2D(reader) + } else { + parseWorld3D(reader) + } + } catch (failure: CommandSyntaxException) { + throw failure.resetTo(reader, start) + } + } + + private fun parseWorld3D(reader: StringReader): RelativeVec { + val x = readWorldComponent(reader, blockAligned) + expectSeparator(reader) + val y = readWorldComponent(reader, blockAligned) + expectSeparator(reader) + val z = readWorldComponent(reader, blockAligned) + return RelativeVec( + Vec(x.value, y.value, z.value), + coordinateTypeOf(x.relative, y.relative, z.relative), + x.relative, + y.relative, + z.relative, + ) + } + + private fun parseWorld2D(reader: StringReader): RelativeVec { + val x = readWorldComponent(reader, blockAligned) + expectSeparator(reader) + val z = readWorldComponent(reader, blockAligned) + return RelativeVec( + Vec(x.value, 0.0, z.value), + coordinateTypeOf(x.relative, z.relative), + x.relative, + false, + z.relative, + ) + } + + private fun parseLocal(reader: StringReader): RelativeVec { + val left = readLocalComponent(reader) + expectSeparator(reader) + val up = readLocalComponent(reader) + expectSeparator(reader) + val forward = readLocalComponent(reader) + return RelativeVec(Vec(left, up, forward), RelativeVec.CoordinateType.LOCAL, true, true, true) + } +} + +/** + * Reads a vanilla-style rotation: a yaw component followed by a pitch component, each absolute or + * `~`-relative to the sender's current view. Local (`^`) coordinates are not part of vanilla's + * rotation grammar, so a leading `^` is rejected the same way it is for a position. + * + * The result is a [RelativeVec] whose `x` holds the yaw value and `z` the pitch value, resolved + * against a sender's view with [RelativeVec.fromView]. + */ +internal object RotationParser : ArgumentType { + override fun parse(reader: StringReader): RelativeVec { + val start = reader.cursor + try { + val yaw = readWorldComponent(reader, blockAligned = false) + expectSeparator(reader) + val pitch = readWorldComponent(reader, blockAligned = false) + return RelativeVec( + Vec(yaw.value, 0.0, pitch.value), + coordinateTypeOf(yaw.relative, pitch.relative), + yaw.relative, + false, + pitch.relative, + ) + } catch (failure: CommandSyntaxException) { + throw failure.resetTo(reader, start) + } + } +} + +/** + * Reads a swizzle of world axes, such as `xyz` or `xz`, case-insensitively and without a repeated + * letter. An unknown letter or a repeat is rejected at the swizzle's start. + */ +internal object AxisParser : ArgumentType> { + override fun parse(reader: StringReader): Set { + val start = reader.cursor + val axes = LinkedHashSet() + while (reader.canRead() && reader.peek() != ' ') { + val axis = when (reader.read().lowercaseChar()) { + 'x' -> Axis.X + 'y' -> Axis.Y + 'z' -> Axis.Z + else -> { + reader.cursor = start + throw ERROR_INVALID_SWIZZLE.createWithContext(reader) + } + } + if (!axes.add(axis)) { + reader.cursor = start + throw ERROR_INVALID_SWIZZLE.createWithContext(reader) + } + } + return axes + } +} + +/** + * Adapts [PositionParser] to the plain [Vec] that + * [dev.slne.surf.api.minestom.command.commandapi.argument.PositionArgument] and its 2D and block + * variants expose, resolving relative and local coordinates against the command source. + * + * A relative or local coordinate requires a command source to resolve against; parsed without one + * (as happens on the bare, sourceless overload, or when the source is not a [CommandSender]), it is + * rejected rather than silently resolved against the origin. + */ +internal class PositionArgumentType( + blockAligned: Boolean, + twoDimensional: Boolean, +) : ArgumentType { + private val delegate = PositionParser(blockAligned, twoDimensional) + + override fun parse(reader: StringReader): Vec = resolve(reader, null) + + override fun parse(reader: StringReader, source: S): Vec = resolve(reader, source as? CommandSender) + + private fun resolve(reader: StringReader, sender: CommandSender?): Vec { + val start = reader.cursor + val relative = delegate.parse(reader) + return requireResolvable(relative, sender, reader, start).fromSender(sender) + } +} + +/** + * Adapts [RotationParser] to the plain [Rotation] that + * [dev.slne.surf.api.minestom.command.commandapi.argument.RotationArgument] exposes, resolving a + * relative yaw or pitch against the command source's current view. + * + * A relative yaw or pitch requires a command source to resolve against; parsed without one (as + * happens on the bare, sourceless overload, or when the source is not a [CommandSender]), it is + * rejected rather than silently resolved against the origin's view. + */ +internal object RotationArgumentType : ArgumentType { + override fun parse(reader: StringReader): Rotation = resolve(reader, null) + + override fun parse(reader: StringReader, source: S): Rotation = resolve(reader, source as? CommandSender) + + private fun resolve(reader: StringReader, sender: CommandSender?): Rotation { + val start = reader.cursor + val relative = RotationParser.parse(reader) + val checked = requireResolvable(relative, sender, reader, start) + val view = checked.fromView((sender as? Entity)?.position ?: Pos.ZERO) + return Rotation(view.x().toFloat(), view.z().toFloat()) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelector.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelector.kt new file mode 100644 index 000000000..9698b340a --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelector.kt @@ -0,0 +1,83 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import net.minestom.server.MinecraftServer +import net.minestom.server.command.CommandSender +import net.minestom.server.coordinate.Pos +import net.minestom.server.entity.Entity +import net.minestom.server.instance.Instance +import java.util.UUID + +/** + * A resolved entity selector, produced by [EntitySelectorParser]. + * + * A bare player name or UUID resolves through [playerName]/[uuid] directly, bypassing + * [predicates] entirely, matching vanilla's own selector grammar where those forms never carry + * bracket options. Otherwise [find] gathers candidates - the sender's own entity for [self], + * online players for a player-only selector, every entity in the relevant instances otherwise - + * filters them with [predicates], orders them with [sorter] and caps the result at [limit]. + * + * [predicates] and [sorter] each receive the selector's anchor position alongside the candidate, + * resolved from [find]'s `sender` (an entity sender's own position, or the world origin for a + * sender without one) and adjusted by any explicit `x`/`y`/`z` option. [worldLimited] restricts + * position-based selectors (`x`, `y`, `z`, `dx`, `dy`, `dz`, `distance`) to the sender's own + * instance when the sender is an entity; a non-entity sender has no instance to restrict to, so + * the search falls back to every instance. + */ +internal class EntitySelector( + val maxResults: Int, + val includesEntities: Boolean, + val predicates: List<(Pos, Entity) -> Boolean>, + val sorter: ((Pos) -> Comparator)?, + val limit: Int, + val self: Boolean, + val playerName: String?, + val uuid: UUID?, + private val worldLimited: Boolean = false, +) { + fun find(sender: CommandSender): List { + playerName?.let { name -> + return listOfNotNull(MinecraftServer.getConnectionManager().getOnlinePlayerByUsername(name)) + } + uuid?.let { id -> + return listOfNotNull(findByUuid(id)) + } + + val anchor = (sender as? Entity)?.position ?: Pos.ZERO + if (self) { + val entity = sender as? Entity ?: return emptyList() + return if (matches(anchor, entity)) listOf(entity) else emptyList() + } + + val senderInstance = (sender as? Entity)?.instance + val candidates = if (includesEntities) { + instancesToSearch(senderInstance).asSequence().flatMap { it.entities.asSequence() } + } else { + MinecraftServer.getConnectionManager().onlinePlayers.asSequence() + .filter { player -> !worldLimited || senderInstance == null || player.instance === senderInstance } + } + + val filtered = candidates + .filter { entity -> !entity.isRemoved } + .filter { entity -> matches(anchor, entity) } + .toList() + val ordered = sorter?.let { comparatorFor -> filtered.sortedWith(comparatorFor(anchor)) } ?: filtered + + return ordered.take(minOf(limit, maxResults)) + } + + private fun matches(anchor: Pos, entity: Entity): Boolean = predicates.all { predicate -> predicate(anchor, entity) } + + private fun findByUuid(id: UUID): Entity? { + MinecraftServer.getConnectionManager().getOnlinePlayerByUuid(id)?.let { return it } + return MinecraftServer.getInstanceManager().instances.asSequence() + .flatMap { instance -> instance.entities.asSequence() } + .find { entity -> entity.uuid == id } + } + + private fun instancesToSearch(senderInstance: Instance?): Collection = + if (worldLimited && senderInstance != null) { + listOf(senderInstance) + } else { + MinecraftServer.getInstanceManager().instances + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelectorParser.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelectorParser.kt new file mode 100644 index 000000000..df632a57c --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/EntitySelectorParser.kt @@ -0,0 +1,631 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectList +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer +import net.minestom.server.MinecraftServer +import net.minestom.server.component.DataComponents +import net.minestom.server.coordinate.Pos +import net.minestom.server.entity.Entity +import net.minestom.server.entity.EntityType +import net.minestom.server.entity.GameMode +import net.minestom.server.entity.Player +import net.minestom.server.tag.Tag +import net.minestom.server.utils.Range +import java.util.* +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ThreadLocalRandom + +/** + * Reads a vanilla-style entity selector: `@a`, `@e`, `@p`, `@r` and `@s`, each with their implied + * limit and player-only default, an optional bracketed `key=value` option list, or a bare player + * name or UUID. + * + * [maxResults] is the ceiling this argument allows; a selector whose own limit (implied by its + * type or overridden by the `limit` option) exceeds it is rejected at parse time rather than + * silently truncated, mirroring vanilla's single-target `EntityArgument`. [playersOnly] rejects a + * selector that could include a non-player entity, except a self selector (`@s`), which is always + * accepted and then filtered normally. + * + * `nbt` is rejected outright: expressing it would require SNBT, which this port does not parse. + * `scores`, `advancements` and `predicate` have their grammar consumed - so a malformed value is + * still reported, and later options in the same bracket list still parse correctly - but are then + * rejected too, since Minestom has no per-entity scoreboard objectives, advancement progress or + * loot-condition registry to resolve them against. Every other listed option resolves against a + * real Minestom equivalent. + */ +internal class EntitySelectorParser( + private val maxResults: Int, + private val playersOnly: Boolean, +) : ArgumentType { + + override fun parse(reader: StringReader): EntitySelector { + val start = reader.cursor + val state = MutableSelector() + + if (reader.canRead() && reader.peek() == '@') { + reader.skip() + parseSelectorType(reader, state) + } else { + parseNameOrUuid(reader, state) + } + finalizePredicates(state) + + val selector = state.toSelector(maxResults) + if (selector.limit > maxResults) { + reader.cursor = start + throw (if (playersOnly) ERROR_NOT_SINGLE_PLAYER else ERROR_NOT_SINGLE_ENTITY).createWithContext( + reader + ) + } + if (selector.includesEntities && playersOnly && !selector.self) { + reader.cursor = start + throw ERROR_ONLY_PLAYERS_ALLOWED.createWithContext(reader) + } + return selector + } + + /** + * Offers the names of the online players followed by the selectors this argument accepts. + * + * A selector whose implied limit exceeds [maxResults] is left out, as is `@e` on a players-only + * argument, so every offered selector is one the parser would accept. + */ + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture { + val players = MinecraftServer.getConnectionManager().onlinePlayers + val values = ObjectArrayList(players.size + ENTITY_SELECTORS.size) + + players.mapTo(values, Player::getUsername) + values.sortWith(String.CASE_INSENSITIVE_ORDER) + + val selectors = if (playersOnly) PLAYER_SELECTORS else ENTITY_SELECTORS + selectors.forEach { selector -> + if (maxResults > 1 || selector in SINGLE_SELECTORS) values += selector + } + + return builder.suggestMatching(values) + } + + private companion object { + val SINGLE_SELECTORS: ObjectList = ObjectList.of("@p", "@r", "@s") + val PLAYER_SELECTORS: ObjectList = ObjectList.of("@p", "@r", "@a", "@s") + val ENTITY_SELECTORS: ObjectList = ObjectList.of("@p", "@r", "@a", "@e", "@s") + } +} + +/** Mutable accumulator for the selector being built; frozen into an [EntitySelector] once parsed. */ +private class MutableSelector { + var limit: Int = 1 + var includesEntities: Boolean = false + var self: Boolean = false + var playerName: String? = null + var uuid: UUID? = null + var sorter: ((Pos) -> Comparator)? = null + var worldLimited: Boolean = false + var x: Double? = null + var y: Double? = null + var z: Double? = null + var dx: Double? = null + var dy: Double? = null + var dz: Double? = null + var distance: Range.Float? = null + val predicates: MutableList<(Pos, Entity) -> Boolean> = mutableListOf() + + /** Options that may appear at most once: `x y z dx dy dz distance limit sort level`. */ + val singleUseSeen: MutableSet = mutableSetOf() + private val invertableStates: MutableMap = mutableMapOf() + + /** The `name`/`type`/`team`/`gamemode` tracking state for [key], created on first use. */ + fun invertableStateFor(key: String): InvertableState = + invertableStates.getOrPut(key) { InvertableState() } + + fun toSelector(maxResults: Int): EntitySelector = EntitySelector( + maxResults = maxResults, + includesEntities = includesEntities, + predicates = predicates.toList(), + sorter = sorter, + limit = limit, + self = self, + playerName = playerName, + uuid = uuid, + worldLimited = worldLimited, + ) +} + +/** + * Mirrors vanilla's `InvertableSetOptionState`: an option using this may be set once as a positive + * value, or any number of times as a negative (`!`) value, but never mixed - a positive after a + * negative, or any repeat after a positive, is rejected. + */ +private class InvertableState { + private var limitation = Limitation.NONE + + fun canParseElement(inverted: Boolean): Boolean = + if (inverted) limitation != Limitation.SINGLE else limitation == Limitation.NONE + + fun markParsedElement(inverted: Boolean) { + limitation = if (inverted) Limitation.MULTIPLE else Limitation.SINGLE + } + + private enum class Limitation { NONE, SINGLE, MULTIPLE } +} + +private fun parseNameOrUuid(reader: StringReader, state: MutableSelector) { + val start = reader.cursor + val name = reader.readString() + val uuid = runCatching { UUID.fromString(name) }.getOrNull() + + if (uuid != null) { + state.uuid = uuid + state.includesEntities = true + } else { + if (name.isEmpty() || name.length > 16) { + reader.cursor = start + throw ERROR_INVALID_NAME_OR_UUID.createWithContext(reader) + } + state.playerName = name + state.includesEntities = false + } + state.limit = 1 +} + +private fun parseSelectorType(reader: StringReader, state: MutableSelector) { + if (!reader.canRead()) throw ERROR_MISSING_SELECTOR_TYPE.createWithContext(reader) + val typeStart = reader.cursor + val type = reader.read() + + when (type) { + 'a' -> { + state.limit = Int.MAX_VALUE + state.includesEntities = false + } + + 'e' -> { + state.limit = Int.MAX_VALUE + state.includesEntities = true + } + + 'p' -> { + state.limit = 1 + state.includesEntities = false + state.sorter = ::nearestComparator + } + + 'r' -> { + state.limit = 1 + state.includesEntities = false + state.sorter = ::randomComparator + } + + 's' -> { + state.limit = 1 + state.includesEntities = true + state.self = true + } + + else -> { + reader.cursor = typeStart + throw ERROR_UNKNOWN_SELECTOR_TYPE.createWithContext(reader, "@$type") + } + } + + if (reader.canRead() && reader.peek() == '[') { + reader.skip() + parseOptions(reader, state) + } +} + +private fun parseOptions(reader: StringReader, state: MutableSelector) { + reader.skipWhitespace() + while (reader.canRead() && reader.peek() != ']') { + reader.skipWhitespace() + val keyStart = reader.cursor + val key = reader.readString() + reader.skipWhitespace() + if (!reader.canRead() || reader.peek() != '=') { + reader.cursor = keyStart + throw ERROR_EXPECTED_OPTION_VALUE.createWithContext(reader, key) + } + reader.skip() + reader.skipWhitespace() + applyOption(key, keyStart, reader, state) + reader.skipWhitespace() + if (reader.canRead()) { + if (reader.peek() != ',') { + if (reader.peek() != ']') throw ERROR_EXPECTED_END_OF_OPTIONS.createWithContext( + reader + ) + break + } + reader.skip() + reader.skipWhitespace() + } + } + + if (reader.canRead()) { + reader.skip() + } else { + throw ERROR_EXPECTED_END_OF_OPTIONS.createWithContext(reader) + } +} + +private fun applyOption(key: String, keyStart: Int, reader: StringReader, state: MutableSelector) { + val valueStart = reader.cursor + when (key) { + "x" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.x = reader.readDouble() + } + + "y" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.y = reader.readDouble() + } + + "z" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.z = reader.readDouble() + } + + "dx" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.dx = reader.readDouble() + } + + "dy" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.dy = reader.readDouble() + } + + "dz" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.dz = reader.readDouble() + } + + "distance" -> { + requireSingleUse(key, keyStart, reader, state) + state.worldLimited = true + state.distance = FloatRangeParser.parse(reader) + } + + "limit" -> { + requireSingleUse(key, keyStart, reader, state, applicable = !state.self) + val count = reader.readInt() + if (count < 1) { + reader.cursor = keyStart + throw ERROR_LIMIT_TOO_SMALL.createWithContext(reader) + } + state.limit = count + } + + "sort" -> { + requireSingleUse(key, keyStart, reader, state, applicable = !state.self) + val name = reader.readUnquotedString() + state.sorter = when (name) { + "nearest" -> ::nearestComparator + "furthest" -> ::furthestComparator + "random" -> ::randomComparator + "arbitrary" -> null + else -> { + reader.cursor = keyStart + throw ERROR_SORT_UNKNOWN.createWithContext(reader, name) + } + } + } + + "name" -> { + val inverted = shouldInvertValue(reader) + requireInvertableUse(key, inverted, valueStart, reader, state) + val name = reader.readString() + state.predicates += { _, entity -> matchesName(entity, name) != inverted } + } + + "type" -> { + val inverted = shouldInvertValue(reader) + requireInvertableUse(key, inverted, valueStart, reader, state) + val typeStart = reader.cursor + val key0 = ResourceLocationParser.readKey(reader) + val type = EntityType.fromKey(key0) ?: run { + reader.cursor = typeStart + throw ERROR_ENTITY_TYPE_INVALID.createWithContext(reader, key0.asString()) + } + if (type == EntityType.PLAYER && !inverted) { + state.includesEntities = false + } + state.predicates += { _, entity -> (entity.entityType == type) != inverted } + } + + "tag" -> { + val inverted = shouldInvertValue(reader) + val tag = reader.readUnquotedString() + state.predicates += { _, entity -> + // `?: emptyList()` guards an entity that never had ENTITY_TAGS written: the tag's + // own default should cover this, but nothing here may rely on that to avoid an NPE + // inside a predicate. + val tags = entity.getTag(ENTITY_TAGS) ?: emptyList() + (if (tag.isEmpty()) tags.isEmpty() else tags.contains(tag)) != inverted + } + } + + "team" -> { + val inverted = shouldInvertValue(reader) + requireInvertableUse(key, inverted, valueStart, reader, state) + val team = reader.readUnquotedString() + state.predicates += { _, entity -> (teamNameOf(entity) == team) != inverted } + } + + "gamemode" -> { + val inverted = shouldInvertValue(reader) + requireInvertableUse(key, inverted, valueStart, reader, state) + val mode = GAME_MODE_PARSER.parse(reader) + state.includesEntities = false + state.predicates += { _, entity -> (entity is Player && entity.gameMode == mode) != inverted } + } + + "level" -> { + requireSingleUse(key, keyStart, reader, state) + val range = IntegerRangeParser.parse(reader) + state.includesEntities = false + state.predicates += { _, entity -> entity is Player && range.inRange(entity.level) } + } + + "scores" -> { + consumeScores(reader) + reader.cursor = keyStart + throw ERROR_UNSUPPORTED_OPTION.createWithContext(reader, key) + } + + "advancements" -> { + consumeAdvancements(reader) + reader.cursor = keyStart + throw ERROR_UNSUPPORTED_OPTION.createWithContext(reader, key) + } + + "predicate" -> { + shouldInvertValue(reader) + ResourceLocationParser.readKey(reader) + reader.cursor = keyStart + throw ERROR_UNSUPPORTED_OPTION.createWithContext(reader, key) + } + + "nbt" -> { + reader.cursor = keyStart + throw ERROR_NBT_UNSUPPORTED.createWithContext(reader) + } + + else -> { + reader.cursor = keyStart + throw ERROR_UNKNOWN_OPTION.createWithContext(reader, key) + } + } +} + +/** + * Rejects a repeated use of a single-use option (`x y z dx dy dz distance limit sort level`), and, + * for `limit`/`sort`, a use on a self selector (`@s`) at all - both mirror vanilla's per-option + * `canUse` gate, checked before the value is read so a repeat never even attempts to parse it. + */ +private fun requireSingleUse( + key: String, + keyStart: Int, + reader: StringReader, + state: MutableSelector, + applicable: Boolean = true, +) { + if (!applicable || !state.singleUseSeen.add(key)) { + reader.cursor = keyStart + throw ERROR_INAPPLICABLE_OPTION.createWithContext(reader, key) + } +} + +/** + * Rejects a `name`/`type`/`team`/`gamemode` use that would mix a positive value with any other + * value, or repeat a positive value - see [InvertableState]. Vanilla checks this at different + * points relative to reading the value depending on the option; since a rejection here always + * aborts the whole selector, checking immediately (before the value is read) is behaviorally + * identical for every caller and simpler to keep consistent across the four options. + */ +private fun requireInvertableUse( + key: String, + inverted: Boolean, + valueStart: Int, + reader: StringReader, + state: MutableSelector, +) { + val invertableState = state.invertableStateFor(key) + if (!invertableState.canParseElement(inverted)) { + reader.cursor = valueStart + throw ERROR_INAPPLICABLE_OPTION.createWithContext(reader, key) + } + invertableState.markParsedElement(inverted) +} + +/** + * Adds the volume-box and distance predicates once every option has been read, so both see the + * final `x`/`y`/`z`/`dx`/`dy`/`dz`/`distance` values regardless of the order they appeared in. + */ +private fun finalizePredicates(state: MutableSelector) { + if (state.dx != null || state.dy != null || state.dz != null) { + state.predicates += { anchor, entity -> matchesVolume(anchor, state, entity) } + } + if (state.distance != null) { + state.predicates += { anchor, entity -> matchesDistance(anchor, state, entity) } + } +} + +/** The anchor point: the sender's position with any explicit `x`/`y`/`z` substituted per axis. */ +private fun anchorOf(basePos: Pos, state: MutableSelector): Pos = + Pos(state.x ?: basePos.x(), state.y ?: basePos.y(), state.z ?: basePos.z()) + +/** + * Matches entities within the box anchored at [anchor]'s origin corner, extended by `dx`/`dy`/`dz` + * on whichever side is positive. Each axis's non-negative side is extended by one extra block + * (mirroring vanilla's `EntitySelectorParser.createAabb`), so `dx=0,dy=0,dz=0` selects the single + * block the origin sits in rather than a degenerate zero-width box. + */ +private fun matchesVolume(anchor: Pos, state: MutableSelector, entity: Entity): Boolean { + val origin = anchorOf(anchor, state) + val dx = state.dx ?: 0.0 + val dy = state.dy ?: 0.0 + val dz = state.dz ?: 0.0 + val pos = entity.position + + return pos.x() >= origin.x() + minOf(0.0, dx) && pos.x() <= origin.x() + maxOf(0.0, dx) + 1.0 && + pos.y() >= origin.y() + minOf(0.0, dy) && pos.y() <= origin.y() + maxOf( + 0.0, + dy + ) + 1.0 && + pos.z() >= origin.z() + minOf(0.0, dz) && pos.z() <= origin.z() + maxOf(0.0, dz) + 1.0 +} + +private fun matchesDistance(anchor: Pos, state: MutableSelector, entity: Entity): Boolean { + val range = state.distance ?: return true + val origin = anchorOf(anchor, state) + return range.inRange(entity.getDistance(origin).toFloat()) +} + +private fun matchesName(entity: Entity, name: String): Boolean = when (entity) { + is Player -> entity.username == name + else -> entity.get(DataComponents.CUSTOM_NAME) + ?.let { component -> PlainTextComponentSerializer.plainText().serialize(component) } == name +} + +/** The name of the team `entity` belongs to, or an empty string if it belongs to none. */ +private fun teamNameOf(entity: Entity): String { + val identifier = if (entity is Player) entity.username else entity.uuid.toString() + return MinecraftServer.getTeamManager().teams + .firstOrNull { team -> identifier in team.members } + ?.teamName ?: "" +} + +private fun shouldInvertValue(reader: StringReader): Boolean { + reader.skipWhitespace() + if (reader.canRead() && reader.peek() == '!') { + reader.skip() + reader.skipWhitespace() + return true + } + return false +} + +/** Consumes a `{name=range,...}` value without keeping it: `scores` has no backing store here. */ +private fun consumeScores(reader: StringReader) { + reader.expect('{') + reader.skipWhitespace() + while (reader.canRead() && reader.peek() != '}') { + reader.skipWhitespace() + reader.readUnquotedString() + reader.skipWhitespace() + reader.expect('=') + reader.skipWhitespace() + IntegerRangeParser.parse(reader) + reader.skipWhitespace() + if (reader.canRead() && reader.peek() == ',') reader.skip() + reader.skipWhitespace() + } + reader.expect('}') +} + +/** Consumes a `{id=bool}` / `{id={crit=bool,...}}` value without keeping it: same reasoning as [consumeScores]. */ +private fun consumeAdvancements(reader: StringReader) { + reader.expect('{') + reader.skipWhitespace() + while (reader.canRead() && reader.peek() != '}') { + reader.skipWhitespace() + ResourceLocationParser.readKey(reader) + reader.skipWhitespace() + reader.expect('=') + reader.skipWhitespace() + if (reader.canRead() && reader.peek() == '{') { + reader.skip() + reader.skipWhitespace() + while (reader.canRead() && reader.peek() != '}') { + reader.skipWhitespace() + reader.readUnquotedString() + reader.skipWhitespace() + reader.expect('=') + reader.skipWhitespace() + reader.readBoolean() + reader.skipWhitespace() + if (reader.canRead() && reader.peek() == ',') reader.skip() + reader.skipWhitespace() + } + reader.expect('}') + } else { + reader.readBoolean() + } + reader.skipWhitespace() + if (reader.canRead() && reader.peek() == ',') reader.skip() + reader.skipWhitespace() + } + reader.expect('}') +} + +private fun nearestComparator(anchor: Pos): Comparator = + Comparator.comparingDouble { entity: Entity -> entity.getDistanceSquared(anchor) } + +private fun furthestComparator(anchor: Pos): Comparator = + nearestComparator(anchor).reversed() + +/** A stable-per-invocation random order: each entity gets one random key, reused across comparisons. */ +private fun randomComparator(@Suppress("UNUSED_PARAMETER") anchor: Pos): Comparator { + val weights = IdentityHashMap() + val random = ThreadLocalRandom.current() + return Comparator.comparingDouble { entity -> weights.getOrPut(entity) { random.nextDouble() } } +} + +private val GAME_MODE_PARSER = + FixedSetParser(GameMode.entries.associateBy { mode -> mode.name.lowercase() }) + +/** Backing store for the `tag` option; nothing writes to it yet, so it is always empty today. */ +private val ENTITY_TAGS: Tag> = Tag.String("tags").list().defaultValue(emptyList()) + +private val ERROR_MISSING_SELECTOR_TYPE = + SimpleCommandExceptionType(LiteralMessage("Missing selector type")) +private val ERROR_UNKNOWN_SELECTOR_TYPE = + DynamicCommandExceptionType { type -> LiteralMessage("Unknown selector type '$type'") } +private val ERROR_INVALID_NAME_OR_UUID = + SimpleCommandExceptionType(LiteralMessage("Invalid player name or UUID")) +private val ERROR_EXPECTED_OPTION_VALUE = + DynamicCommandExceptionType { key -> LiteralMessage("Expected value for option '$key'") } +private val ERROR_EXPECTED_END_OF_OPTIONS = + SimpleCommandExceptionType(LiteralMessage("Expected ',' or ']'")) +private val ERROR_UNKNOWN_OPTION = + DynamicCommandExceptionType { key -> LiteralMessage("Unknown option '$key'") } +private val ERROR_INAPPLICABLE_OPTION = + DynamicCommandExceptionType { key -> LiteralMessage("Option '$key' cannot be used here") } +private val ERROR_UNSUPPORTED_OPTION = DynamicCommandExceptionType { key -> + LiteralMessage("Option '$key' is unsupported: this command implementation has no equivalent in Minestom's model") +} +private val ERROR_NBT_UNSUPPORTED = SimpleCommandExceptionType( + LiteralMessage("Option 'nbt' is unsupported: this command implementation cannot parse SNBT"), +) +private val ERROR_LIMIT_TOO_SMALL = + SimpleCommandExceptionType(LiteralMessage("Limit must be at least 1")) +private val ERROR_SORT_UNKNOWN = + DynamicCommandExceptionType { name -> LiteralMessage("Unknown sort '$name'") } +private val ERROR_ENTITY_TYPE_INVALID = + DynamicCommandExceptionType { type -> LiteralMessage("Unknown entity type '$type'") } +private val ERROR_NOT_SINGLE_ENTITY = + SimpleCommandExceptionType(LiteralMessage("Expected a single entity")) +private val ERROR_NOT_SINGLE_PLAYER = + SimpleCommandExceptionType(LiteralMessage("Expected a single player")) +private val ERROR_ONLY_PLAYERS_ALLOWED = + SimpleCommandExceptionType(LiteralMessage("Only players can be targeted")) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/FixedSetParser.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/FixedSetParser.kt new file mode 100644 index 000000000..3e1dd84a8 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/FixedSetParser.kt @@ -0,0 +1,43 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import java.util.concurrent.CompletableFuture + +/** + * Reads one word and resolves it against a fixed set of accepted spellings. + * + * Matching is case-sensitive, since each spelling is the canonical form its owning argument + * stringifies back to; accepting other casings would let two spellings map to the same value. + * Suggestions are offered case-insensitively, which costs nothing since they are only a typing + * convenience. + */ +internal class FixedSetParser(private val values: Map) : ArgumentType { + override fun parse(reader: StringReader): T { + val start = reader.cursor + val word = reader.readUnquotedString() + + return values[word] ?: run { + reader.cursor = start + throw UNKNOWN.createWithContext(reader, word) + } + } + + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture = builder.suggestMatching(values.keys) + + override fun getExamples(): Collection = values.keys.take(2) + + private companion object { + val UNKNOWN = DynamicCommandExceptionType { value -> + LiteralMessage("Unknown value '$value'") + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/InstanceParser.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/InstanceParser.kt new file mode 100644 index 000000000..5a3df8533 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/InstanceParser.kt @@ -0,0 +1,76 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import net.minestom.server.MinecraftServer +import net.minestom.server.instance.Instance +import java.util.UUID +import java.util.concurrent.CompletableFuture + +/** + * Reads a UUID or a dimension name and resolves it against the currently registered instances. + * + * A dimension name only resolves when it is unique among registered instances; an ambiguous or + * unmatched token is reported at the position it started at. + */ +internal object InstanceParser : ArgumentType { + private val UNKNOWN = DynamicCommandExceptionType { value -> + LiteralMessage("Unknown or ambiguous instance '$value'; use its UUID") + } + + override fun parse(reader: StringReader): Instance { + val start = reader.cursor + while (reader.canRead() && isAllowed(reader.peek())) { + reader.skip() + } + val input = reader.string.substring(start, reader.cursor) + + return resolve(input) ?: run { + reader.cursor = start + throw UNKNOWN.createWithContext(reader, input) + } + } + + /** + * Offers every instance's UUID, plus the dimension names that currently identify exactly one + * instance — an ambiguous name is not suggested because it would not resolve. + */ + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture { + val instances = MinecraftServer.getInstanceManager().instances + val dimensionCounts = Object2IntOpenHashMap() + instances.forEach { instance -> dimensionCounts.addTo(instance.dimensionName, 1) } + + val values = ObjectArrayList(instances.size * 2) + instances.forEach { instance -> values += instance.uuid.toString() } + instances.forEach { instance -> + if (dimensionCounts.getInt(instance.dimensionName) == 1) { + values += instance.dimensionName + } + } + + return builder.suggestMatching(values) + } + + private fun resolve(input: String): Instance? { + val instances = MinecraftServer.getInstanceManager().instances + runCatching { UUID.fromString(input) }.getOrNull()?.let { uuid -> + instances.singleOrNull { instance -> instance.uuid == uuid }?.let { return it } + } + return instances.singleOrNull { instance -> instance.dimensionName == input } + } + + private fun isAllowed(character: Char): Boolean = character in '0'..'9' || + character in 'a'..'z' || character in 'A'..'Z' || + character == '_' || character == ':' || character == '/' || + character == '.' || character == '-' +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ParticleParser.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ParticleParser.kt new file mode 100644 index 000000000..2023e93c5 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ParticleParser.kt @@ -0,0 +1,41 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType +import net.minestom.server.particle.Particle + +/** + * Reads a namespaced particle key and resolves it to its option-free [Particle.Simple] value. + * + * A key naming a particle that carries options (`dust`, `block`, `vibration`, and similar) is + * rejected as unsupported rather than silently resolved to its default-valued instance, since this + * parser has no syntax for particle options. An unrecognized key is rejected as unknown. Both + * failures are reported at the position the key started at. + */ +internal object ParticleParser : ArgumentType { + private val UNKNOWN = DynamicCommandExceptionType { value -> + LiteralMessage("Unknown particle '$value'") + } + + private val UNSUPPORTED = DynamicCommandExceptionType { value -> + LiteralMessage("Unsupported particle '$value'; it requires options this argument cannot express") + } + + override fun parse(reader: StringReader): Particle { + val start = reader.cursor + val key = ResourceLocationParser.readKey(reader) + val particle = Particle.fromKey(key) ?: run { + reader.cursor = start + throw UNKNOWN.createWithContext(reader, key.asString()) + } + + if (particle !is Particle.Simple) { + reader.cursor = start + throw UNSUPPORTED.createWithContext(reader, key.asString()) + } + + return particle + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/RegistryParser.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/RegistryParser.kt new file mode 100644 index 000000000..5af9d7967 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/RegistryParser.kt @@ -0,0 +1,47 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import net.kyori.adventure.key.Key +import java.util.concurrent.CompletableFuture + +/** + * Reads a namespaced key and resolves it through [lookup]. + * + * [registryName] only appears in the failure message. A key that resolves to `null` is reported at + * the position the key started at, so the client underlines the key rather than the rest of the line. + * + * [keys] is queried on every completion rather than captured once, because a registry may gain + * entries after the argument was built. + */ +internal class RegistryParser( + private val registryName: String, + private val keys: () -> Iterable = ::emptyList, + private val lookup: (Key) -> T?, +) : ArgumentType { + override fun parse(reader: StringReader): T { + val start = reader.cursor + val key = ResourceLocationParser.readKey(reader) + + return lookup(key) ?: run { + reader.cursor = start + throw UNKNOWN.createWithContext(reader, "$registryName '$key'") + } + } + + override fun listSuggestions( + context: CommandContext, + builder: SuggestionsBuilder, + ): CompletableFuture = builder.suggestMatching(keys()) + + private companion object { + val UNKNOWN = DynamicCommandExceptionType { value -> + LiteralMessage("Unknown $value") + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ResourceLocationParser.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ResourceLocationParser.kt new file mode 100644 index 000000000..95d0465c6 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ResourceLocationParser.kt @@ -0,0 +1,56 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.exceptions.CommandSyntaxException +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import net.kyori.adventure.key.InvalidKeyException +import net.kyori.adventure.key.Key + +/** + * Reads a namespaced key such as `minecraft:stone`, defaulting the namespace to `minecraft`. + */ +internal object ResourceLocationParser : ArgumentType { + private val INVALID = SimpleCommandExceptionType(LiteralMessage("Invalid identifier")) + + override fun parse(reader: StringReader): Key = readKey(reader) + + /** + * Reads a namespaced key from [reader], consuming only characters allowed in a key and + * leaving the rest of the input untouched. + * + * A key with no separator, or with the separator as its first character, defaults its + * namespace to `minecraft`. The path must not be empty. + * + * @throws CommandSyntaxException if the consumed text is not a valid key + */ + fun readKey(reader: StringReader): Key { + val start = reader.cursor + while (reader.canRead() && isAllowed(reader.peek())) { + reader.skip() + } + + val text = reader.string.substring(start, reader.cursor) + val separator = text.indexOf(':') + val namespace = if (separator >= 1) text.substring(0, separator) else Key.MINECRAFT_NAMESPACE + val value = if (separator >= 0) text.substring(separator + 1) else text + if (value.isEmpty()) invalid(reader, start) + + return try { + Key.key(namespace, value) + } catch (cause: InvalidKeyException) { + invalid(reader, start) + } + } + + private fun invalid(reader: StringReader, start: Int): Nothing { + reader.cursor = start + throw INVALID.createWithContext(reader) + } + + private fun isAllowed(character: Char): Boolean = character in '0'..'9' || + character in 'a'..'z' || + character == '_' || character == ':' || character == '/' || + character == '.' || character == '-' +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ScalarParsers.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ScalarParsers.kt new file mode 100644 index 000000000..ee9d64c78 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/ScalarParsers.kt @@ -0,0 +1,211 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.LiteralMessage +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType +import net.minestom.server.MinecraftServer +import net.minestom.server.entity.Entity +import net.minestom.server.utils.Range +import java.time.Duration +import java.util.UUID + +/** + * Reads a UUID in its canonical dashed hex form, e.g. `550e8400-e29b-41d4-a716-446655440000`. + */ +internal object UuidParser : ArgumentType { + private val INVALID = SimpleCommandExceptionType(LiteralMessage("Invalid UUID")) + + override fun parse(reader: StringReader): UUID { + val start = reader.cursor + while (reader.canRead() && isAllowed(reader.peek())) { + reader.skip() + } + val text = reader.string.substring(start, reader.cursor) + + return try { + UUID.fromString(text) + } catch (cause: IllegalArgumentException) { + reader.cursor = start + throw INVALID.createWithContext(reader) + } + } + + private fun isAllowed(character: Char): Boolean = character in '0'..'9' || + character in 'a'..'f' || character in 'A'..'F' || character == '-' +} + +/** + * Reads an angle in degrees: an absolute value, or `~` optionally followed by an offset applied to + * the source's own yaw. The result is wrapped into `[-180, 180)`. + * + * A source that has no position - the console, for instance - counts as facing yaw `0`. + */ +internal object AngleParser : ArgumentType { + private val INCOMPLETE = SimpleCommandExceptionType(LiteralMessage("Expected an angle")) + private val INVALID = SimpleCommandExceptionType(LiteralMessage("Invalid angle")) + + override fun parse(reader: StringReader): Float = read(reader, yaw = 0f) + + override fun parse(reader: StringReader, source: S): Float = + read(reader, (source as? Entity)?.position?.yaw ?: 0f) + + private fun read(reader: StringReader, yaw: Float): Float { + if (!reader.canRead()) throw INCOMPLETE.createWithContext(reader) + + val relative = reader.peek() == '~' + if (relative) reader.skip() + + val start = reader.cursor + val value = if (reader.canRead() && reader.peek() != ' ') reader.readFloat() else 0f + if (!value.isFinite()) { + reader.cursor = start + throw INVALID.createWithContext(reader) + } + + return wrapDegrees(if (relative) value + yaw else value) + } + + private fun wrapDegrees(degrees: Float): Float { + var wrapped = degrees % 360f + if (wrapped >= 180f) wrapped -= 360f + if (wrapped < -180f) wrapped += 360f + return wrapped + } +} + +/** + * Reads a suffixed vanilla duration: a number followed by an optional unit, `d` for days + * (24000 ticks), `s` for seconds (20 ticks) or `t` for ticks; an absent suffix also means ticks. + * + * The result is rejected if it would be negative or if the suffix is anything else. + */ +internal object TimeParser : ArgumentType { + private val INVALID_UNIT = DynamicCommandExceptionType { unit -> + LiteralMessage("Invalid unit '$unit'; expected 'd', 's', 't' or none") + } + private val NEGATIVE = SimpleCommandExceptionType(LiteralMessage("Duration must not be negative")) + + override fun parse(reader: StringReader): Duration { + val start = reader.cursor + val amount = reader.readFloat() + val unit = if (reader.canRead() && reader.peek() != ' ') reader.read() else null + + val factor = unitFactor(unit) ?: run { + reader.cursor = start + throw INVALID_UNIT.createWithContext(reader, unit.toString()) + } + + val ticks = (amount * factor).toLong() + if (ticks < 0) { + reader.cursor = start + throw NEGATIVE.createWithContext(reader) + } + + return Duration.ofMillis(ticks * MinecraftServer.TICK_MS) + } + + private fun unitFactor(unit: Char?): Int? = when (unit) { + null, 't' -> 1 + 's' -> 20 + 'd' -> 24000 + else -> null + } +} + +/** + * Reads an integer range in vanilla's `min..max` syntax. + * + * Either bound may be omitted, in which case it resolves to [Int.MIN_VALUE] or [Int.MAX_VALUE] + * respectively. A bare value is shorthand for a range containing only that value. At least one + * bound must be present, and the lower bound must not exceed the upper one. + */ +internal object IntegerRangeParser : ArgumentType { + override fun parse(reader: StringReader): Range.Int { + val start = reader.cursor + val (min, max) = readRange(reader, String::toIntOrNull) + return try { + Range.Int(min ?: Int.MIN_VALUE, max ?: Int.MAX_VALUE) + } catch (cause: IllegalArgumentException) { + reader.cursor = start + throw RANGE_INVERTED.createWithContext(reader) + } + } +} + +/** + * Reads a float range in vanilla's `min..max` syntax. + * + * Either bound may be omitted, in which case it resolves to `-Float.MAX_VALUE` or + * `Float.MAX_VALUE` respectively. A bare value is shorthand for a range containing only that + * value. At least one bound must be present, and the lower bound must not exceed the upper one. + */ +internal object FloatRangeParser : ArgumentType { + override fun parse(reader: StringReader): Range.Float { + val start = reader.cursor + val (min, max) = readRange(reader, String::toFloatOrNull) + return try { + Range.Float(min ?: -Float.MAX_VALUE, max ?: Float.MAX_VALUE) + } catch (cause: IllegalArgumentException) { + reader.cursor = start + throw RANGE_INVERTED.createWithContext(reader) + } + } +} + +private val RANGE_EMPTY = SimpleCommandExceptionType(LiteralMessage("Expected value or range of values")) +private val RANGE_INVALID = DynamicCommandExceptionType { value -> LiteralMessage("Invalid range value '$value'") } +private val RANGE_INVERTED = SimpleCommandExceptionType(LiteralMessage("Range minimum must not exceed its maximum")) + +/** + * Reads a `..` range (either side optional, a bare value standing for both), and + * converts each side with [parse]. Resets [reader]'s cursor to the range's start before throwing. + */ +private fun readRange(reader: StringReader, parse: (String) -> T?): Pair { + val start = reader.cursor + val lowerText = readRangeBoundText(reader) + val upperText = if (reader.canRead(2) && reader.peek() == '.' && reader.peek(1) == '.') { + reader.skip() + reader.skip() + readRangeBoundText(reader) + } else { + lowerText + } + + if (lowerText.isEmpty() && upperText.isEmpty()) { + reader.cursor = start + throw RANGE_EMPTY.createWithContext(reader) + } + + fun parseBound(text: String): T? { + if (text.isEmpty()) return null + return parse(text) ?: run { + reader.cursor = start + throw RANGE_INVALID.createWithContext(reader, text) + } + } + + return parseBound(lowerText) to parseBound(upperText) +} + +/** + * Reads one side of a range: an optional `-`, digits, and an optional single `.` followed by + * more digits. Stops before a `..` separator instead of consuming it as a decimal point. + */ +private fun readRangeBoundText(reader: StringReader): String { + val start = reader.cursor + if (reader.canRead() && reader.peek() == '-') { + reader.skip() + } + while (reader.canRead() && reader.peek() in '0'..'9') { + reader.skip() + } + if (reader.canRead() && reader.peek() == '.' && !(reader.canRead(2) && reader.peek(1) == '.')) { + reader.skip() + while (reader.canRead() && reader.peek() in '0'..'9') { + reader.skip() + } + } + return reader.string.substring(start, reader.cursor) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/Suggesting.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/Suggesting.kt new file mode 100644 index 000000000..76d6af533 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/argument/parser/Suggesting.kt @@ -0,0 +1,20 @@ +package dev.slne.surf.api.minestom.command.commandapi.argument.parser + +import com.mojang.brigadier.suggestion.Suggestions +import com.mojang.brigadier.suggestion.SuggestionsBuilder +import java.util.concurrent.CompletableFuture + +/** + * Adds every entry of [values] that continues what has been typed so far, and completes the builder. + * + * Matching is case-insensitive because a suggestion is only a typing convenience; the parser still + * decides which spellings it accepts. + */ +internal fun SuggestionsBuilder.suggestMatching( + values: Iterable, +): CompletableFuture { + values.forEach { value -> + if (value.startsWith(remaining, ignoreCase = true)) suggest(value) + } + return buildFuture() +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ArgumentDsl.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ArgumentDsl.kt new file mode 100644 index 000000000..5706b3b85 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ArgumentDsl.kt @@ -0,0 +1,869 @@ +package dev.slne.surf.api.minestom.command.commandapi.dsl + +import dev.slne.surf.api.minestom.command.commandapi.CommandAPICommand +import dev.slne.surf.api.minestom.command.commandapi.CommandTree +import dev.slne.surf.api.minestom.command.commandapi.argument.* +import net.kyori.adventure.chat.SignedMessage +import net.kyori.adventure.key.Key +import net.minestom.server.color.TeamColor +import net.minestom.server.coordinate.Vec +import net.minestom.server.entity.Entity +import net.minestom.server.entity.EntityType +import net.minestom.server.entity.GameMode +import net.minestom.server.entity.Player +import net.minestom.server.instance.Instance +import net.minestom.server.item.enchant.Enchantment +import net.minestom.server.particle.Particle +import net.minestom.server.potion.PotionEffect +import net.minestom.server.registry.Registry +import net.minestom.server.registry.RegistryKey +import net.minestom.server.sound.SoundEvent +import net.minestom.server.utils.Range +import net.minestom.server.world.biome.Biome +import java.time.Duration +import java.util.* + +inline fun CommandAPICommand.booleanArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + BooleanArgument(nodeName).setOptional(optional = optional).apply(block), +) + +inline fun CommandAPICommand.integerArgument( + nodeName: String, + min: Int = Int.MIN_VALUE, + max: Int = Int.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + IntegerArgument(nodeName, min, max).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.stringArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + StringArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.textArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + TextArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.greedyStringArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + GreedyStringArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.signedMessageArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + SignedMessageArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.literalArgument( + nodeName: String, + literal: String = nodeName, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(LiteralArgument(nodeName, literal).apply(block)) + +inline fun CommandAPICommand.playerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + PlayerArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.playersArgument( + nodeName: String, + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = withArguments( + PlayersArgument(nodeName, allowEmpty).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.entityArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + EntityArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.entitiesArgument( + nodeName: String, + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = withArguments( + EntitiesArgument(nodeName, allowEmpty).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.entityTypeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + EntityTypeArgument(nodeName).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.locationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(PositionArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.location2DArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = + withArguments(Position2DArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.blockPositionArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = + withArguments(BlockPositionArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.rotationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(RotationArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.angleArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(AngleArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.axisArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = withArguments(AxisArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.resourceLocationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = + withArguments(ResourceLocationArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.timeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(TimeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.teamColorArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(TeamColorArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.particleArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(ParticleArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.gameModeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(GameModeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.commandArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(CommandArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.soundArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(SoundArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.potionEffectArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = + withArguments(PotionEffectArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.biomeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = withArguments(BiomeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.enchantmentArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = + withArguments(EnchantmentArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.resourceArgument( + nodeName: String, + identifier: String, + registry: Registry, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = withArguments( + ResourceArgument(nodeName, identifier, registry).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.instanceArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(InstanceArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.longArgument( + nodeName: String, + min: Long = Long.MIN_VALUE, + max: Long = Long.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + LongArgument(nodeName, min, max).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.floatArgument( + nodeName: String, + min: Float = -Float.MAX_VALUE, + max: Float = Float.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + FloatArgument(nodeName, min, max).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.doubleArgument( + nodeName: String, + min: Double = -Double.MAX_VALUE, + max: Double = Double.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + DoubleArgument(nodeName, min, max).setOptional(optional).apply(block), +) + +inline fun > CommandAPICommand.enumArgument( + nodeName: String, + values: Collection, + noinline formatter: (E) -> String = { value -> value.name.lowercase() }, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + EnumArgument(nodeName, values, formatter).setOptional(optional).apply(block), +) + +inline fun CommandAPICommand.uuidArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(UUIDArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.integerRangeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = + withArguments(IntegerRangeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.floatRangeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandAPICommand = + withArguments(FloatRangeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandAPICommand.multiLiteralArgument( + nodeName: String, + vararg literals: String, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments(MultiLiteralArgument(nodeName, *literals).apply(block)) + +inline fun CommandTree.integerArgument( + nodeName: String, + min: Int = Int.MIN_VALUE, + max: Int = Int.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(IntegerArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun CommandTree.stringArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(StringArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.literalArgument( + nodeName: String, + literal: String = nodeName, + block: Argument.() -> Unit = {}, +): CommandTree = then(LiteralArgument(nodeName, literal).apply(block)) + +inline fun CommandTree.playerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(PlayerArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.playersArgument( + nodeName: String, + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = then(PlayersArgument(nodeName, allowEmpty).setOptional(optional).apply(block)) + +inline fun CommandTree.entityArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(EntityArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.entitiesArgument( + nodeName: String, + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = then(EntitiesArgument(nodeName, allowEmpty).setOptional(optional).apply(block)) + +inline fun CommandTree.entityTypeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(EntityTypeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.locationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(PositionArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.location2DArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(Position2DArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.blockPositionArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(BlockPositionArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.rotationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(RotationArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.angleArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(AngleArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.axisArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = then(AxisArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.resourceLocationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(ResourceLocationArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.timeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(TimeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.teamColorArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(TeamColorArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.particleArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(ParticleArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.gameModeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(GameModeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.commandArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(CommandArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.soundArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(SoundArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.potionEffectArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(PotionEffectArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.biomeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = then(BiomeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.enchantmentArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = then(EnchantmentArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.resourceArgument( + nodeName: String, + identifier: String, + registry: Registry, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = + then(ResourceArgument(nodeName, identifier, registry).setOptional(optional).apply(block)) + +inline fun CommandTree.instanceArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(InstanceArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.booleanArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(BooleanArgument(nodeName).setOptional(optional = optional).apply(block)) + +inline fun CommandTree.textArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(TextArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.greedyStringArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(GreedyStringArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.signedMessageArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(SignedMessageArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.longArgument( + nodeName: String, + min: Long = Long.MIN_VALUE, + max: Long = Long.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(LongArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun CommandTree.floatArgument( + nodeName: String, + min: Float = -Float.MAX_VALUE, + max: Float = Float.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(FloatArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun CommandTree.doubleArgument( + nodeName: String, + min: Double = -Double.MAX_VALUE, + max: Double = Double.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(DoubleArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun > CommandTree.enumArgument( + nodeName: String, + values: Collection, + noinline formatter: (E) -> String = { value -> value.name.lowercase() }, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(EnumArgument(nodeName, values, formatter).setOptional(optional).apply(block)) + +inline fun CommandTree.uuidArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(UUIDArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.integerRangeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(IntegerRangeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.floatRangeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): CommandTree = then(FloatRangeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun CommandTree.multiLiteralArgument( + nodeName: String, + vararg literals: String, + block: Argument.() -> Unit = {}, +): CommandTree = then(MultiLiteralArgument(nodeName, *literals).apply(block)) + +inline fun Argument.integerArgument( + nodeName: String, + min: Int = Int.MIN_VALUE, + max: Int = Int.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(IntegerArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun Argument.stringArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(StringArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.literalArgument( + nodeName: String, + literal: String = nodeName, + block: Argument.() -> Unit = {}, +): Argument = then(LiteralArgument(nodeName, literal).apply(block)) + +inline fun Argument.playerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(PlayerArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.playersArgument( + nodeName: String, + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument = then(PlayersArgument(nodeName, allowEmpty).setOptional(optional).apply(block)) + +inline fun Argument.entityArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(EntityArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.entitiesArgument( + nodeName: String, + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument = then(EntitiesArgument(nodeName, allowEmpty).setOptional(optional).apply(block)) + +inline fun Argument.entityTypeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(EntityTypeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.locationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(PositionArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.location2DArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(Position2DArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.blockPositionArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(BlockPositionArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.rotationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(RotationArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.angleArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(AngleArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.axisArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument = then(AxisArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.resourceLocationArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(ResourceLocationArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.timeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(TimeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.teamColorArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(TeamColorArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.particleArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(ParticleArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.gameModeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(GameModeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.commandArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(CommandArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.soundArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(SoundArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.potionEffectArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(PotionEffectArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.biomeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument = then(BiomeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.enchantmentArgument( + nodeName: String, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument = then(EnchantmentArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument

.resourceArgument( + nodeName: String, + identifier: String, + registry: Registry, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument

= + then(ResourceArgument(nodeName, identifier, registry).setOptional(optional).apply(block)) + +inline fun Argument.instanceArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(InstanceArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.booleanArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(BooleanArgument(nodeName).setOptional(optional = optional).apply(block)) + +inline fun Argument.textArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(TextArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.greedyStringArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(GreedyStringArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.signedMessageArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(SignedMessageArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.longArgument( + nodeName: String, + min: Long = Long.MIN_VALUE, + max: Long = Long.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(LongArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun Argument.floatArgument( + nodeName: String, + min: Float = -Float.MAX_VALUE, + max: Float = Float.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(FloatArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun Argument.doubleArgument( + nodeName: String, + min: Double = -Double.MAX_VALUE, + max: Double = Double.MAX_VALUE, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(DoubleArgument(nodeName, min, max).setOptional(optional).apply(block)) + +inline fun > Argument.enumArgument( + nodeName: String, + values: Collection, + noinline formatter: (E) -> String = { value -> value.name.lowercase() }, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(EnumArgument(nodeName, values, formatter).setOptional(optional).apply(block)) + +inline fun Argument.uuidArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(UUIDArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.integerRangeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(IntegerRangeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.floatRangeArgument( + nodeName: String, + optional: Boolean = false, + block: Argument.() -> Unit = {}, +): Argument = then(FloatRangeArgument(nodeName).setOptional(optional).apply(block)) + +inline fun Argument.multiLiteralArgument( + nodeName: String, + vararg literals: String, + block: Argument.() -> Unit = {}, +): Argument = then(MultiLiteralArgument(nodeName, *literals).apply(block)) + +inline fun CommandAPICommand.customArgument( + base: Argument, + noinline parser: (CustomArgumentInfo) -> T, + optional: Boolean? = null, + block: Argument.() -> Unit = {}, +): CommandAPICommand = withArguments( + CustomArgument(base, parser = parser).apply { + optional?.let { override -> + setOptional(false) + if (override) setOptional(true) + } + block() + }, +) + +inline fun CommandAPICommand.listArgument( + nodeName: String, + element: Argument, + delimiter: Char = ',', + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandAPICommand = withArguments( + ListArgument(nodeName, element, delimiter, allowEmpty).setOptional(optional).apply(block), +) + +inline fun CommandTree.customArgument( + base: Argument, + noinline parser: (CustomArgumentInfo) -> T, + optional: Boolean? = null, + block: Argument.() -> Unit = {}, +): CommandTree = then( + CustomArgument(base, parser = parser).apply { + optional?.let { override -> + setOptional(false) + if (override) setOptional(true) + } + block() + }, +) + +inline fun CommandTree.listArgument( + nodeName: String, + element: Argument, + delimiter: Char = ',', + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): CommandTree = then( + ListArgument(nodeName, element, delimiter, allowEmpty).setOptional(optional).apply(block), +) + +inline fun Argument

.customArgument( + base: Argument, + noinline parser: (CustomArgumentInfo) -> T, + optional: Boolean? = null, + block: Argument.() -> Unit = {}, +): Argument

= then( + CustomArgument(base, parser = parser).apply { + optional?.let { override -> + setOptional(false) + if (override) setOptional(true) + } + block() + }, +) + +inline fun Argument

.listArgument( + nodeName: String, + element: Argument, + delimiter: Char = ',', + allowEmpty: Boolean = false, + optional: Boolean = false, + block: Argument>.() -> Unit = {}, +): Argument

= then( + ListArgument(nodeName, element, delimiter, allowEmpty).setOptional(optional).apply(block), +) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/CommandDsl.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/CommandDsl.kt new file mode 100644 index 000000000..44953d5fc --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/CommandDsl.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.api.minestom.command.commandapi.dsl + +import dev.slne.surf.api.minestom.command.commandapi.CommandAPICommand +import dev.slne.surf.api.minestom.command.commandapi.CommandTree + +inline fun commandAPICommand( + name: String, + block: CommandAPICommand.() -> Unit = {}, +) = CommandAPICommand(name).apply(block).register() + +inline fun commandAPICommand( + name: String, + namespace: String, + block: CommandAPICommand.() -> Unit = {}, +) = CommandAPICommand(name).apply(block).register(namespace) + +inline fun commandTree( + name: String, + block: CommandTree.() -> Unit = {}, +) = CommandTree(name).apply(block).register() + +inline fun commandTree( + name: String, + namespace: String, + block: CommandTree.() -> Unit = {}, +) = CommandTree(name).apply(block).register(namespace) + +inline fun subcommand( + name: String, + block: CommandAPICommand.() -> Unit = {}, +) = CommandAPICommand(name).apply(block) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ExecutorDsl.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ExecutorDsl.kt new file mode 100644 index 000000000..19aa16b85 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/ExecutorDsl.kt @@ -0,0 +1,206 @@ +package dev.slne.surf.api.minestom.command.commandapi.dsl + +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandArguments +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandExecutable +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutionInfo +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutorDefinition +import dev.slne.surf.api.minestom.command.commandapi.executor.ExecutorType +import dev.slne.surf.api.minestom.coroutine.minestomAsyncScope +import kotlinx.coroutines.CoroutineScope +import net.minestom.server.command.CommandSender +import net.minestom.server.command.ConsoleSender +import net.minestom.server.entity.Player + +inline fun > SELF.anyExecutor( + crossinline executor: (CommandSender, CommandArguments) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.ANY) { info -> executor(info.sender, info.args) }, +) + +inline fun > SELF.playerExecutor( + crossinline executor: (Player, CommandArguments) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.PLAYER) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(player, info.args) + }, +) + +inline fun > SELF.consoleExecutor( + crossinline executor: (ConsoleSender, CommandArguments) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.CONSOLE) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(console, info.args) + }, +) + +inline fun > SELF.anyExecutionInfo( + crossinline executor: (ExecutionInfo) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.ANY) { info -> executor(info) }, +) + +inline fun > SELF.playerExecutionInfo( + crossinline executor: (ExecutionInfo) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.PLAYER) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(ExecutionInfo(player, info.args, info.input)) + }, +) + +inline fun > SELF.consoleExecutionInfo( + crossinline executor: (ExecutionInfo) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.CONSOLE) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(ExecutionInfo(console, info.args, info.input)) + }, +) + +inline fun > SELF.anyResultingExecutor( + crossinline executor: (CommandSender, CommandArguments) -> Int, +): SELF = addExecutor( + ExecutorDefinition.Resulting(ExecutorType.ANY) { info -> executor(info.sender, info.args) }, +) + +inline fun > SELF.playerResultingExecutor( + crossinline executor: (Player, CommandArguments) -> Int, +): SELF = addExecutor( + ExecutorDefinition.Resulting(ExecutorType.PLAYER) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(player, info.args) + }, +) + +inline fun > SELF.consoleResultingExecutor( + crossinline executor: (ConsoleSender, CommandArguments) -> Int, +): SELF = addExecutor( + ExecutorDefinition.Resulting(ExecutorType.CONSOLE) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(console, info.args) + }, +) + +inline fun > SELF.anyResultingExecutionInfo( + crossinline executor: (ExecutionInfo) -> Int, +): SELF = addExecutor( + ExecutorDefinition.Resulting(ExecutorType.ANY) { info -> executor(info) }, +) + +inline fun > SELF.playerResultingExecutionInfo( + crossinline executor: (ExecutionInfo) -> Int, +): SELF = addExecutor( + ExecutorDefinition.Resulting(ExecutorType.PLAYER) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(ExecutionInfo(player, info.args, info.input)) + }, +) + +inline fun > SELF.consoleResultingExecutionInfo( + crossinline executor: (ExecutionInfo) -> Int, +): SELF = addExecutor( + ExecutorDefinition.Resulting(ExecutorType.CONSOLE) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(ExecutionInfo(console, info.args, info.input)) + }, +) + +fun > SELF.anyExecutorSuspend( + scope: () -> CoroutineScope = { minestomAsyncScope }, + executor: suspend CoroutineScope.(CommandSender, CommandArguments) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Suspending(ExecutorType.ANY, scope) { info -> + executor(info.sender, info.args) + }, +) + +fun > SELF.anyExecutorSuspend( + scope: CoroutineScope, + executor: suspend CoroutineScope.(CommandSender, CommandArguments) -> Unit, +): SELF = anyExecutorSuspend(scope = { scope }, executor = executor) + +fun > SELF.playerExecutorSuspend( + scope: () -> CoroutineScope = { minestomAsyncScope }, + executor: suspend CoroutineScope.(Player, CommandArguments) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Suspending(ExecutorType.PLAYER, scope) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(player, info.args) + }, +) + +fun > SELF.playerExecutorSuspend( + scope: CoroutineScope, + executor: suspend CoroutineScope.(Player, CommandArguments) -> Unit, +): SELF = playerExecutorSuspend(scope = { scope }, executor = executor) + +fun > SELF.consoleExecutorSuspend( + scope: () -> CoroutineScope = { minestomAsyncScope }, + executor: suspend CoroutineScope.(ConsoleSender, CommandArguments) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Suspending(ExecutorType.CONSOLE, scope) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(console, info.args) + }, +) + +fun > SELF.consoleExecutorSuspend( + scope: CoroutineScope, + executor: suspend CoroutineScope.(ConsoleSender, CommandArguments) -> Unit, +): SELF = consoleExecutorSuspend(scope = { scope }, executor = executor) + +fun > SELF.anyExecutionInfoExecutorSuspend( + scope: () -> CoroutineScope = { minestomAsyncScope }, + executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Suspending(ExecutorType.ANY, scope) { info -> executor(info) }, +) + +fun > SELF.anyExecutionInfoExecutorSuspend( + scope: CoroutineScope, + executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, +): SELF = anyExecutionInfoExecutorSuspend(scope = { scope }, executor = executor) + +fun > SELF.playerExecutionInfoExecutorSuspend( + scope: () -> CoroutineScope = { minestomAsyncScope }, + executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Suspending(ExecutorType.PLAYER, scope) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(ExecutionInfo(player, info.args, info.input)) + }, +) + +fun > SELF.playerExecutionInfoExecutorSuspend( + scope: CoroutineScope, + executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, +): SELF = playerExecutionInfoExecutorSuspend(scope = { scope }, executor = executor) + +fun > SELF.consoleExecutionInfoExecutorSuspend( + scope: () -> CoroutineScope = { minestomAsyncScope }, + executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, +): SELF = addExecutor( + ExecutorDefinition.Suspending(ExecutorType.CONSOLE, scope) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(ExecutionInfo(console, info.args, info.input)) + }, +) + +fun > SELF.consoleExecutionInfoExecutorSuspend( + scope: CoroutineScope, + executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, +): SELF = consoleExecutionInfoExecutorSuspend(scope = { scope }, executor = executor) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/SuggestionDsl.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/SuggestionDsl.kt new file mode 100644 index 000000000..41dfa2560 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/dsl/SuggestionDsl.kt @@ -0,0 +1,119 @@ +package dev.slne.surf.api.minestom.command.commandapi.dsl + +import dev.slne.surf.api.minestom.command.commandapi.argument.Argument +import dev.slne.surf.api.minestom.command.commandapi.suggestion.ArgumentSuggestions +import dev.slne.surf.api.minestom.command.commandapi.suggestion.SafeSuggestions +import dev.slne.surf.api.minestom.command.commandapi.suggestion.StringTooltip +import dev.slne.surf.api.minestom.command.commandapi.suggestion.SuggestionInfo +import dev.slne.surf.api.minestom.command.commandapi.suggestion.SuggestionsBranch +import dev.slne.surf.api.minestom.command.commandapi.suggestion.Tooltip + +fun Argument.replaceSuggestions(vararg values: String): Argument = + replaceSuggestions(ArgumentSuggestions.strings(*values)) + +/** + * A bare lambda literal at this call site resolves to [Argument.replaceSuggestions] instead of + * this overload; pass an explicitly typed `(SuggestionInfo) -> Collection` value to + * select it. + */ +fun Argument.replaceSuggestions(provider: (SuggestionInfo) -> Collection): Argument = + replaceSuggestions(ArgumentSuggestions.strings(provider)) + +fun Argument.includeSuggestions(vararg values: String): Argument = + includeSuggestions(ArgumentSuggestions.strings(*values)) + +/** + * A bare lambda literal at this call site resolves to [Argument.includeSuggestions] instead of + * this overload; pass an explicitly typed `(SuggestionInfo) -> Collection` value to + * select it. + */ +fun Argument.includeSuggestions(provider: (SuggestionInfo) -> Collection): Argument = + includeSuggestions(ArgumentSuggestions.strings(provider)) + +fun Argument.replaceSuggestionsAsync( + provider: suspend (SuggestionInfo) -> Collection, +): Argument = replaceSuggestions(ArgumentSuggestions.stringsAsync(provider)) + +fun Argument.includeSuggestionsAsync( + provider: suspend (SuggestionInfo) -> Collection, +): Argument = includeSuggestions(ArgumentSuggestions.stringsAsync(provider)) + +fun Argument.replaceSuggestionsWithTooltips(vararg values: StringTooltip): Argument = + replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(*values)) + +fun Argument.replaceSuggestionsWithTooltips( + provider: (SuggestionInfo) -> Collection, +): Argument = replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(provider)) + +fun Argument.includeSuggestionsWithTooltips(vararg values: StringTooltip): Argument = + includeSuggestions(ArgumentSuggestions.stringsWithTooltips(*values)) + +fun Argument.includeSuggestionsWithTooltips( + provider: (SuggestionInfo) -> Collection, +): Argument = includeSuggestions(ArgumentSuggestions.stringsWithTooltips(provider)) + +fun Argument.replaceSuggestionsWithTooltipsAsync( + provider: suspend (SuggestionInfo) -> Collection, +): Argument = replaceSuggestions(ArgumentSuggestions.stringsWithTooltipsAsync(provider)) + +fun Argument.includeSuggestionsWithTooltipsAsync( + provider: suspend (SuggestionInfo) -> Collection, +): Argument = includeSuggestions(ArgumentSuggestions.stringsWithTooltipsAsync(provider)) + +fun Argument.replaceSafeSuggestions(vararg values: T): Argument = + replaceSafeSuggestions(SafeSuggestions.suggest(*values)) + +/** + * A bare lambda literal at this call site resolves to [Argument.replaceSafeSuggestions] instead + * of this overload; pass an explicitly typed `(SuggestionInfo) -> Collection` value to select + * it. + */ +fun Argument.replaceSafeSuggestions(provider: (SuggestionInfo) -> Collection): Argument = + replaceSafeSuggestions(SafeSuggestions.suggest(provider)) + +fun Argument.includeSafeSuggestions(vararg values: T): Argument = + includeSafeSuggestions(SafeSuggestions.suggest(*values)) + +/** + * A bare lambda literal at this call site resolves to [Argument.includeSafeSuggestions] instead + * of this overload; pass an explicitly typed `(SuggestionInfo) -> Collection` value to select + * it. + */ +fun Argument.includeSafeSuggestions(provider: (SuggestionInfo) -> Collection): Argument = + includeSafeSuggestions(SafeSuggestions.suggest(provider)) + +fun Argument.replaceSafeSuggestionsAsync( + provider: suspend (SuggestionInfo) -> Collection, +): Argument = replaceSafeSuggestions(SafeSuggestions.suggestAsync(provider)) + +fun Argument.includeSafeSuggestionsAsync( + provider: suspend (SuggestionInfo) -> Collection, +): Argument = includeSafeSuggestions(SafeSuggestions.suggestAsync(provider)) + +fun Argument.replaceSafeSuggestionsWithTooltips(vararg values: Tooltip): Argument = + replaceSafeSuggestions(SafeSuggestions.tooltips(*values)) + +fun Argument.replaceSafeSuggestionsWithTooltips( + provider: (SuggestionInfo) -> Collection>, +): Argument = replaceSafeSuggestions(SafeSuggestions.tooltips(provider)) + +fun Argument.includeSafeSuggestionsWithTooltips(vararg values: Tooltip): Argument = + includeSafeSuggestions(SafeSuggestions.tooltips(*values)) + +fun Argument.includeSafeSuggestionsWithTooltips( + provider: (SuggestionInfo) -> Collection>, +): Argument = includeSafeSuggestions(SafeSuggestions.tooltips(provider)) + +fun Argument.replaceSafeSuggestionsWithTooltipsAsync( + provider: suspend (SuggestionInfo) -> Collection>, +): Argument = replaceSafeSuggestions(SafeSuggestions.tooltipsAsync(provider)) + +fun Argument.includeSafeSuggestionsWithTooltipsAsync( + provider: suspend (SuggestionInfo) -> Collection>, +): Argument = includeSafeSuggestions(SafeSuggestions.tooltipsAsync(provider)) + +fun Argument.replaceSuggestions(branch: SuggestionsBranch): Argument = + replaceSuggestions(ArgumentSuggestions.branch(branch)) + +fun Argument.includeSuggestions(branch: SuggestionsBranch): Argument = + includeSuggestions(ArgumentSuggestions.branch(branch)) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException.kt new file mode 100644 index 000000000..53b7057f9 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandSyntaxException.kt @@ -0,0 +1,35 @@ +package dev.slne.surf.api.minestom.command.commandapi.exception + +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer +import java.io.Serial + +open class CommandSyntaxException( + val component: Component?, + val input: String? = null, + val cursor: Int? = null, + cause: Throwable? = null, +) : RuntimeException(component?.let { PlainTextComponentSerializer.plainText().serialize(it) }, cause) { + companion object { + @Serial + private const val serialVersionUID: Long = -540694787746386949L + } +} + +class WrapperCommandSyntaxException( + val exception: CommandSyntaxException, +) : RuntimeException(exception.message, exception) { + val component: Component? + get() = exception.component + + val input: String? + get() = exception.input + + val cursor: Int? + get() = exception.cursor + + companion object { + @Serial + private const val serialVersionUID: Long = -2695063468338553356L + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException.kt new file mode 100644 index 000000000..8deb07bd2 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/CommandValidationException.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.api.minestom.command.commandapi.exception + +import java.io.Serial + +/** + * Exception thrown to indicate that a command validation error has occurred. + * + * This exception is used to signal issues related to the validation + * of command inputs, parameters, or definitions within the Command API. + * + * @param message A detailed message describing the validation error. + */ +class CommandValidationException(message: String) : IllegalArgumentException(message) { + companion object { + @Serial + private const val serialVersionUID: Long = -7547371556844925457L + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/ComponentMessage.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/ComponentMessage.kt new file mode 100644 index 000000000..b470cb03d --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/exception/ComponentMessage.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.api.minestom.command.commandapi.exception + +import com.mojang.brigadier.Message +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer + +/** + * A Brigadier [Message] that keeps the component it was built from. + */ +class ComponentMessage(val component: Component) : Message { + override fun getString(): String = + PlainTextComponentSerializer.plainText().serialize(component) + + override fun toString(): String = string +} + +/** The component [Message] was built from, or `null` if it carries none. */ +fun Message.componentOrNull(): Component? = (this as? ComponentMessage)?.component diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments.kt new file mode 100644 index 000000000..0945a759e --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/CommandArguments.kt @@ -0,0 +1,90 @@ +package dev.slne.surf.api.minestom.command.commandapi.executor + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet +import org.jetbrains.annotations.ApiStatus +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + +data class ParsedArgument( + val name: String, + val value: Any?, + val raw: String?, + val present: Boolean, +) + +class CommandArguments private constructor( + private val ordered: List, +) { + private val named = Object2ObjectOpenHashMap(ordered.size).apply { + ordered.forEach { argument -> + put(argument.name, argument) + } + } + + inline fun get(name: String): T = typed(name, T::class, nullable = false) as T + + inline fun getOptional(name: String): T? = + typed(name, T::class, nullable = true) as T? + + fun getRaw(name: String): String? = named[name]?.raw + + fun getRaw(index: Int): String? = ordered.getOrNull(index)?.raw + + fun rawArguments(): List { + val rawArguments = ObjectArrayList(ordered.size) + + ordered.forEach { argument -> + if (argument.present) { + argument.raw?.let(rawArguments::add) + } + } + + return rawArguments + } + + operator fun get(index: Int): Any? = ordered[index].value + + operator fun contains(name: String): Boolean = named[name]?.present == true + + inline operator fun getValue(thisRef: Any?, property: KProperty<*>): T = + typed(property.name, T::class, nullable = null is T) as T + + @PublishedApi + internal fun typed(name: String, expected: KClass<*>, nullable: Boolean): Any? { + val argument = named[name] + ?: throw IllegalArgumentException("No argument named '$name' exists") + if (!argument.present && argument.value == null) { + if (nullable) return null + throw IllegalArgumentException("Required argument '$name' is absent") + } + val value = argument.value + if (value == null) { + if (nullable) return null + throw IllegalArgumentException("Argument '$name' is null but ${expected.qualifiedName} was required") + } + require(expected.isInstance(value)) { + "Argument '$name' expected ${expected.qualifiedName}, got ${value::class.qualifiedName}" + } + return value + } + + companion object { + @ApiStatus.Internal + fun of(arguments: List): CommandArguments { + val copy = ObjectArrayList(arguments) + val names = ObjectOpenHashSet(copy.size) + + copy.forEach { argument -> + require(names.add(argument.name)) { + "Parsed argument names must be unique" + } + } + + return CommandArguments(copy) + } + + fun empty(): CommandArguments = CommandArguments(emptyList()) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/Executors.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/Executors.kt new file mode 100644 index 000000000..912afd7c2 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/Executors.kt @@ -0,0 +1,64 @@ +package dev.slne.surf.api.minestom.command.commandapi.executor + +import kotlinx.coroutines.CoroutineScope +import net.minestom.server.command.CommandSender +import net.minestom.server.command.ConsoleSender +import net.minestom.server.entity.Player +import org.jetbrains.annotations.ApiStatus + +enum class ExecutorType { + ANY, + PLAYER, + CONSOLE, +} + +data class ExecutionInfo( + val sender: S, + val args: CommandArguments, + val input: String, +) + +sealed interface ExecutorDefinition { + val type: ExecutorType + + data class Normal( + override val type: ExecutorType, + val executor: (ExecutionInfo) -> Unit, + ) : ExecutorDefinition + + data class Resulting( + override val type: ExecutorType, + val executor: (ExecutionInfo) -> Int, + ) : ExecutorDefinition + + data class Suspending( + override val type: ExecutorType, + val scopeProvider: () -> CoroutineScope, + val executor: suspend CoroutineScope.(ExecutionInfo) -> Unit, + ) : ExecutorDefinition +} + +interface CommandExecutable> { + @ApiStatus.Internal + fun addExecutor(definition: ExecutorDefinition): SELF + + fun executes(executor: (CommandSender, CommandArguments) -> Unit): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.ANY) { info -> executor(info.sender, info.args) }, + ) + + fun executesPlayer(executor: (Player, CommandArguments) -> Unit): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.PLAYER) { info -> + val player = info.sender + check(player is Player) { "PLAYER executor received ${player::class.qualifiedName}" } + executor(player, info.args) + }, + ) + + fun executesConsole(executor: (ConsoleSender, CommandArguments) -> Unit): SELF = addExecutor( + ExecutorDefinition.Normal(ExecutorType.CONSOLE) { info -> + val console = info.sender + check(console is ConsoleSender) { "CONSOLE executor received ${console::class.qualifiedName}" } + executor(console, info.args) + }, + ) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/SuspendExecutors.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/SuspendExecutors.kt new file mode 100644 index 000000000..88ae32432 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/executor/SuspendExecutors.kt @@ -0,0 +1,88 @@ +package dev.slne.surf.api.minestom.command.commandapi.executor + +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandSyntaxException +import dev.slne.surf.api.minestom.command.commandapi.exception.WrapperCommandSyntaxException +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor +import net.minestom.server.MinecraftServer +import net.minestom.server.command.CommandSender +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +val GENERIC_COMMAND_FAILURE: Component = Component.text( + "Beim Ausführen des Befehls ist ein Fehler aufgetreten.", + NamedTextColor.RED, +) + +@ApiStatus.Internal +fun launchCommandExecutor( + definition: ExecutorDefinition.Suspending, + sender: CommandSender, + arguments: CommandArguments, + input: String, +): Job = definition.scopeProvider().launch { + try { + definition.executor(this, ExecutionInfo(sender, arguments, input)) + } catch (failure: Throwable) { + handleCommandFailure(sender, input, failure) + } +} + +internal fun handleCommandFailure( + sender: CommandSender, + input: String, + failure: Throwable, + knownFailure: (Throwable) -> Component? = { null }, + unexpectedFailure: Component = GENERIC_COMMAND_FAILURE, + syntaxFailurePolicy: SyntaxFailurePolicy = SyntaxFailurePolicy.RENDER, +) { + if (failure is CancellationException) throw failure + + val knownMessage = knownFailure(failure) + if (knownMessage != null) { + sender.sendMessage(knownMessage) + return + } + + when { + syntaxFailurePolicy == SyntaxFailurePolicy.USE_UNEXPECTED_FAILURE -> sendUnexpectedFailure( + sender, + input, + failure, + unexpectedFailure, + ) + failure is WrapperCommandSyntaxException -> sendSyntaxFailure(sender, failure.exception) + failure is CommandSyntaxException -> sendSyntaxFailure(sender, failure) + else -> sendUnexpectedFailure(sender, input, failure, unexpectedFailure) + } +} + +@ApiStatus.Internal +fun handleCommandExecutorFailure( + sender: CommandSender, + input: String, + failure: Throwable, +) = handleCommandFailure(sender, input, failure) + +internal enum class SyntaxFailurePolicy { + RENDER, + USE_UNEXPECTED_FAILURE, +} + +private fun sendUnexpectedFailure( + sender: CommandSender, + input: String, + failure: Throwable, + component: Component, +) { + MinecraftServer.LOGGER.error("Failed to execute command '{}' for {}", input, sender, failure) + sender.sendMessage(component) +} + +private fun sendSyntaxFailure(sender: CommandSender, failure: CommandSyntaxException) { + val component = failure.component ?: throw failure + sender.sendMessage(component) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform.kt new file mode 100644 index 000000000..4101b2fc7 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/internal/CommandAPIPlatform.kt @@ -0,0 +1,15 @@ +package dev.slne.surf.api.minestom.command.commandapi.internal + +import dev.slne.surf.api.minestom.command.commandapi.CommandDefinition +import dev.slne.surf.api.minestom.command.commandapi.RegisteredCommand +import net.minestom.server.command.CommandSender +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +interface CommandAPIPlatform { + fun register(definition: CommandDefinition, namespace: String?): RegisteredCommand + + fun unregister(name: String): Boolean + + fun execute(sender: CommandSender, input: String): Int +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions.kt new file mode 100644 index 000000000..3701e0355 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/ArgumentSuggestions.kt @@ -0,0 +1,108 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.suggestion + +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectImmutableList +import it.unimi.dsi.fastutil.objects.ObjectList +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope + +fun interface ArgumentSuggestions { + suspend fun suggest(info: SuggestionInfo): List + + val filterPolicy: SuggestionFilter + get() = SuggestionFilter.PREFIX + + companion object { + fun empty(): ArgumentSuggestions = ArgumentSuggestions { emptyList() } + + fun strings(vararg values: String): ArgumentSuggestions = strings(ObjectList.of(*values)) + + fun strings(values: Collection): ArgumentSuggestions { + val copy = ObjectImmutableList(values) + return ArgumentSuggestions { + copy.mapTo(ObjectArrayList(copy.size), ::withoutTooltip) + } + } + + fun strings(provider: (SuggestionInfo) -> Collection): ArgumentSuggestions { + return ArgumentSuggestions { info -> + val provided = provider(info) + provided.mapTo(ObjectArrayList(provided.size), ::withoutTooltip) + } + } + + fun stringCollection(provider: (SuggestionInfo) -> Collection): ArgumentSuggestions { + return strings(provider) + } + + fun stringsAsync(provider: suspend (SuggestionInfo) -> Collection): ArgumentSuggestions { + return ArgumentSuggestions { info -> + val provided = provider(info) + provided.mapTo(ObjectArrayList(provided.size), ::withoutTooltip) + } + } + + fun stringCollectionAsync(provider: suspend (SuggestionInfo) -> Collection): ArgumentSuggestions = + stringsAsync(provider) + + fun stringsWithTooltips(vararg values: StringTooltip): ArgumentSuggestions = + stringsWithTooltips(ObjectList.of(*values)) + + fun stringsWithTooltips(values: Collection): ArgumentSuggestions { + val copy = ObjectImmutableList(values) + return ArgumentSuggestions { copy } + } + + fun stringsWithTooltips(provider: (SuggestionInfo) -> Collection): ArgumentSuggestions { + return ArgumentSuggestions { info -> ObjectImmutableList(provider(info)) } + } + + fun stringsWithTooltipsCollection(provider: (SuggestionInfo) -> Collection): ArgumentSuggestions = + stringsWithTooltips(provider) + + fun stringsWithTooltipsAsync(provider: suspend (SuggestionInfo) -> Collection): ArgumentSuggestions { + return ArgumentSuggestions { info -> ObjectImmutableList(provider(info)) } + } + + fun stringsWithTooltipsCollectionAsync(provider: suspend (SuggestionInfo) -> Collection): ArgumentSuggestions = + stringsWithTooltipsAsync(provider) + + fun unfiltered(provider: suspend (SuggestionInfo) -> Collection): ArgumentSuggestions { + return object : ArgumentSuggestions { + override val filterPolicy = SuggestionFilter.NONE + + override suspend fun suggest(info: SuggestionInfo): List { + return ObjectImmutableList(provider(info)) + } + } + } + + fun merge(vararg providers: ArgumentSuggestions): ArgumentSuggestions { + val copy = ObjectImmutableList(providers) + return ArgumentSuggestions { info -> + coroutineScope { + copy.mapTo(ObjectArrayList(copy.size)) { provider -> + async { provider.suggest(info) } + } + .awaitAll() + .flatten() + } + } + } + + fun branch(branch: SuggestionsBranch): ArgumentSuggestions = ArgumentSuggestions { info -> + branch.getNextSuggestion(info.sender, *info.previousArgs.rawArguments().toTypedArray()) + ?.suggest(info) + ?.let(::ObjectImmutableList) + .orEmpty() + } + + private fun withoutTooltip(value: String) = StringTooltip(value, null) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions.kt new file mode 100644 index 000000000..feb5d9ec4 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SafeSuggestions.kt @@ -0,0 +1,70 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.suggestion + +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectImmutableList +import it.unimi.dsi.fastutil.objects.ObjectList + +fun interface SafeSuggestions { + suspend fun suggest(info: SuggestionInfo): List> + + companion object { + fun empty(): SafeSuggestions = SafeSuggestions { emptyList() } + + fun suggest(vararg values: T): SafeSuggestions = suggest(ObjectList.of(*values)) + + fun suggest(values: Collection): SafeSuggestions { + val copy = ObjectImmutableList(values) + return SafeSuggestions { + copy.mapTo(ObjectArrayList(copy.size), ::withoutTooltip) + } + } + + fun suggest(provider: (SuggestionInfo) -> Collection): SafeSuggestions { + return SafeSuggestions { info -> + val provided = provider(info) + provided.mapTo(ObjectArrayList(provided.size), ::withoutTooltip) + } + } + + fun suggestCollection(provider: (SuggestionInfo) -> Collection): SafeSuggestions = + suggest(provider) + + fun suggestAsync(provider: suspend (SuggestionInfo) -> Collection): SafeSuggestions { + return SafeSuggestions { info -> + val provided = provider(info) + provided.mapTo(ObjectArrayList(provided.size), ::withoutTooltip) + } + } + + fun suggestCollectionAsync(provider: suspend (SuggestionInfo) -> Collection): SafeSuggestions = + suggestAsync(provider) + + fun tooltips(vararg values: Tooltip): SafeSuggestions = + tooltips(ObjectList.of(*values)) + + fun tooltips(values: Collection>): SafeSuggestions { + val copy = ObjectImmutableList(values) + return SafeSuggestions { copy } + } + + fun tooltips(provider: (SuggestionInfo) -> Collection>): SafeSuggestions { + return SafeSuggestions { info -> ObjectImmutableList(provider(info)) } + } + + fun tooltipCollection(provider: (SuggestionInfo) -> Collection>): SafeSuggestions = + tooltips(provider) + + fun tooltipsAsync(provider: suspend (SuggestionInfo) -> Collection>): SafeSuggestions = + SafeSuggestions { info -> ObjectImmutableList(provider(info)) } + + fun tooltipCollectionAsync(provider: suspend (SuggestionInfo) -> Collection>): SafeSuggestions = + tooltipsAsync(provider) + + private fun withoutTooltip(value: T) = Tooltip(value, null) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch.kt new file mode 100644 index 000000000..679258ee2 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/SuggestionsBranch.kt @@ -0,0 +1,177 @@ +/* + * Substantially translated from CommandAPI 12.0.0 (https://github.com/CommandAPI/CommandAPI). + * MIT License, Copyright (c) 2020 - 2022 Jorel Ali. + * The complete license is distributed in META-INF/LICENSES/CommandAPI-LICENSE.txt. + */ +package dev.slne.surf.api.minestom.command.commandapi.suggestion + +import dev.slne.surf.api.minestom.command.commandapi.exception.CommandSyntaxException +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandArguments +import dev.slne.surf.api.minestom.command.commandapi.executor.ParsedArgument +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import it.unimi.dsi.fastutil.objects.ObjectImmutableList +import it.unimi.dsi.fastutil.objects.ObjectList +import net.kyori.adventure.text.Component +import net.minestom.server.command.CommandSender + +class SuggestionsBranch private constructor( + suggestions: List, +) { + private val suggestions = ObjectImmutableList(suggestions) + private val branches = ObjectArrayList() + + fun branch(vararg branches: SuggestionsBranch): SuggestionsBranch = apply { + this.branches += branches + } + + suspend fun getNextSuggestion( + sender: CommandSender, + vararg previousRaw: String, + ): ArgumentSuggestions? = traverse( + mode = TraversalMode.NEXT, + sender = sender, + rawArguments = ObjectList.of(*previousRaw), + processed = emptyList(), + ).provider + + suspend fun enforceReplacements( + sender: CommandSender, + vararg previousRaw: String, + ) { + traverse( + mode = TraversalMode.ENFORCE, + sender = sender, + rawArguments = ObjectList.of(*previousRaw), + processed = emptyList(), + ) + } + + private suspend fun traverse( + mode: TraversalMode, + sender: CommandSender, + rawArguments: List, + processed: List, + ): TraversalResult { + if (suggestions.isEmpty && branches.isEmpty) { + return TraversalResult(null) + } + + val currentProcessed = ObjectArrayList(processed) + for (provider in suggestions) { + if (currentProcessed.size == rawArguments.size) { + if (mode == TraversalMode.NEXT) { + return TraversalResult(provider) + } + + if (provider == null) { + return TraversalResult(null) + } + + val missingInfo = suggestionInfo(sender, currentProcessed, "") + if (provider.suggest(missingInfo).isNotEmpty()) { + throw syntax("Expected more arguments", rawArguments, currentProcessed) + } + + return TraversalResult(null) + } + + val candidate = rawArguments[currentProcessed.size] + if (provider != null) { + val info = suggestionInfo(sender, currentProcessed, "") + if (provider.suggest(info).none { it.suggestion == candidate }) { + val message = + if (currentProcessed.isEmpty) "Unknown command" else "Unknown argument" + throw syntax(message, rawArguments, currentProcessed) + } + } + + currentProcessed += candidate + } + + if (branches.isEmpty) { + return TraversalResult(null) + } + + val successes = ObjectArrayList() + val failures = ObjectArrayList() + + for (branch in branches) { + try { + successes += branch.traverse(mode, sender, rawArguments, currentProcessed) + } catch (exception: CommandSyntaxException) { + failures += exception + } + } + + if (successes.isEmpty) { + throw failures.maxByOrNull { it.cursor ?: -1 } + ?: syntax("Unknown argument", rawArguments, currentProcessed) + } + + if (mode == TraversalMode.ENFORCE) { + return TraversalResult(null) + } + + if (successes.size == 1) { + return successes.single() + } + + val providers = successes.mapTo(ObjectArrayList(successes.size), TraversalResult::provider) + + if (providers.all { it == null }) { + return TraversalResult(null) + } + + if (providers.any { it == null }) { + throw syntax( + "Multiple paths for a SuggestionsBranch must either be all null or all non-null", + rawArguments, + currentProcessed, + ) + } + + return TraversalResult(ArgumentSuggestions.merge(*providers.filterNotNull().toTypedArray())) + } + + private fun suggestionInfo( + sender: CommandSender, + processed: List, + currentArgument: String, + ): SuggestionInfo { + val parsed = processed.mapIndexedTo(ObjectArrayList(processed.size)) { index, raw -> + ParsedArgument(index.toString(), raw, raw, present = true) + } + + return SuggestionInfo( + sender = sender, + previousArgs = CommandArguments.of(parsed), + currentInput = processed.joinToString( + " ", + postfix = if (processed.isEmpty()) "" else " " + ), + currentArg = currentArgument, + ) + } + + private fun syntax( + message: String, + rawArguments: List, + processed: List, + ) = CommandSyntaxException( + component = Component.text(message), + input = rawArguments.joinToString(" "), + cursor = processed.joinToString(" ").length + if (processed.isEmpty()) 0 else 1, + ) + + private data class TraversalResult(val provider: ArgumentSuggestions?) + + private enum class TraversalMode { + NEXT, + ENFORCE, + } + + companion object { + fun suggest(vararg suggestions: ArgumentSuggestions?): SuggestionsBranch = + SuggestionsBranch(ObjectList.of(*suggestions)) + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip.kt new file mode 100644 index 000000000..4f1fca30e --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/command/commandapi/suggestion/Tooltip.kt @@ -0,0 +1,32 @@ +package dev.slne.surf.api.minestom.command.commandapi.suggestion + +import dev.slne.surf.api.minestom.command.commandapi.executor.CommandArguments +import net.kyori.adventure.text.Component +import net.minestom.server.command.CommandSender + +data class Tooltip( + val suggestion: T, + val tooltip: Component?, +) + +data class StringTooltip( + val suggestion: String, + val tooltip: Component?, +) { + companion object { + fun ofString(suggestion: String, tooltip: Component? = null) = + StringTooltip(suggestion, tooltip) + } +} + +data class SuggestionInfo( + val sender: CommandSender, + val previousArgs: CommandArguments, + val currentInput: String, + val currentArg: String, +) + +enum class SuggestionFilter { + PREFIX, + NONE, +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomDispatchers.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomDispatchers.kt new file mode 100644 index 000000000..95389a1a8 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomDispatchers.kt @@ -0,0 +1,65 @@ +package dev.slne.surf.api.minestom.coroutine + +import dev.slne.surf.api.minestom.extension.SchedulerManager +import kotlinx.coroutines.* +import net.minestom.server.timer.Task +import net.minestom.server.timer.TaskSchedule +import java.lang.Runnable +import java.util.concurrent.Executors +import kotlin.coroutines.CoroutineContext + +object MinestomDispatchers { + + val Blocking: CoroutineDispatcher = Executors.newThreadPerTaskExecutor( + Thread.ofVirtual().name("surf-blocking-", 0).factory() + ).asCoroutineDispatcher() + + @OptIn(InternalCoroutinesApi::class, ExperimentalCoroutinesApi::class) + val Main: CoroutineDispatcher = object : CoroutineDispatcher(), Delay { + override fun dispatch(context: CoroutineContext, block: Runnable) { + SchedulerManager.scheduleNextTick(block) + } + + override fun scheduleResumeAfterDelay( + timeMillis: Long, + continuation: CancellableContinuation + ) { + val task = schedule(timeMillis) { + with(continuation) { + resumeUndispatched(Unit) + } + } + + continuation.invokeOnCancellation { + task.cancel() + } + } + + override fun invokeOnTimeout( + timeMillis: Long, + block: Runnable, + context: CoroutineContext + ): DisposableHandle { + val task = schedule(timeMillis, block) + + return DisposableHandle { + task.cancel() + } + } + + private fun schedule(timeMillis: Long, block: Runnable): Task { + val delay = when { + timeMillis <= 0L -> TaskSchedule.immediate() + else -> TaskSchedule.millis(timeMillis) + } + + return SchedulerManager.scheduleTask( + block, + delay, + TaskSchedule.stop() + ) + } + + override fun toString(): String = "MinestomDispatchers.Main" + } +} \ No newline at end of file diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomScopeProvider.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomScopeProvider.kt new file mode 100644 index 000000000..0a8045676 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/coroutine/MinestomScopeProvider.kt @@ -0,0 +1,30 @@ +package dev.slne.surf.api.minestom.coroutine + +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.plus +import net.minestom.server.MinecraftServer + +internal object MinestomScopeProvider { + + val scope: CoroutineScope + val asyncScope: CoroutineScope + val blockingScope: CoroutineScope + + init { + val exceptionHandler = CoroutineExceptionHandler { context, throwable -> + MinecraftServer.LOGGER.error("Coroutine exception in context: $context", throwable) + } + val rootScope = CoroutineScope(exceptionHandler) + + scope = rootScope + SupervisorJob() + MinestomDispatchers.Main + asyncScope = rootScope + SupervisorJob() + Dispatchers.Default + blockingScope = rootScope + SupervisorJob() + MinestomDispatchers.Blocking + } +} + +val minestomScope get() = MinestomScopeProvider.scope +val minestomAsyncScope get() = MinestomScopeProvider.asyncScope +val minestomBlockingScope get() = MinestomScopeProvider.blockingScope diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/dialog/callback/DialogCallbackListener.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/dialog/callback/DialogCallbackListener.kt index c45f0c051..bfc9658f9 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/dialog/callback/DialogCallbackListener.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/dialog/callback/DialogCallbackListener.kt @@ -1,8 +1,8 @@ package dev.slne.surf.api.minestom.dialog.callback import com.google.inject.Singleton -import dev.slne.minestom.lobby.api.event.EventRegistrar -import dev.slne.minestom.lobby.api.extension.addListener +import dev.slne.surf.api.minestom.event.EventRegistrar +import dev.slne.surf.api.minestom.extension.addListener import net.minestom.server.event.Event import net.minestom.server.event.EventNode import net.minestom.server.event.player.PlayerCustomClickEvent diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/EventRegistrar.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/EventRegistrar.kt new file mode 100644 index 000000000..829475007 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/EventRegistrar.kt @@ -0,0 +1,25 @@ +package dev.slne.surf.api.minestom.event + +import net.minestom.server.event.Event +import net.minestom.server.event.EventNode + +/** + * Contributes listeners to the server's own event node. + * + * ``` + * class WelcomeListener : EventRegistrar { + * override fun register(node: EventNode) { + * node.addListener { it.player.sendMessage("Welcome!") } + * } + * } + * + * // in a module: + * binder().bindEventRegistrar() + * ``` + * + * @see dev.slne.surf.api.minestom.command.CommandRegistrar for the command equivalent + */ +fun interface EventRegistrar { + + fun register(node: EventNode) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/SuspendingEventNode.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/SuspendingEventNode.kt new file mode 100644 index 000000000..0b92656da --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/event/SuspendingEventNode.kt @@ -0,0 +1,54 @@ +package dev.slne.surf.api.minestom.event + +import net.kyori.adventure.text.logger.slf4j.ComponentLogger +import org.jetbrains.annotations.ApiStatus +import kotlin.coroutines.cancellation.CancellationException + +class SuspendingEventNode(private val name: String) { + + companion object { + private val LOGGER = ComponentLogger.logger() + } + + private val lock = Any() + + @Volatile + private var listeners: List> = emptyList() + + + fun addListener(priority: Int = 0, listener: suspend (E) -> Unit): Registration { + val registration = Registration(this, priority, listener) + + synchronized(lock) { + listeners = (listeners + registration).sortedBy { it.priority } + } + + return registration + } + + + @ApiStatus.Internal + suspend fun call(event: E) { + for (registration in listeners) { + try { + registration.listener(event) + } catch (cancellation: CancellationException) { + throw cancellation + } catch (failure: Throwable) { + LOGGER.error("Listener for '{}' failed, continuing with the next one", name, failure) + } + } + } + + class Registration internal constructor( + private val node: SuspendingEventNode, + internal val priority: Int, + internal val listener: suspend (E) -> Unit + ) : AutoCloseable { + override fun close() { + synchronized(node.lock) { + node.listeners -= this + } + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/events.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/events.kt new file mode 100644 index 000000000..febc80157 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/events.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.api.minestom.extension + +import net.minestom.server.event.Event +import net.minestom.server.event.EventListener +import net.minestom.server.event.EventNode + +inline fun EventNode.addListener( + noinline listener: (T) -> Unit +) { + addListener(EventListener.of(T::class.java, listener)) +} \ No newline at end of file diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/server.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/server.kt new file mode 100644 index 000000000..eb6396b5d --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/extension/server.kt @@ -0,0 +1,96 @@ +package dev.slne.surf.api.minestom.extension + +import net.minestom.server.MinecraftServer +import net.minestom.server.MinecraftServer.enchantmentEntityEffects +import net.minestom.server.MinecraftServer.enchantmentLevelBasedValues +import net.minestom.server.MinecraftServer.enchantmentLocationEffects +import net.minestom.server.MinecraftServer.enchantmentValueEffects +import net.minestom.server.MinecraftServer.getAdvancementManager +import net.minestom.server.MinecraftServer.getBannerPatternRegistry +import net.minestom.server.MinecraftServer.getBiomeRegistry +import net.minestom.server.MinecraftServer.getBlockManager +import net.minestom.server.MinecraftServer.getBossBarManager +import net.minestom.server.MinecraftServer.getChatTypeRegistry +import net.minestom.server.MinecraftServer.getCommandManager +import net.minestom.server.MinecraftServer.getConnectionManager +import net.minestom.server.MinecraftServer.getDamageTypeRegistry +import net.minestom.server.MinecraftServer.getDimensionTypeRegistry +import net.minestom.server.MinecraftServer.getEnchantmentRegistry +import net.minestom.server.MinecraftServer.getExceptionManager +import net.minestom.server.MinecraftServer.getGlobalEventHandler +import net.minestom.server.MinecraftServer.getInstanceManager +import net.minestom.server.MinecraftServer.getInstrumentRegistry +import net.minestom.server.MinecraftServer.getJukeboxSongRegistry +import net.minestom.server.MinecraftServer.getPacketListenerManager +import net.minestom.server.MinecraftServer.getPacketParser +import net.minestom.server.MinecraftServer.getPaintingVariantRegistry +import net.minestom.server.MinecraftServer.getRecipeManager +import net.minestom.server.MinecraftServer.getSchedulerManager +import net.minestom.server.MinecraftServer.getTeamManager +import net.minestom.server.MinecraftServer.getTrimMaterialRegistry +import net.minestom.server.MinecraftServer.getTrimPatternRegistry +import net.minestom.server.MinecraftServer.getWolfVariantRegistry +import net.minestom.server.advancements.AdvancementManager +import net.minestom.server.adventure.bossbar.BossBarManager +import net.minestom.server.codec.StructCodec +import net.minestom.server.command.CommandManager +import net.minestom.server.entity.damage.DamageType +import net.minestom.server.entity.metadata.animal.tameable.WolfVariant +import net.minestom.server.entity.metadata.other.PaintingVariant +import net.minestom.server.event.GlobalEventHandler +import net.minestom.server.exception.ExceptionManager +import net.minestom.server.instance.InstanceManager +import net.minestom.server.instance.block.BlockManager +import net.minestom.server.instance.block.banner.BannerPattern +import net.minestom.server.instance.block.jukebox.JukeboxSong +import net.minestom.server.item.armor.TrimMaterial +import net.minestom.server.item.armor.TrimPattern +import net.minestom.server.item.enchant.Enchantment +import net.minestom.server.item.enchant.EntityEffect +import net.minestom.server.item.enchant.LevelBasedValue +import net.minestom.server.item.enchant.LocationEffect +import net.minestom.server.item.enchant.ValueEffect +import net.minestom.server.item.instrument.Instrument +import net.minestom.server.listener.manager.PacketListenerManager +import net.minestom.server.message.ChatType +import net.minestom.server.network.ConnectionManager +import net.minestom.server.network.packet.PacketParser +import net.minestom.server.network.packet.client.ClientPacket +import net.minestom.server.recipe.RecipeManager +import net.minestom.server.registry.DynamicRegistry +import net.minestom.server.scoreboard.TeamManager +import net.minestom.server.timer.SchedulerManager +import net.minestom.server.world.DimensionType +import net.minestom.server.world.biome.Biome + +val server get() = MinecraftServer.process() ?: error("Server is not initialized yet. Please make sure to call this after the server has started.") + +inline val GlobalEventHandler: GlobalEventHandler get() = getGlobalEventHandler() +inline val PacketListenerManager: PacketListenerManager get() = getPacketListenerManager() +inline val InstanceManager: InstanceManager get() = getInstanceManager() +inline val BlockManager: BlockManager get() = getBlockManager() +inline val CommandManager: CommandManager get() = getCommandManager() +inline val RecipeManager: RecipeManager get() = getRecipeManager() +inline val TeamManager: TeamManager get() = getTeamManager() +inline val SchedulerManager: SchedulerManager get() = getSchedulerManager() +inline val ExceptionManager: ExceptionManager get() = getExceptionManager() +inline val ConnectionManager: ConnectionManager get() = getConnectionManager() +inline val BossBarManager: BossBarManager get() = getBossBarManager() +inline val PacketParser: PacketParser get() = getPacketParser() +inline val AdvancementManager: AdvancementManager get() = getAdvancementManager() +inline val ChatTypeRegistry: DynamicRegistry get() = getChatTypeRegistry() +inline val DimensionTypeRegistry: DynamicRegistry get() = getDimensionTypeRegistry() +inline val BiomeRegistry: DynamicRegistry get() = getBiomeRegistry() +inline val DamageTypeRegistry: DynamicRegistry get() = getDamageTypeRegistry() +inline val TrimMaterialRegistry: DynamicRegistry get() = getTrimMaterialRegistry() +inline val TrimPatternRegistry: DynamicRegistry get() = getTrimPatternRegistry() +inline val BannerPatternRegistry: DynamicRegistry get() = getBannerPatternRegistry() +inline val WolfVariantRegistry: DynamicRegistry get() = getWolfVariantRegistry() +inline val EnchantmentRegistry: DynamicRegistry get() = getEnchantmentRegistry() +inline val PaintingVariantRegistry: DynamicRegistry get() = getPaintingVariantRegistry() +inline val JukeboxSongRegistry: DynamicRegistry get() = getJukeboxSongRegistry() +inline val InstrumentRegistry: DynamicRegistry get() = getInstrumentRegistry() +inline val EnchantmentLevelBasedValues: DynamicRegistry> get() = enchantmentLevelBasedValues() +inline val EnchantmentValueEffects: DynamicRegistry> get() = enchantmentValueEffects() +inline val EnchantmentEntityEffects: DynamicRegistry> get() = enchantmentEntityEffects() +inline val EnchantmentLocationEffects: DynamicRegistry> get() = enchantmentLocationEffects() \ No newline at end of file diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader.kt index 4d2240e5f..65bbe53a4 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/impl/inventory/framework/MinestomInventoryLoader.kt @@ -1,8 +1,8 @@ package dev.slne.surf.api.minestom.impl.inventory.framework import com.google.inject.Singleton -import dev.slne.minestom.lobby.api.event.EventRegistrar -import dev.slne.minestom.lobby.api.extension.addListener +import dev.slne.surf.api.minestom.event.EventRegistrar +import dev.slne.surf.api.minestom.extension.addListener import dev.slne.surf.api.minestom.inventory.framework.view.ViewNavigationHistory import me.devnatan.inventoryframework.ViewFrame import net.minestom.server.event.Event diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt new file mode 100644 index 000000000..48cb400c7 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt @@ -0,0 +1,71 @@ +package dev.slne.surf.api.minestom.player + +import dev.slne.surf.api.minestom.chat.RemoteChatSender +import dev.slne.surf.api.minestom.chat.RemoteSignedMessage +import net.kyori.adventure.chat.SignedMessage +import net.kyori.adventure.text.Component +import net.minestom.server.crypto.ChatSession +import net.minestom.server.entity.Player +import net.minestom.server.network.player.GameProfile +import net.minestom.server.network.player.PlayerConnection +import org.jetbrains.annotations.ApiStatus + +abstract class SurfPlayer @ApiStatus.Internal protected constructor( + playerConnection: PlayerConnection, + gameProfile: GameProfile, +) : Player(playerConnection, gameProfile) { + + abstract fun hasPermission(permission: String): Boolean + + /** + * Sends [message] to this player with its signature intact, attributed to [boundName]. + * + * [unsignedContent] replaces what is displayed without + * touching what was signed. Passing `null` + * shows the signed content as it was sent. + * + * A message that carries no signature of this server's own is sent as plain system text. + */ + abstract fun sendSignedMessage( + message: SignedMessage, + boundName: Component, + unsignedContent: Component?, + ) + + /** + * Captures [message] so that it can be shown to a player on another server. + * + * [unsignedContent] replaces what is displayed there without touching what was signed. + * + * Returns `null` for a message this server did not receive from a client, which therefore + * carries nothing another server could hand to a client. + */ + abstract fun captureSignedMessage( + message: SignedMessage, + unsignedContent: Component?, + ): RemoteSignedMessage? + + /** + * The chat session this player currently signs their messages under, or `null` while they have + * none. + */ + abstract fun chatSession(): ChatSession? + + /** + * Shows [message] to this player as coming from [sender], a player on another server. + * + * [sender] is announced to this player's client for as long as it takes to deliver the message, + * so that the signature can be verified without the sender ever being on this server. + * + * @see captureSignedMessage + */ + abstract fun sendRemoteSignedMessage( + sender: RemoteChatSender, + message: RemoteSignedMessage, + boundName: Component, + ) + + fun displayName(): Component = (displayName ?: Component.text(username)) + .insertion(username) + .hoverEvent(this) +} \ No newline at end of file diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt new file mode 100644 index 000000000..8a1fd2822 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt @@ -0,0 +1,50 @@ +@file:Suppress("UNCHECKED_CAST") + +package dev.slne.surf.api.minestom.player + +import net.minestom.server.network.ConnectionManager +import net.minestom.server.network.player.PlayerConnection +import java.util.* + +/** + * @see ConnectionManager.getOnlinePlayers + */ +val ConnectionManager.onlineSurfPlayers: Collection + get() = onlinePlayers as Collection + +/** + * @see ConnectionManager.getConfigPlayers + */ +val ConnectionManager.configSurfPlayers: Collection + get() = configPlayers as Collection + +/** + * @see ConnectionManager.getPlayer + */ +fun ConnectionManager.getSurfPlayer( + connection: PlayerConnection, +): SurfPlayer? = getPlayer(connection) as? SurfPlayer + +/** + * @see ConnectionManager.getOnlinePlayerByUsername + */ +fun ConnectionManager.getOnlineSurfPlayerByUsername( + username: String, +): SurfPlayer? = getOnlinePlayerByUsername(username) as? SurfPlayer + +/** + * @see ConnectionManager.getOnlinePlayerByUuid + */ +fun ConnectionManager.getOnlineSurfPlayerByUuid( + uuid: UUID, +): SurfPlayer? = getOnlinePlayerByUuid(uuid) as? SurfPlayer + +fun ConnectionManager.getSurfPlayer(uuid: UUID): SurfPlayer? = getOnlineSurfPlayerByUuid(uuid) + +/** + * @see ConnectionManager.findOnlinePlayer + */ +fun ConnectionManager.findOnlineSurfPlayer( + username: String, +): SurfPlayer? = findOnlinePlayer(username) as? SurfPlayer + diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt new file mode 100644 index 000000000..d9d7eb4ac --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.api.minestom.player + +import net.minestom.server.entity.Player +import net.minestom.server.event.trait.PlayerEvent +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +@OptIn(ExperimentalContracts::class) +fun Player.requireSurfPlayer(): SurfPlayer { + contract { + returns() implies (this@requireSurfPlayer is SurfPlayer) + } + + require(this is SurfPlayer) { "Player ${this.username} is not a SurfPlayer" } + return this +} + +val PlayerEvent.surfPlayer get() = player.requireSurfPlayer() \ No newline at end of file diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPlugin.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPlugin.kt new file mode 100644 index 000000000..1190d5a1e --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPlugin.kt @@ -0,0 +1,104 @@ +package dev.slne.surf.api.minestom.plugin + +import com.google.inject.AbstractModule +import dev.slne.surf.api.minestom.command.CommandRegistrar +import dev.slne.surf.api.minestom.event.EventRegistrar +import dev.slne.surf.api.minestom.plugin.annotation.DataDirectory +import dev.slne.surf.api.minestom.plugin.annotation.MinestomPluginMeta +import org.jetbrains.annotations.ApiStatus + +/** + * A plugin as the server sees it: a Guice module plus the entrypoint that starts it. + * + * Plugins are discovered through `ServiceLoader`, so a subclass needs a + * `META-INF/services/dev.slne.surf.api.minestom.plugin.MinestomPlugin` entry, a + * [MinestomPluginMeta] annotation for its id and dependencies, and a no-argument constructor. + * + * Each plugin is wired into its own private section of the server's injector. Everything the server + * binds stays injectable and keeps sharing the server's instances - services, the server's worlds, + * Minestom's own types. What the plugin binds is its own: two plugins may bind the same key without + * colliding, and each one gets its own [DataDirectory] path. + */ +abstract class MinestomPlugin( + val entrypoint: Class +) : AbstractModule() { + val meta = MinestomPluginMeta.get(javaClass) + + private val declaredEventRegistrars = linkedSetOf>() + private val declaredCommandRegistrars = linkedSetOf>() + + @get:ApiStatus.Internal + val eventRegistrars: Set> + get() = declaredEventRegistrars + + @get:ApiStatus.Internal + val commandRegistrars: Set> + get() = declaredCommandRegistrars + + init { + MinestomPluginMeta.validate(meta) + } + + final override fun configure() { + bind(entrypoint) + + configurePlugin() + } + + /** + * Register the plugin's Guice bindings here. + * + * ``` + * override fun configurePlugin() { + * bind(MyService::class.java).asEagerSingleton() + * bindEventRegistrar() + * bindCommandRegistrar() + * } + * ``` + * + * This method must not start services, open connections or register + * listeners. Side effects belong in the entrypoint's start method. + * + * The entrypoint is already bound when this runs, so binding it again is an error. + */ + protected open fun configurePlugin() = Unit + + /** + * Registers [registrar] as an [EventRegistrar], so the server hands it its event node during + * startup. + */ + protected fun bindEventRegistrar(registrar: Class) { + bind(registrar) + declaredEventRegistrars += registrar + } + + /** + * Registers [T] as an [EventRegistrar], so the server hands it its event node during startup. + * + * ``` + * bindEventRegistrar() + * ``` + */ + protected inline fun bindEventRegistrar() = + bindEventRegistrar(T::class.java) + + /** + * Registers [registrar] as a [CommandRegistrar], so the server asks it to register its + * commands during startup. + */ + protected fun bindCommandRegistrar(registrar: Class) { + bind(registrar) + declaredCommandRegistrars += registrar + } + + /** + * Registers [T] as a [CommandRegistrar], so the server asks it to register its commands during + * startup. + * + * ``` + * bindCommandRegistrar() + * ``` + */ + protected inline fun bindCommandRegistrar() = + bindCommandRegistrar(T::class.java) +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint.kt new file mode 100644 index 000000000..538ab0181 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/MinestomPluginEntrypoint.kt @@ -0,0 +1,9 @@ +package dev.slne.surf.api.minestom.plugin + +interface MinestomPluginEntrypoint { + suspend fun start() + + suspend fun afterStart() = Unit + + suspend fun stop() = Unit +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/DataDirectory.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/DataDirectory.kt new file mode 100644 index 000000000..d1d3dfa3d --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/DataDirectory.kt @@ -0,0 +1,29 @@ +package dev.slne.surf.api.minestom.plugin.annotation + +import com.google.inject.BindingAnnotation + +/** + * The plugin's own data directory, `plugins/`. + * + * The server creates the directory while it wires the plugin, so it already exists by the time + * anything is injected. + * + * ``` + * class MyStorage @Inject constructor( + * @DataDirectory private val dataDirectory: Path, + * ) { + * private val file = dataDirectory.resolve("storage.yml") + * } + * ``` + * + * @see dev.slne.surf.api.minestom.plugin.MinestomPlugin + */ +@BindingAnnotation +@Retention(AnnotationRetention.RUNTIME) +@Target( + AnnotationTarget.FIELD, + AnnotationTarget.VALUE_PARAMETER, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, +) +annotation class DataDirectory diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta.kt new file mode 100644 index 000000000..5a81eafe8 --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/plugin/annotation/MinestomPluginMeta.kt @@ -0,0 +1,43 @@ +package dev.slne.surf.api.minestom.plugin.annotation + +import dev.slne.surf.api.minestom.plugin.MinestomPlugin +import org.intellij.lang.annotations.Pattern + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +annotation class MinestomPluginMeta( + @MinestomPluginIdPattern + val id: String, + val dependsOn: Array<@MinestomPluginIdPattern String> = [] +) { + + companion object { + private const val ID_PATTERN_STRING = "[a-z0-9][a-z0-9._-]*" + + @Pattern(ID_PATTERN_STRING) + @Retention(AnnotationRetention.BINARY) + @Target(AnnotationTarget.TYPE, AnnotationTarget.VALUE_PARAMETER) + annotation class MinestomPluginIdPattern + + val ID_PATTERN = Regex(ID_PATTERN_STRING) + + internal fun get(clazz: Class): MinestomPluginMeta { + val annotation = clazz.getDeclaredAnnotation(MinestomPluginMeta::class.java) + requireNotNull(annotation) { + "Class ${clazz.name} is not annotated with @MinestomPluginMeta" + } + return annotation + } + + internal fun validate(meta: MinestomPluginMeta) { + require(ID_PATTERN.matches(meta.id)) { + "Invalid Minestom plugin id '${meta.id}'. " + + "Expected lowercase characters, digits, '.', '_' or '-'." + } + + require(meta.id !in meta.dependsOn) { + "Minestom plugin '${meta.id}' must not depend on itself" + } + } + } +} diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/util/uuid-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/util/uuid-ext.kt new file mode 100644 index 000000000..b438820ed --- /dev/null +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/util/uuid-ext.kt @@ -0,0 +1,9 @@ +package dev.slne.surf.api.minestom.util + +import com.google.common.primitives.Longs +import java.util.* + +val NIL_UUID: UUID = UUID(0L, 0L) + +fun UUID.toByteArray(): ByteArray = + Longs.toByteArray(mostSignificantBits) + Longs.toByteArray(leastSignificantBits) diff --git a/surf-api-minestom/src/test/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCacheTest.kt b/surf-api-minestom/src/test/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCacheTest.kt new file mode 100644 index 000000000..09c81ad35 --- /dev/null +++ b/surf-api-minestom/src/test/kotlin/dev/slne/surf/api/minestom/chat/signature/MessageSignatureCacheTest.kt @@ -0,0 +1,107 @@ +package dev.slne.surf.api.minestom.chat.signature + +import net.minestom.server.crypto.MessageSignature +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import java.time.Instant + +class MessageSignatureCacheTest { + + private fun signature(seed: Int): MessageSignature = + MessageSignature(ByteArray(SIGNATURE_LENGTH) { index -> (seed + index).toByte() }) + + private fun bodyWith(lastSeen: List) = SignedMessageBody( + content = "content", + timeStamp = Instant.EPOCH, + salt = 0L, + lastSeen = LastSeenMessages(lastSeen), + ) + + @Test + fun `an unknown signature is not found`() { + val cache = MessageSignatureCache(4) + + assertEquals(MessageSignatureCache.NOT_FOUND, cache.pack(signature(1))) + } + + @Test + fun `a pushed signature is packed to the index it was stored at`() { + val cache = MessageSignatureCache(4) + val pushed = signature(1) + + cache.push(bodyWith(emptyList()), pushed) + + assertEquals(0, cache.pack(pushed)) + assertEquals(pushed, cache.unpack(0)) + } + + @Test + fun `an equal signature from a different array packs to the same index`() { + val cache = MessageSignatureCache(4) + + cache.push(bodyWith(emptyList()), signature(7)) + + assertEquals(0, cache.pack(signature(7))) + } + + @Test + fun `the newest signature takes the first slot and shifts the previous one down`() { + val cache = MessageSignatureCache(4) + val first = signature(1) + val second = signature(2) + + cache.push(bodyWith(emptyList()), first) + cache.push(bodyWith(emptyList()), second) + + assertEquals(0, cache.pack(second)) + assertEquals(1, cache.pack(first)) + } + + @Test + fun `last seen entries are pushed before the message signature`() { + val cache = MessageSignatureCache(8) + val seenFirst = signature(1) + val seenSecond = signature(2) + val own = signature(3) + + cache.push(bodyWith(listOf(seenFirst, seenSecond)), own) + + // push() drains the queue from the back, so the message's own signature lands first. + assertEquals(0, cache.pack(own)) + assertEquals(1, cache.pack(seenSecond)) + assertEquals(2, cache.pack(seenFirst)) + } + + @Test + fun `re-pushing an entry keeps it in the cache exactly once`() { + val cache = MessageSignatureCache(4) + val repeated = signature(1) + val other = signature(2) + + cache.push(bodyWith(emptyList()), repeated) + cache.push(bodyWith(emptyList()), other) + cache.push(bodyWith(emptyList()), repeated) + + assertEquals(0, cache.pack(repeated)) + assertEquals(1, cache.pack(other)) + assertNull(cache.unpack(2)) + } + + @Test + fun `entries beyond the capacity are dropped`() { + val cache = MessageSignatureCache(2) + + cache.push(bodyWith(emptyList()), signature(1)) + cache.push(bodyWith(emptyList()), signature(2)) + cache.push(bodyWith(emptyList()), signature(3)) + + assertEquals(0, cache.pack(signature(3))) + assertEquals(1, cache.pack(signature(2))) + assertEquals(MessageSignatureCache.NOT_FOUND, cache.pack(signature(1))) + } + + private companion object { + const val SIGNATURE_LENGTH = 256 + } +} From b5c743717db81e8d2901efc39b2f6b03900742a6 Mon Sep 17 00:00:00 2001 From: TheBjoRedCraft Date: Fri, 4 Sep 2026 15:52:10 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20feat(player):=20rename=20SurfPl?= =?UTF-8?q?ayer=20to=20SurfMinestomPlayer=20and=20update=20references?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rename SurfPlayer class to SurfMinestomPlayer for clarity - update all references to SurfPlayer in AsyncChatEvent, ConnectionManager, and player extensions - ensure compatibility with existing functionality while improving code readability --- surf-api-minestom/build.gradle.kts | 2 +- .../surf/api/minestom/chat/AsyncChatEvent.kt | 6 +++--- .../api/minestom/chat/RemoteSignedMessage.kt | 6 +++--- .../{SurfPlayer.kt => SurfMinestomPlayer.kt} | 2 +- .../minestom/player/connection-manager-ext.kt | 19 ++++++++++--------- .../surf/api/minestom/player/player-ext.kt | 6 +++--- 6 files changed, 21 insertions(+), 20 deletions(-) rename surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/{SurfPlayer.kt => SurfMinestomPlayer.kt} (96%) diff --git a/surf-api-minestom/build.gradle.kts b/surf-api-minestom/build.gradle.kts index 4aace0813..b753506f1 100644 --- a/surf-api-minestom/build.gradle.kts +++ b/surf-api-minestom/build.gradle.kts @@ -13,7 +13,7 @@ dependencies { compileOnlyApi(libs.minestom) compileOnlyApi(libs.mojang.brigadier) - compileOnly(libs.guice) + compileOnlyApi(libs.guice) api(libs.guava) api(libs.dazzleconf) diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt index 7433f44c4..fded7e292 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/AsyncChatEvent.kt @@ -1,14 +1,14 @@ package dev.slne.surf.api.minestom.chat import dev.slne.surf.api.minestom.event.SuspendingEventNode -import dev.slne.surf.api.minestom.player.SurfPlayer +import dev.slne.surf.api.minestom.player.SurfMinestomPlayer import net.kyori.adventure.audience.Audience import net.kyori.adventure.chat.SignedMessage import net.kyori.adventure.text.Component import org.jetbrains.annotations.ApiStatus /** - * Fired when a [SurfPlayer] sends a chat message. + * Fired when a [SurfMinestomPlayer] sends a chat message. * * Listeners run off the tick thread on * a virtual thread, so they may suspend *and* they may block @@ -28,7 +28,7 @@ import org.jetbrains.annotations.ApiStatus */ class AsyncChatEvent @ApiStatus.Internal constructor( - val player: SurfPlayer, + val player: SurfMinestomPlayer, /** * The [Audience]s that this chat message will be displayed to. diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt index 4cb0bdfa6..a41a33f61 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/chat/RemoteSignedMessage.kt @@ -3,7 +3,7 @@ package dev.slne.surf.api.minestom.chat import net.kyori.adventure.text.Component import net.minestom.server.crypto.MessageSignature import java.time.Instant -import java.util.UUID +import java.util.* /** * A signed chat message in a form that survives leaving this server. @@ -12,8 +12,8 @@ import java.util.UUID * sender can still show the message as signed. A message from a sender without a chat session has no * [signature], a nil [sessionId] and is shown as unsigned. * - * @see dev.slne.surf.api.minestom.player.SurfPlayer.captureSignedMessage - * @see dev.slne.surf.api.minestom.player.SurfPlayer.sendRemoteSignedMessage + * @see dev.slne.surf.api.minestom.player.SurfMinestomPlayer.captureSignedMessage + * @see dev.slne.surf.api.minestom.player.SurfMinestomPlayer.sendRemoteSignedMessage */ data class RemoteSignedMessage( val sender: UUID, diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfMinestomPlayer.kt similarity index 96% rename from surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt rename to surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfMinestomPlayer.kt index 48cb400c7..9a2a0d5ef 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfPlayer.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/SurfMinestomPlayer.kt @@ -10,7 +10,7 @@ import net.minestom.server.network.player.GameProfile import net.minestom.server.network.player.PlayerConnection import org.jetbrains.annotations.ApiStatus -abstract class SurfPlayer @ApiStatus.Internal protected constructor( +abstract class SurfMinestomPlayer @ApiStatus.Internal protected constructor( playerConnection: PlayerConnection, gameProfile: GameProfile, ) : Player(playerConnection, gameProfile) { diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt index 8a1fd2822..0d3e03031 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/connection-manager-ext.kt @@ -9,42 +9,43 @@ import java.util.* /** * @see ConnectionManager.getOnlinePlayers */ -val ConnectionManager.onlineSurfPlayers: Collection - get() = onlinePlayers as Collection +val ConnectionManager.onlineSurfMinestomPlayers: Collection + get() = onlinePlayers as Collection /** * @see ConnectionManager.getConfigPlayers */ -val ConnectionManager.configSurfPlayers: Collection - get() = configPlayers as Collection +val ConnectionManager.configSurfMinestomPlayers: Collection + get() = configPlayers as Collection /** * @see ConnectionManager.getPlayer */ fun ConnectionManager.getSurfPlayer( connection: PlayerConnection, -): SurfPlayer? = getPlayer(connection) as? SurfPlayer +): SurfMinestomPlayer? = getPlayer(connection) as? SurfMinestomPlayer /** * @see ConnectionManager.getOnlinePlayerByUsername */ fun ConnectionManager.getOnlineSurfPlayerByUsername( username: String, -): SurfPlayer? = getOnlinePlayerByUsername(username) as? SurfPlayer +): SurfMinestomPlayer? = getOnlinePlayerByUsername(username) as? SurfMinestomPlayer /** * @see ConnectionManager.getOnlinePlayerByUuid */ fun ConnectionManager.getOnlineSurfPlayerByUuid( uuid: UUID, -): SurfPlayer? = getOnlinePlayerByUuid(uuid) as? SurfPlayer +): SurfMinestomPlayer? = getOnlinePlayerByUuid(uuid) as? SurfMinestomPlayer -fun ConnectionManager.getSurfPlayer(uuid: UUID): SurfPlayer? = getOnlineSurfPlayerByUuid(uuid) +fun ConnectionManager.getSurfPlayer(uuid: UUID): SurfMinestomPlayer? = + getOnlineSurfPlayerByUuid(uuid) /** * @see ConnectionManager.findOnlinePlayer */ fun ConnectionManager.findOnlineSurfPlayer( username: String, -): SurfPlayer? = findOnlinePlayer(username) as? SurfPlayer +): SurfMinestomPlayer? = findOnlinePlayer(username) as? SurfMinestomPlayer diff --git a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt index d9d7eb4ac..4345b99a1 100644 --- a/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt +++ b/surf-api-minestom/src/main/kotlin/dev/slne/surf/api/minestom/player/player-ext.kt @@ -6,12 +6,12 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @OptIn(ExperimentalContracts::class) -fun Player.requireSurfPlayer(): SurfPlayer { +fun Player.requireSurfPlayer(): SurfMinestomPlayer { contract { - returns() implies (this@requireSurfPlayer is SurfPlayer) + returns() implies (this@requireSurfPlayer is SurfMinestomPlayer) } - require(this is SurfPlayer) { "Player ${this.username} is not a SurfPlayer" } + require(this is SurfMinestomPlayer) { "Player ${this.username} is not a SurfPlayer" } return this }