Skip to content

Commit e8ec6cd

Browse files
committed
Refactored enum argument parsing into EnumArgumentType
Replaced the existing implementation in `CustomArgumentTypes` with `EnumArgumentType` and introduced a dedicated class for cleaner, reusable logic. Deprecated the old `enumType` method in favor of this new approach.
1 parent 26760bf commit e8ec6cd

File tree

2 files changed

+85
-17
lines changed

2 files changed

+85
-17
lines changed

paper/src/main/java/core/paper/command/CustomArgumentTypes.java

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,30 @@
33
import com.mojang.brigadier.arguments.ArgumentType;
44
import com.mojang.brigadier.arguments.StringArgumentType;
55
import core.paper.cache.PlayerCache;
6+
import core.paper.command.argument.EnumArgumentType;
7+
import core.paper.command.argument.codec.EnumStringCodec;
68
import net.kyori.adventure.text.Component;
79
import org.bukkit.Bukkit;
810
import org.bukkit.OfflinePlayer;
911
import org.bukkit.entity.Player;
1012
import org.jspecify.annotations.NullMarked;
1113

12-
import java.util.Arrays;
1314
import java.util.Objects;
1415
import java.util.concurrent.CompletableFuture;
1516

1617
@NullMarked
18+
@Deprecated(forRemoval = true, since = "2.3.0")
1719
public final class CustomArgumentTypes {
1820
private static final ComponentCommandExceptionType NO_PLAYER_FOUND = new ComponentCommandExceptionType(
1921
Component.translatable("argument.entity.notfound.player")
2022
);
2123

24+
/**
25+
* @deprecated use {@link EnumArgumentType#of(Class, EnumStringCodec)}
26+
*/
27+
@Deprecated(forRemoval = true, since = "2.3.0")
2228
public static <T extends Enum<T>> ArgumentType<T> enumType(Class<T> enumClass) {
23-
return new WrappedArgumentType<>(StringArgumentType.string(),
24-
(reader, type) -> Arrays.stream(enumClass.getEnumConstants())
25-
.filter(constant -> constant.name().equalsIgnoreCase(type.replace("-", "_")))
26-
.findAny().orElseThrow(() -> new ComponentCommandExceptionType(
27-
Component.text("No such enum constant: " + type)
28-
).createWithContext(reader)),
29-
(context, builder) -> {
30-
Arrays.stream(enumClass.getEnumConstants())
31-
.map(Enum::name)
32-
.map(String::toLowerCase)
33-
.map(s -> s.replace("_", "-"))
34-
.filter(s -> s.contains(builder.getRemaining()))
35-
.map(StringArgumentType::escapeIfRequired)
36-
.forEach(builder::suggest);
37-
return builder.buildFuture();
38-
});
29+
return EnumArgumentType.of(enumClass, EnumStringCodec.hyphen());
3930
}
4031

4132
public static ArgumentType<OfflinePlayer> cachedOfflinePlayer() {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package core.paper.command.argument;
2+
3+
import com.mojang.brigadier.StringReader;
4+
import com.mojang.brigadier.arguments.ArgumentType;
5+
import com.mojang.brigadier.arguments.StringArgumentType;
6+
import com.mojang.brigadier.context.CommandContext;
7+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
8+
import com.mojang.brigadier.suggestion.Suggestions;
9+
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
10+
import core.paper.command.ComponentCommandExceptionType;
11+
import core.paper.command.argument.codec.EnumStringCodec;
12+
import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
13+
import net.kyori.adventure.text.Component;
14+
import org.jetbrains.annotations.Contract;
15+
import org.jspecify.annotations.NullMarked;
16+
17+
import java.util.Arrays;
18+
import java.util.concurrent.CompletableFuture;
19+
20+
/**
21+
* Represents an argument type for parsing and suggesting enum constants.
22+
* This class allows for conversion between string representations and enum constants of a specified type,
23+
* enabling the creation of command arguments based on enums.
24+
*
25+
* @param <E> the type of the enum
26+
* @since 2.3.0
27+
*/
28+
@NullMarked
29+
public final class EnumArgumentType<E extends Enum<E>> implements CustomArgumentType<E, String> {
30+
private final Class<E> enumClass;
31+
private final EnumStringCodec codec;
32+
33+
private EnumArgumentType(Class<E> enumClass, EnumStringCodec codec) {
34+
this.enumClass = enumClass;
35+
this.codec = codec;
36+
}
37+
38+
/**
39+
* Creates a new instance of {@link EnumArgumentType} for the specified enum class and string codec.
40+
*
41+
* @param <E> the type of the enum
42+
* @param enumClass the class of the enum type for which the argument type is being created
43+
* @param codec the {@link EnumStringCodec} responsible for converting between strings and enum constants
44+
* @return a new {@link EnumArgumentType} instance
45+
*/
46+
@Contract(value = "_, _ -> new", pure = true)
47+
public static <E extends Enum<E>> EnumArgumentType<E> of(Class<E> enumClass, EnumStringCodec codec) {
48+
return new EnumArgumentType<>(enumClass, codec);
49+
}
50+
51+
@Override
52+
public E parse(StringReader reader) throws CommandSyntaxException {
53+
var type = getNativeType().parse(reader);
54+
try {
55+
return codec.fromString(enumClass, type);
56+
} catch (IllegalArgumentException ignore) {
57+
throw new ComponentCommandExceptionType(
58+
Component.text("No such enum constant: " + type)
59+
).createWithContext(reader);
60+
}
61+
}
62+
63+
@Override
64+
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
65+
Arrays.stream(enumClass.getEnumConstants())
66+
.map(codec::toString)
67+
.map(StringArgumentType::escapeIfRequired)
68+
.filter(s -> s.contains(builder.getRemaining()))
69+
.forEach(builder::suggest);
70+
return builder.buildFuture();
71+
}
72+
73+
@Override
74+
public ArgumentType<String> getNativeType() {
75+
return StringArgumentType.string();
76+
}
77+
}

0 commit comments

Comments
 (0)