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
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,17 @@ See [examples/example-minestom](https://github.com/spectr-is/cloud-minecraft/blo
### Minestom Parsers
As of right now there's only two built-in parsers that I bothered to add.

| Parser | Type | Description |
|--------------------|--------------|-------------------------------------------|
| `PlayerParser` | `Player` | Resolves an online player by username |
| `EntityTypeParser` | `EntityType` | Resolves an entity type by namespaced key |
## 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 (`~ ~ ~ ~ ~`)) |

## links

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@
import org.incendo.cloud.SenderMapperHolder;
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.EntityTypeParser;
import org.incendo.cloud.minestom.parser.GameModeParser;
import org.incendo.cloud.minestom.parser.InstanceParser;
import org.incendo.cloud.minestom.parser.PlayerParser;
import org.incendo.cloud.minestom.parser.location.PosParser;
import org.incendo.cloud.minestom.parser.location.VecParser;

/**
* Command manager for the Minestom platform.
Expand Down Expand Up @@ -72,7 +77,12 @@ public MinestomCommandManager(

this.parserRegistry()
.registerParser(PlayerParser.playerParser())
.registerParser(EntityTypeParser.entityTypeParser());
.registerParser(EntityTypeParser.entityTypeParser())
.registerParser(InstanceParser.instanceParser())
.registerParser(GameModeParser.gameModeParser())
.registerParser(DimensionTypeParser.dimensionTypeParser())
.registerParser(PosParser.posParser())
.registerParser(VecParser.vecParser());

this.captionRegistry().registerProvider(new MinestomDefaultCaptionsProvider<>());

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

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

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

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

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

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

private MinestomCaptionKeys() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,39 @@ public final class MinestomDefaultCaptionsProvider<C> extends DelegatingCaptionP
*/
public static final String ARGUMENT_PARSE_FAILURE_ENTITY_TYPE = "'<input>' is not a valid entity type";

/**
* Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_INSTANCE}
*/
public static final String ARGUMENT_PARSE_FAILURE_INSTANCE = "No instance found for input '<input>'";

/**
* Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_GAME_MODE}
*/
public static final String ARGUMENT_PARSE_FAILURE_GAME_MODE = "'<input>' is not a valid game mode";

/**
* Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE}
*/
public static final String ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE = "'<input>' is not a valid dimension type";

/**
* Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_VEC}
*/
public static final String ARGUMENT_PARSE_FAILURE_VEC = "'<input>' is not a valid vec (expected: x y z)";

/**
* Default caption for {@link MinestomCaptionKeys#ARGUMENT_PARSE_FAILURE_POS}
*/
public static final String ARGUMENT_PARSE_FAILURE_POS = "'<input>' is not a valid pos (expected: x y z, optionally with yaw and pitch)";

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)
.build();

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
@@ -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.world.DimensionType;
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 DimensionType dimension types}, matched by namespaced key.
*
* @param <C> command sender type
*/
public final class DimensionTypeParser<C> implements ArgumentParser<C, DimensionType>, BlockingSuggestionProvider.Strings<C> {

/**
* Creates a new dimension type 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, DimensionType> dimensionTypeParser() {
return ParserDescriptor.of(new DimensionTypeParser<>(), DimensionType.class);
}

/**
* Returns a {@link CommandComponent.Builder} using {@link #dimensionTypeParser()} 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, DimensionType> dimensionTypeComponent() {
return CommandComponent.<C, DimensionType>builder().parser(dimensionTypeParser());
}

@Override
public @NonNull ArgumentParseResult<@NonNull DimensionType> 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 DimensionTypeParseException(input, commandContext));
}
final DimensionType type = MinecraftServer.getDimensionTypeRegistry().get(key);
if (type == null) {
return ArgumentParseResult.failure(new DimensionTypeParseException(input, commandContext));
}
return ArgumentParseResult.success(type);
}

@Override
public @NonNull Iterable<@NonNull String> stringSuggestions(
final @NonNull CommandContext<C> commandContext,
final @NonNull CommandInput input
) {
return MinecraftServer.getDimensionTypeRegistry().keys().stream()
.map(key -> key.key().asString())
.collect(Collectors.toList());
}

/**
* Exception thrown when a dimension type cannot be found for the input provided.
*/
public static final class DimensionTypeParseException extends ParserException {

private final String input;

/**
* Create a new dimension type parse exception.
*
* @param input string input
* @param context command context
*/
public DimensionTypeParseException(
final @NonNull String input,
final @NonNull CommandContext<?> context
) {
super(
DimensionTypeParser.class,
context,
MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_DIMENSION_TYPE,
CaptionVariable.of("input", input)
);
this.input = input;
}

/**
* Returns the supplied input.
*
* @return input value
*/
public @NonNull String input() {
return this.input;
}
}
}
Original file line number Diff line number Diff line change
@@ -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;

import java.util.Arrays;
import java.util.Locale;
import java.util.stream.Collectors;
import net.minestom.server.entity.GameMode;
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 GameMode game modes}.
*
* @param <C> command sender type
*/
public final class GameModeParser<C> implements ArgumentParser<C, GameMode>, BlockingSuggestionProvider.Strings<C> {

/**
* Creates a new game mode 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, GameMode> gameModeParser() {
return ParserDescriptor.of(new GameModeParser<>(), GameMode.class);
}

/**
* Returns a {@link CommandComponent.Builder} using {@link #gameModeParser()} 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, GameMode> gameModeComponent() {
return CommandComponent.<C, GameMode>builder().parser(gameModeParser());
}

@Override
public @NonNull ArgumentParseResult<@NonNull GameMode> 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)));
}

@Override
public @NonNull Iterable<@NonNull String> stringSuggestions(
final @NonNull CommandContext<C> commandContext,
final @NonNull CommandInput input
) {
return Arrays.stream(GameMode.values())
.map(gm -> gm.name().toLowerCase(Locale.ROOT))
.collect(Collectors.toList());
}

/**
* Exception thrown when a game mode cannot be found for the input provided.
*/
public static final class GameModeParseException extends ParserException {

private final String input;

/**
* Create a new game mode parse exception.
*
* @param input string input
* @param context command context
*/
public GameModeParseException(
final @NonNull String input,
final @NonNull CommandContext<?> context
) {
super(
GameModeParser.class,
context,
MinestomCaptionKeys.ARGUMENT_PARSE_FAILURE_GAME_MODE,
CaptionVariable.of("input", input)
);
this.input = input;
}

/**
* Returns the supplied input.
*
* @return input value
*/
public @NonNull String input() {
return this.input;
}
}
}
Loading