From 8d6e0fef90fb94c08989f1d1cddc21a3d6669190 Mon Sep 17 00:00:00 2001
From: Skullian <133133667+Skullians@users.noreply.github.com>
Date: Sun, 3 May 2026 18:45:43 +0100
Subject: [PATCH 1/3] feat(minestom): add ItemStackParser
---
.../minestom/MinestomCommandManager.java | 4 +-
.../minestom/caption/MinestomCaptionKeys.java | 5 +
.../MinestomDefaultCaptionsProvider.java | 6 +
.../cloud/minestom/data/ProtoItemStack.java | 67 +++++++++
.../cloud/minestom/data/package-info.java | 4 +
.../minestom/parser/ItemStackParser.java | 139 ++++++++++++++++++
6 files changed, 224 insertions(+), 1 deletion(-)
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/ProtoItemStack.java
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/package-info.java
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
index ba968eff..61decdab 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
@@ -40,6 +40,7 @@
import org.incendo.cloud.minestom.parser.EntityTypeParser;
import org.incendo.cloud.minestom.parser.GameModeParser;
import org.incendo.cloud.minestom.parser.InstanceParser;
+import org.incendo.cloud.minestom.parser.ItemStackParser;
import org.incendo.cloud.minestom.parser.PlayerParser;
import org.incendo.cloud.minestom.parser.location.PosParser;
import org.incendo.cloud.minestom.parser.location.VecParser;
@@ -82,7 +83,8 @@ public MinestomCommandManager(
.registerParser(GameModeParser.gameModeParser())
.registerParser(DimensionTypeParser.dimensionTypeParser())
.registerParser(PosParser.posParser())
- .registerParser(VecParser.vecParser());
+ .registerParser(VecParser.vecParser())
+ .registerParser(ItemStackParser.itemStackParser());
this.captionRegistry().registerProvider(new MinestomDefaultCaptionsProvider<>());
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
index 48558016..4a8f706f 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
@@ -72,6 +72,11 @@ public final class MinestomCaptionKeys {
*/
public static final Caption ARGUMENT_PARSE_FAILURE_POS = of("argument.parse.failure.pos");
+ /**
+ * Variables: {@code }
+ */
+ public static final Caption ARGUMENT_PARSE_FAILURE_ITEM_STACK = of("argument.parse.failure.item_stack");
+
private MinestomCaptionKeys() {
}
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java
index 973b8b2d..bc7f8993 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java
@@ -69,6 +69,11 @@ public final class MinestomDefaultCaptionsProvider extends DelegatingCaptionP
*/
public static final String ARGUMENT_PARSE_FAILURE_POS = "'' is not a valid pos (expected: x y z, optionally with yaw and pitch)";
+ /**
+ * Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_ITEM_STACK}
+ */
+ public static final String ARGUMENT_PARSE_FAILURE_ITEM_STACK = "'' is not a valid item";
+
private static final CaptionProvider> PROVIDER = CaptionProvider.constantProvider()
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER, ARGUMENT_PARSE_FAILURE_PLAYER)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ENTITY_TYPE, ARGUMENT_PARSE_FAILURE_ENTITY_TYPE)
@@ -77,6 +82,7 @@ public final class MinestomDefaultCaptionsProvider extends DelegatingCaptionP
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE, ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_VEC, ARGUMENT_PARSE_FAILURE_VEC)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_POS, ARGUMENT_PARSE_FAILURE_POS)
+ .putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ITEM_STACK, ARGUMENT_PARSE_FAILURE_ITEM_STACK)
.build();
@SuppressWarnings("unchecked")
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/ProtoItemStack.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/ProtoItemStack.java
new file mode 100644
index 00000000..266f5475
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/ProtoItemStack.java
@@ -0,0 +1,67 @@
+//
+// MIT License
+//
+// Copyright (c) 2024 Incendo
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+package org.incendo.cloud.minestom.data;
+
+import net.minestom.server.item.ItemStack;
+import net.minestom.server.item.Material;
+import org.apiguardian.api.API;
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+/**
+ * Intermediary result for an argument which parses a {@link net.minestom.server.item.Material} and optional NBT data.
+ *
+ * @since 2.1.0
+ */
+@API(status = API.Status.STABLE, since = "2.0.0")
+public final class ProtoItemStack {
+
+ private final Material material;
+
+ /**
+ * Creates a new proto item stack.
+ *
+ * @param material the material
+ */
+ public ProtoItemStack(final @NonNull Material material) {
+ this.material = material;
+ }
+
+ /**
+ * Creates an {@link ItemStack} from this proto item stack with the given amount.
+ *
+ * @param amount the stack size
+ * @return the created item stack
+ * @throws IllegalArgumentException if the amount exceeds the material's max stack size
+ */
+ public @NonNull ItemStack createItemStack(final int amount) {
+ if (amount > this.material.maxStackSize()) {
+ throw new IllegalArgumentException(String.format(
+ "The maximum stack size for %s is %d",
+ this.material.name(),
+ this.material.maxStackSize()
+ ));
+ }
+ return ItemStack.of(this.material, amount);
+ }
+}
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/package-info.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/package-info.java
new file mode 100644
index 00000000..6c1624f0
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/data/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * cloud-minestom data holders
+ */
+package org.incendo.cloud.minestom.data;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java
new file mode 100644
index 00000000..4c1846ed
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java
@@ -0,0 +1,139 @@
+//
+// MIT License
+//
+// Copyright (c) 2024 Incendo
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+package org.incendo.cloud.minestom.parser;
+
+import java.util.stream.Collectors;
+import net.kyori.adventure.key.Key;
+import net.minestom.server.item.Material;
+import org.apiguardian.api.API;
+import org.incendo.cloud.caption.CaptionVariable;
+import org.incendo.cloud.component.CommandComponent;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.context.CommandInput;
+import org.incendo.cloud.exception.parsing.ParserException;
+import org.incendo.cloud.minestom.caption.MinestomCaptionKeys;
+import org.incendo.cloud.minestom.data.ProtoItemStack;
+import org.incendo.cloud.parser.ArgumentParseResult;
+import org.incendo.cloud.parser.ArgumentParser;
+import org.incendo.cloud.parser.ParserDescriptor;
+import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
+import org.jspecify.annotations.NonNull;
+
+/**
+ * Parser for {@link ProtoItemStack}.
+ *
+ * @param command sender type
+ */
+public final class ItemStackParser implements ArgumentParser, BlockingSuggestionProvider.Strings {
+
+ /**
+ * Creates a new item stack parser.
+ *
+ * @param command sender type
+ * @return the created parser
+ * @since 2.0.0
+ */
+ @API(status = API.Status.STABLE, since = "2.0.0")
+ public static @NonNull ParserDescriptor itemStackParser() {
+ return ParserDescriptor.of(new ItemStackParser<>(), ProtoItemStack.class);
+ }
+
+ /**
+ * Returns a {@link CommandComponent.Builder} using {@link #itemStackParser()} as the parser.
+ *
+ * @param the command sender type
+ * @return the component builder
+ * @since 2.0.0
+ */
+ @API(status = API.Status.STABLE, since = "2.0.0")
+ public static CommandComponent.@NonNull Builder itemStackComponent() {
+ return CommandComponent.builder().parser(itemStackParser());
+ }
+
+ @Override
+ public @NonNull ArgumentParseResult<@NonNull ProtoItemStack> parse(
+ final @NonNull CommandContext<@NonNull C> commandContext,
+ final @NonNull CommandInput commandInput
+ ) {
+ final String input = commandInput.readString();
+ final Key key;
+ try {
+ key = Key.key(input);
+ } catch (final Exception e) {
+ return ArgumentParseResult.failure(new ItemStackParseException(input, commandContext));
+ }
+
+ final Material material = Material.fromKey(key);
+ if (material == null) {
+ return ArgumentParseResult.failure(new ItemStackParseException(input, commandContext));
+ }
+ return ArgumentParseResult.success(new ProtoItemStack(material));
+ }
+
+ @Override
+ public @NonNull Iterable<@NonNull String> stringSuggestions(
+ final @NonNull CommandContext commandContext,
+ final @NonNull CommandInput input
+ ) {
+ return Material.values().stream()
+ .map(m -> m.key().value())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Exception thrown when an item stack cannot be parsed from the input provided.
+ */
+ public static final class ItemStackParseException extends ParserException {
+
+ private final String input;
+
+ /**
+ * Create a new item stack parse exception.
+ *
+ * @param input string input
+ * @param context command context
+ */
+ public ItemStackParseException(
+ final @NonNull String input,
+ final @NonNull CommandContext> context
+ ) {
+ super(
+ ItemStackParser.class,
+ context,
+ MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ITEM_STACK,
+ CaptionVariable.of("input", input)
+ );
+ this.input = input;
+ }
+
+ /**
+ * Returns the supplied input.
+ *
+ * @return input value
+ */
+ public @NonNull String input() {
+ return this.input;
+ }
+ }
+}
From d3d3e97e32ab956c795f83588223448e21dbd7b9 Mon Sep 17 00:00:00 2001
From: Skullian <133133667+Skullians@users.noreply.github.com>
Date: Mon, 4 May 2026 01:27:34 +0100
Subject: [PATCH 2/3] feat: add some more parsers
---
README.md | 23 +--
.../minestom/MinestomCommandManager.java | 12 +-
.../minestom/caption/MinestomCaptionKeys.java | 20 ++-
.../MinestomDefaultCaptionsProvider.java | 24 ++-
.../minestom/parser/EnchantmentParser.java | 138 ++++++++++++++++++
...eModeParser.java => SoundEventParser.java} | 52 +++----
.../parser/attribute/AttributeParser.java | 132 +++++++++++++++++
.../parser/attribute/package-info.java | 4 +
.../parser/{ => item}/ItemStackParser.java | 2 +-
.../minestom/parser/item/package-info.java | 4 +
.../parser/location/package-info.java | 2 +-
.../cloud/minestom/parser/package-info.java | 2 +-
12 files changed, 362 insertions(+), 53 deletions(-)
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/EnchantmentParser.java
rename cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/{GameModeParser.java => SoundEventParser.java} (67%)
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/AttributeParser.java
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/package-info.java
rename cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/{ => item}/ItemStackParser.java (99%)
create mode 100644 cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/package-info.java
diff --git a/README.md b/README.md
index a305bacc..99a263a3 100644
--- a/README.md
+++ b/README.md
@@ -51,15 +51,20 @@ As of right now there's only two built-in parsers that I bothered to add.
## Included parsers
-| Parser | Type | Description |
-|-----------------------|-----------------|-----------------------------------------------------------------------------------------------------|
-| `PlayerParser` | `Player` | Resolves an online player by username |
-| `EntityTypeParser` | `EntityType` | Resolves an entity type by namespaced key |
-| `InstanceParser` | `Instance` | Resolves a loaded instance by UUID |
-| `GameModeParser` | `GameMode` | Resolves a game mode by name |
-| `DimensionTypeParser` | `DimensionType` | Resolves a dimension type by namespaced key |
-| `VecParser` | `Vec` | Resolves a `Vec` from `x y z` (supports relative coordinates (`~ ~ ~`) |
-| `PosParser` | `Pos` | Resolves a `Pos` from `x y z`, (+ optional pitch/yaw - also supports relative coords (`~ ~ ~ ~ ~`)) |
+You'll see a decent amount of random parsers that I've added after needing them lol
+
+| Parser | Type | Description |
+|----------------------------|----------------------------|-----------------------------------------------------------------------------------------------------|
+| `PlayerParser` | `Player` | Resolves an online player by username |
+| `EntityTypeParser` | `EntityType` | Resolves an entity type by namespaced key |
+| `InstanceParser` | `Instance` | Resolves a loaded instance by UUID |
+| `DimensionTypeParser` | `DimensionType` | Resolves a dimension type by namespaced key |
+| `VecParser` | `Vec` | Resolves a `Vec` from `x y z` (supports relative coordinates (`~ ~ ~`) |
+| `PosParser` | `Pos` | Resolves a `Pos` from `x y z`, (+ optional pitch/yaw - also supports relative coords (`~ ~ ~ ~ ~`)) |
+| `ItemStackParser` | `ItemStack` | Resolves an `ItemStack` from `id:meta:count` |
+| `EnchantmentParser` | `RegistryKey` | Resolves an enchantment registry key by namespaced key |
+| `SoundEventParser` | `SoundEvent` | Resolves a builtin sound event by namespaced key |
+| `AttributeParser` | `Attribute` | Resolves an entity attribute by namespaced key |
## links
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
index 61decdab..84cf3e58 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
@@ -37,11 +37,13 @@
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.minestom.caption.MinestomDefaultCaptionsProvider;
import org.incendo.cloud.minestom.parser.DimensionTypeParser;
+import org.incendo.cloud.minestom.parser.EnchantmentParser;
import org.incendo.cloud.minestom.parser.EntityTypeParser;
-import org.incendo.cloud.minestom.parser.GameModeParser;
import org.incendo.cloud.minestom.parser.InstanceParser;
-import org.incendo.cloud.minestom.parser.ItemStackParser;
import org.incendo.cloud.minestom.parser.PlayerParser;
+import org.incendo.cloud.minestom.parser.SoundEventParser;
+import org.incendo.cloud.minestom.parser.attribute.AttributeParser;
+import org.incendo.cloud.minestom.parser.item.ItemStackParser;
import org.incendo.cloud.minestom.parser.location.PosParser;
import org.incendo.cloud.minestom.parser.location.VecParser;
@@ -80,11 +82,13 @@ public MinestomCommandManager(
.registerParser(PlayerParser.playerParser())
.registerParser(EntityTypeParser.entityTypeParser())
.registerParser(InstanceParser.instanceParser())
- .registerParser(GameModeParser.gameModeParser())
.registerParser(DimensionTypeParser.dimensionTypeParser())
.registerParser(PosParser.posParser())
.registerParser(VecParser.vecParser())
- .registerParser(ItemStackParser.itemStackParser());
+ .registerParser(ItemStackParser.itemStackParser())
+ .registerParser(EnchantmentParser.enchantmentParser())
+ .registerParser(SoundEventParser.soundEventParser())
+ .registerParser(AttributeParser.attributeParser());
this.captionRegistry().registerProvider(new MinestomDefaultCaptionsProvider<>());
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
index 4a8f706f..5e83df27 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
@@ -52,11 +52,6 @@ public final class MinestomCaptionKeys {
*/
public static final Caption ARGUMENT_PARSE_FAILURE_INSTANCE = of("argument.parse.failure.instance");
- /**
- * Variables: {@code }
- */
- public static final Caption ARGUMENT_PARSE_FAILURE_GAME_MODE = of("argument.parse.failure.game_mode");
-
/**
* Variables: {@code }
*/
@@ -77,6 +72,21 @@ public final class MinestomCaptionKeys {
*/
public static final Caption ARGUMENT_PARSE_FAILURE_ITEM_STACK = of("argument.parse.failure.item_stack");
+ /**
+ * Variables: {@code }
+ */
+ public static final Caption ARGUMENT_PARSE_FAILURE_ENCHANTMENT = of("argument.parse.failure.enchantment");
+
+ /**
+ * Variables: {@code }
+ */
+ public static final Caption ARGUMENT_PARSE_FAILURE_SOUND_EVENT = of("argument.parse.failure.sound_event");
+
+ /**
+ * Variables: {@code }
+ */
+ public static final Caption ARGUMENT_PARSE_FAILURE_ATTRIBUTE = of("argument.parse.failure.attribute");
+
private MinestomCaptionKeys() {
}
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java
index bc7f8993..fd242706 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomDefaultCaptionsProvider.java
@@ -49,11 +49,6 @@ public final class MinestomDefaultCaptionsProvider extends DelegatingCaptionP
*/
public static final String ARGUMENT_PARSE_FAILURE_INSTANCE = "No instance found for input ''";
- /**
- * Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_GAME_MODE}
- */
- public static final String ARGUMENT_PARSE_FAILURE_GAME_MODE = "'' is not a valid game mode";
-
/**
* Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE}
*/
@@ -74,15 +69,32 @@ public final class MinestomDefaultCaptionsProvider extends DelegatingCaptionP
*/
public static final String ARGUMENT_PARSE_FAILURE_ITEM_STACK = "'' is not a valid item";
+ /**
+ * Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_ENCHANTMENT}
+ */
+ public static final String ARGUMENT_PARSE_FAILURE_ENCHANTMENT = "'' is not a valid enchantment";
+
+ /**
+ * Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_SOUND_EVENT}
+ */
+ public static final String ARGUMENT_PARSE_FAILURE_SOUND_EVENT = "'' is not a valid sound event";
+
+ /**
+ * Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_ATTRIBUTE}
+ */
+ public static final String ARGUMENT_PARSE_FAILURE_ATTRIBUTE = "'' is not a valid attribute";
+
private static final CaptionProvider> PROVIDER = CaptionProvider.constantProvider()
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER, ARGUMENT_PARSE_FAILURE_PLAYER)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ENTITY_TYPE, ARGUMENT_PARSE_FAILURE_ENTITY_TYPE)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_INSTANCE, ARGUMENT_PARSE_FAILURE_INSTANCE)
- .putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_GAME_MODE, ARGUMENT_PARSE_FAILURE_GAME_MODE)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE, ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_VEC, ARGUMENT_PARSE_FAILURE_VEC)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_POS, ARGUMENT_PARSE_FAILURE_POS)
.putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ITEM_STACK, ARGUMENT_PARSE_FAILURE_ITEM_STACK)
+ .putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ENCHANTMENT, ARGUMENT_PARSE_FAILURE_ENCHANTMENT)
+ .putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_SOUND_EVENT, ARGUMENT_PARSE_FAILURE_SOUND_EVENT)
+ .putCaption(MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ATTRIBUTE, ARGUMENT_PARSE_FAILURE_ATTRIBUTE)
.build();
@SuppressWarnings("unchecked")
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/EnchantmentParser.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/EnchantmentParser.java
new file mode 100644
index 00000000..864b5981
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/EnchantmentParser.java
@@ -0,0 +1,138 @@
+//
+// MIT License
+//
+// Copyright (c) 2024 Incendo
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+package org.incendo.cloud.minestom.parser;
+
+import java.util.stream.Collectors;
+import net.kyori.adventure.key.Key;
+import net.minestom.server.MinecraftServer;
+import net.minestom.server.item.enchant.Enchantment;
+import net.minestom.server.registry.RegistryKey;
+import org.apiguardian.api.API;
+import org.incendo.cloud.caption.CaptionVariable;
+import org.incendo.cloud.component.CommandComponent;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.context.CommandInput;
+import org.incendo.cloud.exception.parsing.ParserException;
+import org.incendo.cloud.minestom.caption.MinestomCaptionKeys;
+import org.incendo.cloud.parser.ArgumentParseResult;
+import org.incendo.cloud.parser.ArgumentParser;
+import org.incendo.cloud.parser.ParserDescriptor;
+import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
+import org.jspecify.annotations.NonNull;
+
+/**
+ * Parser for {@link RegistryKey} referencing an {@link Enchantment}, resolved by namespaced key.
+ *
+ * @param command sender type
+ */
+public final class EnchantmentParser implements ArgumentParser>, BlockingSuggestionProvider.Strings {
+
+ /**
+ * Creates a new enchantment parser.
+ *
+ * @param command sender type
+ * @return the created parser
+ * @since 2.0.0
+ */
+ @API(status = API.Status.STABLE, since = "2.0.0")
+ @SuppressWarnings("unchecked")
+ public static @NonNull ParserDescriptor> enchantmentParser() {
+ return ParserDescriptor.of(new EnchantmentParser<>(), (Class>) (Class>) RegistryKey.class);
+ }
+
+ /**
+ * Returns a {@link CommandComponent.Builder} using {@link #enchantmentParser()} as the parser.
+ *
+ * @param the command sender type
+ * @return the component builder
+ * @since 2.0.0
+ */
+ @API(status = API.Status.STABLE, since = "2.0.0")
+ @SuppressWarnings("unchecked")
+ public static CommandComponent.@NonNull Builder> enchantmentComponent() {
+ return CommandComponent.>builder().parser(enchantmentParser());
+ }
+
+ @Override
+ public @NonNull ArgumentParseResult<@NonNull RegistryKey> parse(
+ final @NonNull CommandContext<@NonNull C> commandContext,
+ final @NonNull CommandInput commandInput
+ ) {
+ final String input = commandInput.readString();
+ final Key key = input.contains(":") ? Key.key(input) : Key.key("minecraft", input);
+ final RegistryKey registryKey = MinecraftServer.getEnchantmentRegistry().getKey(key);
+ if (registryKey == null) {
+ return ArgumentParseResult.failure(
+ new EnchantmentParseException(input, commandContext)
+ );
+ }
+ return ArgumentParseResult.success(registryKey);
+ }
+
+ @Override
+ public @NonNull Iterable<@NonNull String> stringSuggestions(
+ final @NonNull CommandContext commandContext,
+ final @NonNull CommandInput input
+ ) {
+ return MinecraftServer.getEnchantmentRegistry().keys().stream()
+ .map(k -> k.key().value())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Exception thrown when an enchantment cannot be found for the input provided.
+ */
+ public static final class EnchantmentParseException extends ParserException {
+
+ private final String input;
+
+ /**
+ * Create a new enchantment parse exception.
+ *
+ * @param input string input
+ * @param context command context
+ */
+ public EnchantmentParseException(
+ final @NonNull String input,
+ final @NonNull CommandContext> context
+ ) {
+ super(
+ EnchantmentParser.class,
+ context,
+ MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ENCHANTMENT,
+ CaptionVariable.of("input", input)
+ );
+ this.input = input;
+ }
+
+ /**
+ * Returns the supplied input.
+ *
+ * @return input value
+ */
+ public @NonNull String input() {
+ return this.input;
+ }
+ }
+}
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/GameModeParser.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/SoundEventParser.java
similarity index 67%
rename from cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/GameModeParser.java
rename to cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/SoundEventParser.java
index 6c9f2292..41ce9183 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/GameModeParser.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/SoundEventParser.java
@@ -23,10 +23,9 @@
//
package org.incendo.cloud.minestom.parser;
-import java.util.Arrays;
-import java.util.Locale;
import java.util.stream.Collectors;
-import net.minestom.server.entity.GameMode;
+import net.kyori.adventure.key.Key;
+import net.minestom.server.sound.SoundEvent;
import org.apiguardian.api.API;
import org.incendo.cloud.caption.CaptionVariable;
import org.incendo.cloud.component.CommandComponent;
@@ -41,47 +40,48 @@
import org.jspecify.annotations.NonNull;
/**
- * Parser for {@link GameMode game modes}.
+ * Parser for {@link SoundEvent}, resolved by namespaced key.
*
* @param command sender type
*/
-public final class GameModeParser implements ArgumentParser, BlockingSuggestionProvider.Strings {
+public final class SoundEventParser implements ArgumentParser, BlockingSuggestionProvider.Strings {
/**
- * Creates a new game mode parser.
+ * Creates a new sound event parser.
*
* @param command sender type
* @return the created parser
* @since 2.0.0
*/
@API(status = API.Status.STABLE, since = "2.0.0")
- public static @NonNull ParserDescriptor gameModeParser() {
- return ParserDescriptor.of(new GameModeParser<>(), GameMode.class);
+ public static @NonNull ParserDescriptor soundEventParser() {
+ return ParserDescriptor.of(new SoundEventParser<>(), SoundEvent.class);
}
/**
- * Returns a {@link CommandComponent.Builder} using {@link #gameModeParser()} as the parser.
+ * Returns a {@link CommandComponent.Builder} using {@link #soundEventParser()} as the parser.
*
* @param the command sender type
* @return the component builder
* @since 2.0.0
*/
@API(status = API.Status.STABLE, since = "2.0.0")
- public static CommandComponent.@NonNull Builder gameModeComponent() {
- return CommandComponent.builder().parser(gameModeParser());
+ public static CommandComponent.@NonNull Builder soundEventComponent() {
+ return CommandComponent.builder().parser(soundEventParser());
}
@Override
- public @NonNull ArgumentParseResult<@NonNull GameMode> parse(
+ public @NonNull ArgumentParseResult<@NonNull SoundEvent> parse(
final @NonNull CommandContext<@NonNull C> commandContext,
final @NonNull CommandInput commandInput
) {
final String input = commandInput.readString();
- return Arrays.stream(GameMode.values())
- .filter(gm -> gm.name().equalsIgnoreCase(input))
- .findFirst()
- .map(ArgumentParseResult::success)
- .orElseGet(() -> ArgumentParseResult.failure(new GameModeParseException(input, commandContext)));
+ final Key key = input.contains(":") ? Key.key(input) : Key.key("minecraft", input);
+ final SoundEvent sound = SoundEvent.fromKey(key);
+ if (sound == null) {
+ return ArgumentParseResult.failure(new SoundEventParseException(input, commandContext));
+ }
+ return ArgumentParseResult.success(sound);
}
@Override
@@ -89,32 +89,32 @@ public final class GameModeParser implements ArgumentParser, Blo
final @NonNull CommandContext commandContext,
final @NonNull CommandInput input
) {
- return Arrays.stream(GameMode.values())
- .map(gm -> gm.name().toLowerCase(Locale.ROOT))
+ return SoundEvent.values().stream()
+ .map(s -> s.key().value())
.collect(Collectors.toList());
}
/**
- * Exception thrown when a game mode cannot be found for the input provided.
+ * Exception thrown when a sound event cannot be found for the input provided.
*/
- public static final class GameModeParseException extends ParserException {
+ public static final class SoundEventParseException extends ParserException {
private final String input;
/**
- * Create a new game mode parse exception.
+ * Create a new sound event parse exception.
*
- * @param input string input
+ * @param input string input
* @param context command context
*/
- public GameModeParseException(
+ public SoundEventParseException(
final @NonNull String input,
final @NonNull CommandContext> context
) {
super(
- GameModeParser.class,
+ SoundEventParser.class,
context,
- MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_GAME_MODE,
+ MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_SOUND_EVENT,
CaptionVariable.of("input", input)
);
this.input = input;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/AttributeParser.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/AttributeParser.java
new file mode 100644
index 00000000..7f6ba4a6
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/AttributeParser.java
@@ -0,0 +1,132 @@
+//
+// MIT License
+//
+// Copyright (c) 2024 Incendo
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+package org.incendo.cloud.minestom.parser.attribute;
+
+import java.util.stream.Collectors;
+import net.kyori.adventure.key.Key;
+import net.minestom.server.entity.attribute.Attribute;
+import org.apiguardian.api.API;
+import org.incendo.cloud.caption.CaptionVariable;
+import org.incendo.cloud.component.CommandComponent;
+import org.incendo.cloud.context.CommandContext;
+import org.incendo.cloud.context.CommandInput;
+import org.incendo.cloud.exception.parsing.ParserException;
+import org.incendo.cloud.minestom.caption.MinestomCaptionKeys;
+import org.incendo.cloud.parser.ArgumentParseResult;
+import org.incendo.cloud.parser.ArgumentParser;
+import org.incendo.cloud.parser.ParserDescriptor;
+import org.incendo.cloud.suggestion.BlockingSuggestionProvider;
+import org.jspecify.annotations.NonNull;
+
+/**
+ * Parser for {@link Attribute}, by namespaced key.
+ *
+ * @param command sender type
+ */
+public final class AttributeParser implements ArgumentParser, BlockingSuggestionProvider.Strings {
+
+ /**
+ * Creates a new attribute parser.
+ *
+ * @param command sender type
+ * @return the created parser
+ * @since 2.0.0
+ */
+ @API(status = API.Status.STABLE, since = "2.0.0")
+ public static @NonNull ParserDescriptor attributeParser() {
+ return ParserDescriptor.of(new AttributeParser<>(), Attribute.class);
+ }
+
+ /**
+ * Returns a {@link CommandComponent.Builder} using {@link #attributeParser()} as the parser.
+ *
+ * @param the command sender type
+ * @return the component builder
+ * @since 2.0.0
+ */
+ @API(status = API.Status.STABLE, since = "2.0.0")
+ public static CommandComponent.@NonNull Builder attributeComponent() {
+ return CommandComponent.builder().parser(attributeParser());
+ }
+
+ @Override
+ public @NonNull ArgumentParseResult<@NonNull Attribute> parse(
+ final @NonNull CommandContext<@NonNull C> commandContext,
+ final @NonNull CommandInput commandInput
+ ) {
+ final String input = commandInput.readString();
+ final Key key = input.contains(":") ? Key.key(input) : Key.key("minecraft", input);
+ final Attribute attribute = Attribute.fromKey(key);
+ if (attribute == null) {
+ return ArgumentParseResult.failure(new AttributeParseException(input, commandContext));
+ }
+ return ArgumentParseResult.success(attribute);
+ }
+
+ @Override
+ public @NonNull Iterable<@NonNull String> stringSuggestions(
+ final @NonNull CommandContext commandContext,
+ final @NonNull CommandInput input
+ ) {
+ return Attribute.values().stream()
+ .map(a -> a.key().value())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Exception thrown when an attribute cannot be found for the input provided.
+ */
+ public static final class AttributeParseException extends ParserException {
+
+ private final String input;
+
+ /**
+ * Create a new attribute parse exception.
+ *
+ * @param input string input
+ * @param context command context
+ */
+ public AttributeParseException(
+ final @NonNull String input,
+ final @NonNull CommandContext> context
+ ) {
+ super(
+ AttributeParser.class,
+ context,
+ MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_ATTRIBUTE,
+ CaptionVariable.of("input", input)
+ );
+ this.input = input;
+ }
+
+ /**
+ * Returns the supplied input.
+ *
+ * @return input value
+ */
+ public @NonNull String input() {
+ return this.input;
+ }
+ }
+}
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/package-info.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/package-info.java
new file mode 100644
index 00000000..ba7ec2d2
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/attribute/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * cloud-minestom attribute-specific command arguments
+ */
+package org.incendo.cloud.minestom.parser.attribute;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/ItemStackParser.java
similarity index 99%
rename from cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java
rename to cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/ItemStackParser.java
index 4c1846ed..e2f04ed4 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/ItemStackParser.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/ItemStackParser.java
@@ -21,7 +21,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
-package org.incendo.cloud.minestom.parser;
+package org.incendo.cloud.minestom.parser.item;
import java.util.stream.Collectors;
import net.kyori.adventure.key.Key;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/package-info.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/package-info.java
new file mode 100644
index 00000000..c24fa98b
--- /dev/null
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/item/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * cloud-minestom item-specific command arguments
+ */
+package org.incendo.cloud.minestom.parser.item;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/location/package-info.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/location/package-info.java
index 5246c5db..cf02038e 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/location/package-info.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/location/package-info.java
@@ -1,4 +1,4 @@
/**
- * cloud-bukkit location-specific command arguments
+ * cloud-minestom location-specific command arguments
*/
package org.incendo.cloud.minestom.parser.location;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/package-info.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/package-info.java
index bd401ff2..9052e0d7 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/package-info.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/parser/package-info.java
@@ -1,4 +1,4 @@
/**
- * cloud-bukkit command arguments
+ * cloud-minestom command arguments
*/
package org.incendo.cloud.minestom.parser;
From 0da0c7de75922ec8a4168d66ab0255d0f1ecf6c3 Mon Sep 17 00:00:00 2001
From: Skullian <133133667+Skullians@users.noreply.github.com>
Date: Mon, 4 May 2026 01:31:47 +0100
Subject: [PATCH 3/3] fix: compile
---
.../org/incendo/cloud/minestom/MinestomCommandManager.java | 1 -
.../incendo/cloud/minestom/caption/MinestomCaptionKeys.java | 5 -----
2 files changed, 6 deletions(-)
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
index b39ceed2..2147ab2f 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/MinestomCommandManager.java
@@ -44,7 +44,6 @@
import org.incendo.cloud.minestom.parser.PlayerParser;
import org.incendo.cloud.minestom.parser.SoundEventParser;
import org.incendo.cloud.minestom.parser.attribute.AttributeParser;
-import org.incendo.cloud.minestom.parser.item.ItemStackParser;
import org.incendo.cloud.minestom.parser.location.PosParser;
import org.incendo.cloud.minestom.parser.location.VecParser;
diff --git a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
index 334949a3..5e83df27 100644
--- a/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
+++ b/cloud-minestom/src/main/java/org/incendo/cloud/minestom/caption/MinestomCaptionKeys.java
@@ -87,11 +87,6 @@ public final class MinestomCaptionKeys {
*/
public static final Caption ARGUMENT_PARSE_FAILURE_ATTRIBUTE = of("argument.parse.failure.attribute");
- /**
- * Variables: {@code }
- */
- public static final Caption ARGUMENT_PARSE_FAILURE_ITEM_STACK = of("argument.parse.failure.item_stack");
-
private MinestomCaptionKeys() {
}