/* * This file is part of Baritone. * * Baritone is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Baritone is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Baritone. If not, see . */ package baritone.utils.command.defaults; import baritone.api.Settings; import baritone.api.cache.IWaypoint; import baritone.api.cache.Waypoint; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalBlock; import baritone.api.utils.BetterBlockPos; import baritone.api.utils.command.Command; import baritone.api.utils.command.datatypes.ForWaypoints; import baritone.api.utils.command.datatypes.RelativeBlockPos; import baritone.api.utils.command.exception.CommandInvalidStateException; import baritone.api.utils.command.exception.CommandInvalidTypeException; import baritone.api.utils.command.helpers.arguments.ArgConsumer; import baritone.api.utils.command.helpers.pagination.Paginator; import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.event.ClickEvent; import net.minecraft.util.text.event.HoverEvent; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; import static baritone.api.utils.command.BaritoneChatControl.FORCE_COMMAND_PREFIX; import static java.util.Arrays.asList; public class WaypointsCommand extends Command { public WaypointsCommand() { super(asList("waypoints", "waypoint", "wp")); } @Override protected void executed(String label, ArgConsumer args, Settings settings) { Action action = args.has() ? Action.getByName(args.getString()) : Action.LIST; if (action == null) { throw new CommandInvalidTypeException(args.consumed(), "an action"); } BiFunction toComponent = (waypoint, _action) -> { ITextComponent component = new TextComponentString(""); ITextComponent tagComponent = new TextComponentString(waypoint.getTag().name() + " "); tagComponent.getStyle().setColor(TextFormatting.GRAY); String name = waypoint.getName(); ITextComponent nameComponent = new TextComponentString(!name.isEmpty() ? name : ""); nameComponent.getStyle().setColor(!name.isEmpty() ? TextFormatting.GRAY : TextFormatting.DARK_GRAY); ITextComponent timestamp = new TextComponentString(" @ " + new Date(waypoint.getCreationTimestamp())); timestamp.getStyle().setColor(TextFormatting.DARK_GRAY); component.appendSibling(tagComponent); component.appendSibling(nameComponent); component.appendSibling(timestamp); component.getStyle() .setHoverEvent(new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TextComponentString("Click to select") )) .setClickEvent(new ClickEvent( ClickEvent.Action.RUN_COMMAND, String.format( "%s%s %s %s @ %d", FORCE_COMMAND_PREFIX, label, _action.names[0], waypoint.getTag().getName(), waypoint.getCreationTimestamp() )) ); return component; }; Function transform = waypoint -> toComponent.apply(waypoint, action == Action.LIST ? Action.INFO : action); if (action == Action.LIST) { IWaypoint.Tag tag = args.has() ? IWaypoint.Tag.getByName(args.peekString()) : null; if (tag != null) { args.get(); } IWaypoint[] waypoints = tag != null ? ForWaypoints.getWaypointsByTag(tag) : ForWaypoints.getWaypoints(); if (waypoints.length > 0) { args.requireMax(1); Paginator.paginate( args, waypoints, () -> logDirect( tag != null ? String.format("All waypoints by tag %s:", tag.name()) : "All waypoints:" ), transform, String.format( "%s%s %s%s", FORCE_COMMAND_PREFIX, label, action.names[0], tag != null ? " " + tag.getName() : "" ) ); } else { args.requireMax(0); throw new CommandInvalidStateException( tag != null ? "No waypoints found by that tag" : "No waypoints found" ); } } else if (action == Action.SAVE) { IWaypoint.Tag tag = IWaypoint.Tag.getByName(args.getString()); if (tag == null) { throw new CommandInvalidStateException(String.format("'%s' is not a tag ", args.consumedString())); } String name = args.has() ? args.getString() : ""; BetterBlockPos pos = args.has() ? args.getDatatypePost(RelativeBlockPos.class, ctx.playerFeet()) : ctx.playerFeet(); args.requireMax(0); IWaypoint waypoint = new Waypoint(name, tag, pos); ForWaypoints.waypoints().addWaypoint(waypoint); ITextComponent component = new TextComponentString("Waypoint added: "); component.getStyle().setColor(TextFormatting.GRAY); component.appendSibling(toComponent.apply(waypoint, Action.INFO)); logDirect(component); } else if (action == Action.CLEAR) { args.requireMax(1); IWaypoint.Tag tag = IWaypoint.Tag.getByName(args.getString()); IWaypoint[] waypoints = ForWaypoints.getWaypointsByTag(tag); for (IWaypoint waypoint : waypoints) { ForWaypoints.waypoints().removeWaypoint(waypoint); } logDirect(String.format("Cleared %d waypoints", waypoints.length)); } else { IWaypoint[] waypoints = args.getDatatypeFor(ForWaypoints.class); IWaypoint waypoint = null; if (args.has() && args.peekString().equals("@")) { args.requireExactly(2); args.get(); long timestamp = args.getAs(Long.class); for (IWaypoint iWaypoint : waypoints) { if (iWaypoint.getCreationTimestamp() == timestamp) { waypoint = iWaypoint; break; } } if (waypoint == null) { throw new CommandInvalidStateException("Timestamp was specified but no waypoint was found"); } } else { switch (waypoints.length) { case 0: throw new CommandInvalidStateException("No waypoints found"); case 1: waypoint = waypoints[0]; } } if (waypoint == null) { args.requireMax(1); Paginator.paginate( args, waypoints, () -> logDirect("Multiple waypoints were found:"), transform, String.format( "%s%s %s %s", FORCE_COMMAND_PREFIX, label, action.names[0], args.consumedString() ) ); } else { if (action == Action.INFO) { logDirect(transform.apply(waypoint)); logDirect(String.format("Position: %s", waypoint.getLocation())); ITextComponent deleteComponent = new TextComponentString("Click to delete this waypoint"); deleteComponent.getStyle().setClickEvent(new ClickEvent( ClickEvent.Action.RUN_COMMAND, String.format( "%s%s delete %s @ %d", FORCE_COMMAND_PREFIX, label, waypoint.getTag().getName(), waypoint.getCreationTimestamp() ) )); ITextComponent goalComponent = new TextComponentString("Click to set goal to this waypoint"); goalComponent.getStyle().setClickEvent(new ClickEvent( ClickEvent.Action.RUN_COMMAND, String.format( "%s%s goal %s @ %d", FORCE_COMMAND_PREFIX, label, waypoint.getTag().getName(), waypoint.getCreationTimestamp() ) )); ITextComponent backComponent = new TextComponentString("Click to return to the waypoints list"); backComponent.getStyle().setClickEvent(new ClickEvent( ClickEvent.Action.RUN_COMMAND, String.format( "%s%s list", FORCE_COMMAND_PREFIX, label ) )); logDirect(deleteComponent); logDirect(goalComponent); logDirect(backComponent); } else if (action == Action.DELETE) { ForWaypoints.waypoints().removeWaypoint(waypoint); logDirect("That waypoint has successfully been deleted"); } else if (action == Action.GOAL) { Goal goal = new GoalBlock(waypoint.getLocation()); baritone.getCustomGoalProcess().setGoal(goal); logDirect(String.format("Goal: %s", goal)); } } } } @Override protected Stream tabCompleted(String label, ArgConsumer args, Settings settings) { if (args.has()) { if (args.hasExactlyOne()) { return new TabCompleteHelper() .append(Action.getAllNames()) .sortAlphabetically() .filterPrefix(args.getString()) .stream(); } else { Action action = Action.getByName(args.getString()); if (args.hasExactlyOne()) { if (action == Action.LIST || action == Action.SAVE || action == Action.CLEAR) { return new TabCompleteHelper() .append(IWaypoint.Tag.getAllNames()) .sortAlphabetically() .filterPrefix(args.getString()) .stream(); } else { return args.tabCompleteDatatype(ForWaypoints.class); } } else if (args.has(3) && action == Action.SAVE) { args.get(); args.get(); return args.tabCompleteDatatype(RelativeBlockPos.class); } } } return Stream.empty(); } @Override public String getShortDesc() { return "Manage waypoints"; } @Override public List getLongDesc() { return asList( "The waypoint command allows you to manage Baritone's waypoints.", "", "Waypoints can be used to mark positions for later. Waypoints are each given a tag and an optional name.", "", "Note that the info, delete, and goal commands let you specify a waypoint by tag. If there is more than one waypoint with a certain tag, then they will let you select which waypoint you mean.", "", "Usage:", "> wp [l/list] - List all waypoints.", "> wp - Save your current position as an unnamed waypoint with the specified tag.", "> wp - Save the waypoint with the specified name.", "> wp - Save the waypoint with the specified name and position.", "> wp - Show info on a waypoint by tag.", "> wp - Delete a waypoint by tag.", "> wp - Set a goal to a waypoint by tag." ); } private enum Action { LIST("list", "get", "l"), CLEAR("clear", "c"), SAVE("save", "s"), INFO("info", "show", "i"), DELETE("delete", "d"), GOAL("goal", "goto", "g"); private final String[] names; Action(String... names) { this.names = names; } public static Action getByName(String name) { for (Action action : Action.values()) { for (String alias : action.names) { if (alias.equalsIgnoreCase(name)) { return action; } } } return null; } public static String[] getAllNames() { Set names = new HashSet<>(); for (Action action : Action.values()) { names.addAll(asList(action.names)); } return names.toArray(new String[0]); } } }