aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker/skyblock
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java101
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java64
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java171
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java149
4 files changed, 485 insertions, 0 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java
new file mode 100644
index 00000000..7ec9cefa
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java
@@ -0,0 +1,101 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import it.unimi.dsi.fastutil.ints.IntIntPair;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.texture.atlas.Sprite;
+import net.minecraft.util.Identifier;
+import org.apache.commons.math3.analysis.UnivariateMatrixFunction;
+
+import java.awt.*;
+import java.util.Arrays;
+
+public class CrystalsHud {
+ public static final MinecraftClient client = MinecraftClient.getInstance();
+
+ protected static final Identifier MAP_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/crystals_map.png"); //todo is this the right place to store file
+
+ private static final Identifier MAP_ICON = new Identifier("textures/map/map_icons.png");
+
+ public static boolean visable = false;
+
+
+
+
+ public static void init() {
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker")
+ .then(ClientCommandManager.literal("hud")
+ .then(ClientCommandManager.literal("crystals")
+ .executes(Scheduler.queueOpenScreenCommand(CrystalsHudConfigScreen::new))))));
+
+ HudRenderCallback.EVENT.register((context, tickDelta) -> {
+ if (!SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enabled
+ || client.options.playerListKey.isPressed()
+ || client.player == null
+ || !visable) {
+ return;
+ }
+ render(context, SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.x,
+ SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.y);
+ });
+ }
+
+ public static IntIntPair getDimForConfig() {
+ return IntIntPair.of(62, 62);
+ }
+
+ public static void render( DrawContext context, int hudX, int hudY) {
+
+ if (SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enableBackground) {
+ context.fill(hudX, hudY, hudX + 62, hudY + 62, 0x64000000);
+ }
+
+
+ //draw map texture
+ context.
+ drawTexture(MAP_TEXTURE,hudX,hudY,0,0,62,62,62,62);
+ //draw player on map
+ if (client.player == null || client.getNetworkHandler() == null) {
+ return;
+ }
+ //get player location
+ double playerX = client.player.getX();
+ double playerZ = client.player.getZ();
+ double facing = client.player.getYaw();
+ //map location to map
+ int renderX = (int)((playerX-202)/621 * 62);
+ int renderY = (int)((playerZ -202)/621 * 62);
+ int renderAngle = (int)(facing %360);
+ if (renderAngle < 0){//make sure the angle is always correct between 0 and 360
+ renderAngle = 360 + renderAngle;
+ }
+ //clamp location to map
+ renderX = Math.max(0, Math.min(62, renderX));
+ renderY = Math.max(0, Math.min(62, renderY));
+ //draw marker on map
+ context.
+ drawTexture(MAP_ICON,hudX+renderX,hudY+renderY,2,0,5,7,128,128);
+
+ //todo add direction and scale (could be wrong drawing methods) and offset to center on player
+
+ }
+
+ public static void update() {
+ if (client.player == null || client.getNetworkHandler() == null || !SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.enabled) {
+ visable = false;
+ return;
+ }
+ //get if the player is in the crystals
+ visable = Utils.isInCrystals();
+
+
+ }
+
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java
new file mode 100644
index 00000000..18be8bed
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHudConfigScreen.java
@@ -0,0 +1,64 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.tabhud.widget.hud.HudCommsWidget;
+import de.hysky.skyblocker.utils.render.RenderHelper;
+import it.unimi.dsi.fastutil.ints.IntIntPair;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.text.Text;
+
+import java.awt.*;
+
+public class CrystalsHudConfigScreen extends Screen {
+
+ private int hudX = SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.x;
+ private int hudY = SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.y;
+ private final Screen parent;
+
+ protected CrystalsHudConfigScreen() {
+ this(null);
+ }
+
+ public CrystalsHudConfigScreen(Screen parent) {
+ super(Text.of("Crystals HUD Config"));
+ this.parent = parent;
+ }
+
+ @Override
+ public void render(DrawContext context, int mouseX, int mouseY, float delta) {
+ super.render(context, mouseX, mouseY, delta);
+ renderBackground(context, mouseX, mouseY, delta);
+ CrystalsHud.render( context, hudX, hudY);
+ context.drawCenteredTextWithShadow(textRenderer, "Right Click To Reset Position", width / 2, height / 2, Color.GRAY.getRGB());
+ }
+
+ @Override
+ public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
+ IntIntPair dims = CrystalsHud.getDimForConfig();
+ if (RenderHelper.pointIsInArea(mouseX, mouseY, hudX, hudY, hudX + 200, hudY + 40) && button == 0) {
+ hudX = (int) Math.max(Math.min(mouseX - (double) dims.leftInt() / 2, this.width - dims.leftInt()), 0);
+ hudY = (int) Math.max(Math.min(mouseY - (double) dims.rightInt() / 2, this.height - dims.rightInt()), 0);
+ }
+ return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (button == 1) {
+ IntIntPair dims = CrystalsHud.getDimForConfig();
+ hudX = this.width / 2 - dims.leftInt();
+ hudY = this.height / 2 - dims.rightInt();
+ }
+ return super.mouseClicked(mouseX, mouseY, button);
+ }
+
+ @Override
+ public void close() {
+ SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.x = hudX;
+ SkyblockerConfigManager.get().locations.dwarvenMines.crystalsHud.y = hudY;
+ SkyblockerConfigManager.save();
+
+ client.setScreen(parent);
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
new file mode 100644
index 00000000..d9f31f1d
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
@@ -0,0 +1,171 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import com.mojang.authlib.GameProfile;
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
+import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.command.CommandRegistryAccess;
+import net.minecraft.command.argument.BlockPosArgumentType;
+import net.minecraft.command.argument.DefaultPosArgument;
+import net.minecraft.command.argument.PosArgument;
+import net.minecraft.network.message.MessageType;
+import net.minecraft.network.message.SignedMessage;
+import net.minecraft.server.command.ServerCommandSource;
+import net.minecraft.text.ClickEvent;
+import net.minecraft.text.MutableText;
+import net.minecraft.text.Text;
+import net.minecraft.util.math.BlockPos;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.mojang.brigadier.arguments.StringArgumentType.getString;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+public class CrystalsLocationsManager {
+ public static final MinecraftClient client = MinecraftClient.getInstance();
+ public static Map<String,CrystalsWaypoint> ActiveWaypoints= new HashMap<>() {};
+
+ public static final Map<String, CrystalsWaypoint.Category> WAYPOINTLOCATIONS = Map.of(
+ "Jungle Temple", CrystalsWaypoint.Category.JUNGLETEMPLE,
+ "Mines Of Divan", CrystalsWaypoint.Category.MINESOFDIVAN,
+ "Goblin Queen's Den", CrystalsWaypoint.Category.GOBLINQUEENSDEN,
+ "Lost Precursor City", CrystalsWaypoint.Category.LOSTPRECURSORCITY,
+ "Khazad-dûm", CrystalsWaypoint.Category.KHAZADUM,
+ "Fairy Grotto", CrystalsWaypoint.Category.FAIRYGROTTO,
+ "Dragon's Lair", CrystalsWaypoint.Category.DRAGONSLAIR
+ );
+ private static final Pattern TEXT_CWORDS_PATTERN = Pattern.compile("([0-9][0-9][0-9]) ([0-9][0-9][0-9]?) ([0-9][0-9][0-9])");
+
+
+ public static void init() {
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker")
+ .then(ClientCommandManager.literal("hud")
+ .then(ClientCommandManager.literal("crystals")
+ .executes(Scheduler.queueOpenScreenCommand(CrystalsHudConfigScreen::new))))));
+
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(CrystalsLocationsManager::render);
+ ClientReceiveMessageEvents.CHAT.register(CrystalsLocationsManager::extractLocationFromMessage);
+ ClientCommandRegistrationCallback.EVENT.register(CrystalsLocationsManager::registerWaypointLocationCommands);
+ }
+ private static void extractLocationFromMessage(Text message, SignedMessage signedMessage, GameProfile sender, MessageType.Parameters params, Instant receptionTimestamp){
+ if (!SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints.findInChat ) { //todo || !Utils.isInCrystals()
+ return;
+ }
+ //get the message text
+ String value = signedMessage.getContent().getString();
+ Matcher matcher = TEXT_CWORDS_PATTERN.matcher(value);
+ //if there are cwords in the message try to get them and what they are talking about
+ if (matcher.find()){
+ String location = matcher.group();
+ Integer[] cowordinates = Arrays.stream(location.split(" ",3)).map(Integer::parseInt).toArray(Integer[]::new);
+ BlockPos blockPos = new BlockPos(cowordinates[0],cowordinates[1],cowordinates[2]);
+ //todo make sure this is in bounds of crystals
+ //see if there is a name of a location to add to this
+ for (String waypointLocation : WAYPOINTLOCATIONS.keySet()){
+ if (value.toLowerCase().contains(waypointLocation.toLowerCase())){ //todo be more lenient
+ //all data found to create waypoint
+ addCustomWaypoint(Text.of(waypointLocation),blockPos);
+ return;
+ }
+ }
+ //if the location is not found ask the user for the location (could have been in a previous chat message)
+ if (client.player == null || client.getNetworkHandler() == null ) {
+ return;
+ }
+ client.player.sendMessage(getLocationInputText(location), false);
+ }
+
+
+ }
+ private static void registerWaypointLocationCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
+ dispatcher.register(literal(SkyblockerMod.NAMESPACE)
+ .then(literal("crystalWaypoints")
+ .then(argument("pos", BlockPosArgumentType.blockPos())
+ .then(argument("place", StringArgumentType.greedyString())
+ .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"),context.getArgument("pos", PosArgument.class)))
+ )
+ )
+ )
+ );
+ }
+ private static Text getSetLocationMessage(String location,BlockPos blockPos) {
+ MutableText text = Text.empty();
+ text.append(Text.literal("Added waypoint for "+location+" at :"+blockPos.getX()+" "+blockPos.getY()+" "+blockPos.getZ()+".")); //todo add colours
+
+ return text;
+ }
+ private static Text getLocationInputText(String location) {
+ MutableText text = Text.empty();
+ for (String waypointLocation : WAYPOINTLOCATIONS.keySet()){
+ //todo add colour codes
+ text.append(Text.literal("["+waypointLocation+"]").styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker crystalWaypoints "+location+" "+waypointLocation))));
+ }
+
+ return text;
+ }
+ public static int addWaypointFromCommand(FabricClientCommandSource source, String place, PosArgument location) {
+ // TODO Less hacky way with custom ClientBlockPosArgumentType
+ BlockPos blockPos = location.toAbsoluteBlockPos(new ServerCommandSource(null, source.getPosition(), source.getRotation(), null, 0, null, null, null, null));
+ if (WAYPOINTLOCATIONS.containsKey(place)){
+ addCustomWaypoint(Text.of(place), blockPos);
+ //todo send to map
+ //tell the client it has done this
+ if (client.player == null || client.getNetworkHandler() == null ) {
+ return Command.SINGLE_SUCCESS;
+ }
+ client.player.sendMessage(getSetLocationMessage(place, blockPos), false);
+ }
+ return Command.SINGLE_SUCCESS;
+ }
+
+
+ private static void addCustomWaypoint( Text waypointName, BlockPos pos) {
+ CrystalsWaypoint.Category category = WAYPOINTLOCATIONS.get(waypointName.getString());
+ CrystalsWaypoint waypoint = new CrystalsWaypoint(category, waypointName, pos);
+ ActiveWaypoints.put(waypointName.getString(),waypoint);
+ }
+ public static void render(WorldRenderContext context) {
+ if (SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints.enabled ) {
+ for (CrystalsWaypoint crystalsWaypoint : ActiveWaypoints.values()) {
+ if (crystalsWaypoint.shouldRender()) {
+ crystalsWaypoint.render(context);
+ }
+ }
+ }
+ }
+
+ public static void update() {
+ if (client.player == null || client.getNetworkHandler() == null || !SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints.enabled) {
+ ActiveWaypoints= new HashMap<>();
+ return;
+ }
+ //get if the player is in the crystals
+ String location = Utils.getIslandArea().replace("⏣ ","");
+ //if new location and needs waypoint add waypoint
+ if (!location.equals("Unknown") && WAYPOINTLOCATIONS.containsKey(location) && !ActiveWaypoints.containsKey(location)){
+ //add waypoint at player location
+ BlockPos playerLocation = client.player.getBlockPos();
+ addCustomWaypoint(Text.of(location),playerLocation);
+ //todo send to map gui
+ }
+
+
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java
new file mode 100644
index 00000000..9c6db04f
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java
@@ -0,0 +1,149 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import com.google.gson.JsonObject;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.JsonOps;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.render.RenderHelper;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.command.argument.EnumArgumentType;
+import net.minecraft.entity.Entity;
+import net.minecraft.text.Text;
+import net.minecraft.text.TextCodecs;
+import net.minecraft.util.Formatting;
+import net.minecraft.util.StringIdentifiable;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+
+public class CrystalsWaypoint extends Waypoint {
+ private static final Logger LOGGER = LoggerFactory.getLogger(CrystalsWaypoint.class);
+ public static final Codec<CrystalsWaypoint> CODEC = RecordCodecBuilder.create(instance -> instance.group(
+ Category.CODEC.fieldOf("category").forGetter(crystalsWaypoint -> crystalsWaypoint.category),
+ TextCodecs.CODEC.fieldOf("name").forGetter(crystalsWaypoint -> crystalsWaypoint.name),
+ BlockPos.CODEC.fieldOf("pos").forGetter(crystalsWaypoint -> crystalsWaypoint.pos)
+ ).apply(instance, CrystalsWaypoint::new));
+ public static final Codec<List<CrystalsWaypoint>> LIST_CODEC = CODEC.listOf();
+ static final List<String> SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman");
+ private static final Supplier<SkyblockerConfig.CrystalsWaypoints> CONFIG = () -> SkyblockerConfigManager.get().locations.dwarvenMines.crystalsWaypoints;
+ static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.get().waypointType;
+ final Category category;
+ final Text name;
+ private final Vec3d centerPos;
+
+ CrystalsWaypoint( JsonObject waypoint, String name, BlockPos pos) {
+ this(Category.get(waypoint), name, pos);
+ }
+
+ CrystalsWaypoint(Category category, String name, BlockPos pos) {
+ this( category, Text.of(name), pos);
+ }
+
+ CrystalsWaypoint( Category category, Text name, BlockPos pos) {
+ super(pos, TYPE_SUPPLIER, category.colorComponents);
+ this.category = category;
+ this.name = name;
+ this.centerPos = pos.toCenterPos();
+ }
+
+ static ToDoubleFunction<CrystalsWaypoint> getSquaredDistanceToFunction(Entity entity) {
+ return crystalsWaypoint -> entity.squaredDistanceTo(crystalsWaypoint.centerPos);
+ }
+
+ static Predicate<CrystalsWaypoint> getRangePredicate(Entity entity) {
+ return crystalsWaypoint -> entity.squaredDistanceTo(crystalsWaypoint.centerPos) <= 36D;
+ }
+
+ @Override
+ public boolean shouldRender() {
+ return super.shouldRender() ;
+ }
+
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj) || obj instanceof CrystalsWaypoint other && category == other.category && name.equals(other.name) && pos.equals(other.pos);
+ }
+
+ /**
+ * Renders the secret waypoint, including a waypoint through {@link Waypoint#render(WorldRenderContext)}, the name, and the distance from the player.
+ */
+ @Override
+ public void render(WorldRenderContext context) {
+ //TODO In the future, shrink the box for wither essence and items so its more realistic
+ super.render(context);
+
+
+ Vec3d posUp = centerPos.add(0, 1, 0);
+ RenderHelper.renderText(context, name, posUp, true);
+ double distance = context.camera().getPos().distanceTo(centerPos);
+ RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, 1, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true);
+
+ }
+
+
+
+ enum Category implements StringIdentifiable { //todo set better colours and remove extra data
+ JUNGLETEMPLE("Jungle Temple", 0, 255, 0),
+ MINESOFDIVAN("Mines Of Divan", 255, 0, 0),
+ GOBLINQUEENSDEN("Goblin Queen's Den", 2, 213, 250),
+ LOSTPRECURSORCITY("Lost Precursor City", 2, 64, 250),
+ KHAZADUM("Khazad-dûm", 142, 66, 0),
+ FAIRYGROTTO("Fairy Grotto", 30, 30, 30),
+ DRAGONSLAIR("Dragon's Lair", 250, 217, 2),
+ DEFAULT("default", 190, 255, 252);
+
+ private static final Codec<Category> CODEC = StringIdentifiable.createCodec(Category::values);
+ private final String name;
+
+ private final float[] colorComponents;
+
+ Category(String name, int... intColorComponents) {
+ this.name = name;
+
+ colorComponents = new float[intColorComponents.length];
+ for (int i = 0; i < intColorComponents.length; i++) {
+ colorComponents[i] = intColorComponents[i] / 255F;
+ }
+ }
+
+ static Category get(JsonObject waypointJson) {
+ return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(LOGGER::error).orElse(Category.DEFAULT);
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public String asString() {
+ return name;
+ }
+
+ static class CategoryArgumentType extends EnumArgumentType<Category> {
+ CategoryArgumentType() {
+ super(Category.CODEC, Category::values);
+ }
+
+ static CategoryArgumentType category() {
+ return new CategoryArgumentType();
+ }
+
+ static <S> Category getCategory(CommandContext<S> context, String name) {
+ return context.getArgument(name, Category.class);
+ }
+ }
+ }
+}