Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<>());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ public final class MinestomCaptionKeys {
*/
public static final Caption ARGUMENT_PARSE_FAILURE_POS = of("argument.parse.failure.pos");

/**
* Variables: {@code <input>}
*/
public static final Caption ARGUMENT_PARSE_FAILURE_ITEM_STACK = of("argument.parse.failure.item_stack");

private MinestomCaptionKeys() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public final class MinestomDefaultCaptionsProvider<C> extends DelegatingCaptionP
*/
public static final String ARGUMENT_PARSE_FAILURE_POS = "'<input>' 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 = "'<input>' 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)
Expand All @@ -77,6 +82,7 @@ public final class MinestomDefaultCaptionsProvider<C> 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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* cloud-minestom data holders
*/
package org.incendo.cloud.minestom.data;
Original file line number Diff line number Diff line change
@@ -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 <C> command sender type
*/
public final class ItemStackParser<C> implements ArgumentParser<C, ProtoItemStack>, BlockingSuggestionProvider.Strings<C> {

/**
* Creates a new item stack parser.
*
* @param <C> command sender type
* @return the created parser
* @since 2.0.0
*/
@API(status = API.Status.STABLE, since = "2.0.0")
public static <C> @NonNull ParserDescriptor<C, ProtoItemStack> itemStackParser() {
return ParserDescriptor.of(new ItemStackParser<>(), ProtoItemStack.class);
}

/**
* Returns a {@link CommandComponent.Builder} using {@link #itemStackParser()} as the parser.
*
* @param <C> the command sender type
* @return the component builder
* @since 2.0.0
*/
@API(status = API.Status.STABLE, since = "2.0.0")
public static <C> CommandComponent.@NonNull Builder<C, ProtoItemStack> itemStackComponent() {
return CommandComponent.<C, ProtoItemStack>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<C> 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;
}
}
}