commit
b8c8b1eb69
2
.gitignore
vendored
2
.gitignore
vendored
@ -14,6 +14,8 @@ classes/
|
|||||||
# IntelliJ Files
|
# IntelliJ Files
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
/logs/
|
/logs/
|
||||||
|
|
||||||
# Copyright Files
|
# Copyright Files
|
||||||
|
@ -34,12 +34,12 @@ public final class BaritoneAPI {
|
|||||||
private static final Settings settings;
|
private static final Settings settings;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
settings = new Settings();
|
||||||
|
SettingsUtil.readAndApply(settings);
|
||||||
|
|
||||||
ServiceLoader<IBaritoneProvider> baritoneLoader = ServiceLoader.load(IBaritoneProvider.class);
|
ServiceLoader<IBaritoneProvider> baritoneLoader = ServiceLoader.load(IBaritoneProvider.class);
|
||||||
Iterator<IBaritoneProvider> instances = baritoneLoader.iterator();
|
Iterator<IBaritoneProvider> instances = baritoneLoader.iterator();
|
||||||
provider = instances.next();
|
provider = instances.next();
|
||||||
|
|
||||||
settings = new Settings();
|
|
||||||
SettingsUtil.readAndApply(settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IBaritoneProvider getProvider() {
|
public static IBaritoneProvider getProvider() {
|
||||||
|
@ -23,8 +23,10 @@ import baritone.api.cache.IWorldProvider;
|
|||||||
import baritone.api.event.listener.IEventBus;
|
import baritone.api.event.listener.IEventBus;
|
||||||
import baritone.api.pathing.calc.IPathingControlManager;
|
import baritone.api.pathing.calc.IPathingControlManager;
|
||||||
import baritone.api.process.*;
|
import baritone.api.process.*;
|
||||||
|
import baritone.api.selection.ISelectionManager;
|
||||||
import baritone.api.utils.IInputOverrideHandler;
|
import baritone.api.utils.IInputOverrideHandler;
|
||||||
import baritone.api.utils.IPlayerContext;
|
import baritone.api.utils.IPlayerContext;
|
||||||
|
import baritone.api.utils.command.manager.ICommandManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Brady
|
* @author Brady
|
||||||
@ -32,15 +34,6 @@ import baritone.api.utils.IPlayerContext;
|
|||||||
*/
|
*/
|
||||||
public interface IBaritone {
|
public interface IBaritone {
|
||||||
|
|
||||||
/**
|
|
||||||
* Call as soon as Minecraft is ready, initializes all of the processes, behaviors, etc. This will
|
|
||||||
* only effectively be ran once, any additional calls are redundant because the initialization state
|
|
||||||
* is saved.
|
|
||||||
* <p>
|
|
||||||
* Or whenever your overeager utility client wants.
|
|
||||||
*/
|
|
||||||
void init();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The {@link IPathingBehavior} instance
|
* @return The {@link IPathingBehavior} instance
|
||||||
* @see IPathingBehavior
|
* @see IPathingBehavior
|
||||||
@ -128,6 +121,18 @@ public interface IBaritone {
|
|||||||
*/
|
*/
|
||||||
IEventBus getGameEventHandler();
|
IEventBus getGameEventHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link ISelectionManager} instance
|
||||||
|
* @see ISelectionManager
|
||||||
|
*/
|
||||||
|
ISelectionManager getSelectionManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link ICommandManager} instance
|
||||||
|
* @see ICommandManager
|
||||||
|
*/
|
||||||
|
ICommandManager getCommandManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open click
|
* Open click
|
||||||
*/
|
*/
|
||||||
|
@ -30,8 +30,8 @@ import java.awt.*;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -495,15 +495,20 @@ public final class Settings {
|
|||||||
public final Setting<Boolean> chatControl = new Setting<>(true);
|
public final Setting<Boolean> chatControl = new Setting<>(true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A second override over chatControl to force it on
|
* Some clients like Impact try to force chatControl to off, so here's a second setting to do it anyway
|
||||||
*/
|
*/
|
||||||
public final Setting<Boolean> removePrefix = new Setting<>(false);
|
public final Setting<Boolean> chatControlAnyway = new Setting<>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the path
|
* Render the path
|
||||||
*/
|
*/
|
||||||
public final Setting<Boolean> renderPath = new Setting<>(true);
|
public final Setting<Boolean> renderPath = new Setting<>(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the path as a line instead of a frickin thingy
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> renderPathAsLine = new Setting<>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the goal
|
* Render the goal
|
||||||
*/
|
*/
|
||||||
@ -604,21 +609,41 @@ public final class Settings {
|
|||||||
public final Setting<Float> cachedChunksOpacity = new Setting<>(0.5f);
|
public final Setting<Float> cachedChunksOpacity = new Setting<>(0.5f);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not to use the "#" command prefix
|
* Whether or not to allow you to run Baritone commands with the prefix
|
||||||
*/
|
*/
|
||||||
public final Setting<Boolean> prefixControl = new Setting<>(true);
|
public final Setting<Boolean> prefixControl = new Setting<>(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command prefix for chat control
|
||||||
|
*/
|
||||||
|
public final Setting<String> prefix = new Setting<>("#");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use a short Baritone prefix [B] instead of [Baritone] when logging to chat
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> shortBaritonePrefix = new Setting<>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Echo commands to chat when they are run
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> echoCommands = new Setting<>(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Censor coordinates in goals and block positions
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> censorCoordinates = new Setting<>(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Censor arguments to ran commands, to hide, for example, coordinates to #goal
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> censorRanCommands = new Setting<>(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Always prefer silk touch tools over regular tools. This will not sacrifice speed, but it will always prefer silk
|
* Always prefer silk touch tools over regular tools. This will not sacrifice speed, but it will always prefer silk
|
||||||
* touch tools over other tools of the same speed. This includes always choosing ANY silk touch tool over your hand.
|
* touch tools over other tools of the same speed. This includes always choosing ANY silk touch tool over your hand.
|
||||||
*/
|
*/
|
||||||
public final Setting<Boolean> preferSilkTouch = new Setting<>(false);
|
public final Setting<Boolean> preferSilkTouch = new Setting<>(false);
|
||||||
|
|
||||||
/*
|
|
||||||
* Censor coordinates in goals and block positions
|
|
||||||
*/
|
|
||||||
public final Setting<Boolean> censorCoordinates = new Setting<>(false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Don't stop walking forward when you need to break blocks in your way
|
* Don't stop walking forward when you need to break blocks in your way
|
||||||
*/
|
*/
|
||||||
@ -938,6 +963,51 @@ public final class Settings {
|
|||||||
*/
|
*/
|
||||||
public final Setting<Color> colorGoalBox = new Setting<>(Color.GREEN);
|
public final Setting<Color> colorGoalBox = new Setting<>(Color.GREEN);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of the goal box when it's inverted
|
||||||
|
*/
|
||||||
|
public final Setting<Color> colorInvertedGoalBox = new Setting<>(Color.RED);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of all selections
|
||||||
|
*/
|
||||||
|
public final Setting<Color> colorSelection = new Setting<>(Color.CYAN);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of the selection pos 1
|
||||||
|
*/
|
||||||
|
public final Setting<Color> colorSelectionPos1 = new Setting<>(Color.BLACK);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of the selection pos 2
|
||||||
|
*/
|
||||||
|
public final Setting<Color> colorSelectionPos2 = new Setting<>(Color.ORANGE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opacity of the selection. 0 is completely transparent, 1 is completely opaque
|
||||||
|
*/
|
||||||
|
public final Setting<Float> selectionOpacity = new Setting<>(.5f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Line width of the goal when rendered, in pixels
|
||||||
|
*/
|
||||||
|
public final Setting<Float> selectionLineWidth = new Setting<>(2F);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render selections
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> renderSelection = new Setting<>(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore depth when rendering selections
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> renderSelectionIgnoreDepth = new Setting<>(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render selection corners
|
||||||
|
*/
|
||||||
|
public final Setting<Boolean> renderSelectionCorners = new Setting<>(true);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of lowercase setting field names to their respective setting
|
* A map of lowercase setting field names to their respective setting
|
||||||
@ -952,6 +1022,7 @@ public final class Settings {
|
|||||||
public final Map<Setting<?>, Type> settingTypes;
|
public final Map<Setting<?>, Type> settingTypes;
|
||||||
|
|
||||||
public final class Setting<T> {
|
public final class Setting<T> {
|
||||||
|
|
||||||
public T value;
|
public T value;
|
||||||
public final T defaultValue;
|
public final T defaultValue;
|
||||||
private String name;
|
private String name;
|
||||||
|
25
src/api/java/baritone/api/accessor/IGuiScreen.java
Normal file
25
src/api/java/baritone/api/accessor/IGuiScreen.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.accessor;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public interface IGuiScreen {
|
||||||
|
|
||||||
|
void openLink(URI url);
|
||||||
|
}
|
23
src/api/java/baritone/api/accessor/IItemStack.java
Normal file
23
src/api/java/baritone/api/accessor/IItemStack.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.accessor;
|
||||||
|
|
||||||
|
public interface IItemStack {
|
||||||
|
|
||||||
|
int getBaritoneHash();
|
||||||
|
}
|
@ -64,9 +64,17 @@ public interface IPathingBehavior extends IBehavior {
|
|||||||
Goal getGoal();
|
Goal getGoal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether or not a path is currently being executed.
|
* @return Whether or not a path is currently being executed. This will be false if there's currently a pause.
|
||||||
|
* @see #hasPath()
|
||||||
*/
|
*/
|
||||||
default boolean isPathing() {
|
boolean isPathing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If there is a current path. Note that the path is not necessarily being executed, for example when there
|
||||||
|
* is a pause in effect.
|
||||||
|
* @see #isPathing()
|
||||||
|
*/
|
||||||
|
default boolean hasPath() {
|
||||||
return getCurrent() != null;
|
return getCurrent() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
src/api/java/baritone/api/cache/IWaypoint.java
vendored
51
src/api/java/baritone/api/cache/IWaypoint.java
vendored
@ -17,12 +17,9 @@
|
|||||||
|
|
||||||
package baritone.api.cache;
|
package baritone.api.cache;
|
||||||
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
import baritone.api.utils.BetterBlockPos;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A marker for a position in the world.
|
* A marker for a position in the world.
|
||||||
@ -60,7 +57,7 @@ public interface IWaypoint {
|
|||||||
*
|
*
|
||||||
* @return The block position of this waypoint
|
* @return The block position of this waypoint
|
||||||
*/
|
*/
|
||||||
BlockPos getLocation();
|
BetterBlockPos getLocation();
|
||||||
|
|
||||||
enum Tag {
|
enum Tag {
|
||||||
|
|
||||||
@ -92,20 +89,48 @@ public interface IWaypoint {
|
|||||||
/**
|
/**
|
||||||
* The names for the tag, anything that the tag can be referred to as.
|
* The names for the tag, anything that the tag can be referred to as.
|
||||||
*/
|
*/
|
||||||
private final String[] names;
|
public final String[] names;
|
||||||
|
|
||||||
Tag(String... names) {
|
Tag(String... names) {
|
||||||
this.names = names;
|
this.names = names;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a tag from one of the names that could be used to identify said tag.
|
* @return A name that can be passed to {@link #getByName(String)} to retrieve this tag
|
||||||
*
|
|
||||||
* @param name The name of the tag
|
|
||||||
* @return The tag, if one is found, otherwise, {@code null}
|
|
||||||
*/
|
*/
|
||||||
public static Tag fromString(String name) {
|
public String getName() {
|
||||||
return TAG_LIST.stream().filter(tag -> ArrayUtils.contains(tag.names, name.toLowerCase())).findFirst().orElse(null);
|
return names[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a tag by one of its names.
|
||||||
|
*
|
||||||
|
* @param name The name to search for.
|
||||||
|
* @return The tag, if found, or null.
|
||||||
|
*/
|
||||||
|
public static Tag getByName(String name) {
|
||||||
|
for (Tag action : Tag.values()) {
|
||||||
|
for (String alias : action.names) {
|
||||||
|
if (alias.equalsIgnoreCase(name)) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return All tag names.
|
||||||
|
*/
|
||||||
|
public static String[] getAllNames() {
|
||||||
|
Set<String> names = new HashSet<>();
|
||||||
|
|
||||||
|
for (Tag tag : Tag.values()) {
|
||||||
|
names.addAll(Arrays.asList(tag.names));
|
||||||
|
}
|
||||||
|
|
||||||
|
return names.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package baritone.api.cache;
|
package baritone.api.cache;
|
||||||
|
|
||||||
|
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||||
import baritone.api.utils.IPlayerContext;
|
import baritone.api.utils.IPlayerContext;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@ -33,28 +34,53 @@ public interface IWorldScanner {
|
|||||||
/**
|
/**
|
||||||
* Scans the world, up to the specified max chunk radius, for the specified blocks.
|
* Scans the world, up to the specified max chunk radius, for the specified blocks.
|
||||||
*
|
*
|
||||||
* @param ctx The {@link IPlayerContext} containing player and world info that the
|
* @param ctx The {@link IPlayerContext} containing player and world info that the scan is based upon
|
||||||
* scan is based upon
|
* @param filter The blocks to scan for
|
||||||
* @param blocks The blocks to scan for
|
|
||||||
* @param max The maximum number of blocks to scan before cutoff
|
* @param max The maximum number of blocks to scan before cutoff
|
||||||
* @param yLevelThreshold If a block is found within this Y level, the current result will be
|
* @param yLevelThreshold If a block is found within this Y level, the current result will be returned, if the value
|
||||||
* returned, if the value is negative, then this condition doesn't apply.
|
* is negative, then this condition doesn't apply.
|
||||||
* @param maxSearchRadius The maximum chunk search radius
|
* @param maxSearchRadius The maximum chunk search radius
|
||||||
* @return The matching block positions
|
* @return The matching block positions
|
||||||
*/
|
*/
|
||||||
List<BlockPos> scanChunkRadius(IPlayerContext ctx, List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius);
|
List<BlockPos> scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius);
|
||||||
|
|
||||||
|
default List<BlockPos> scanChunkRadius(IPlayerContext ctx, List<Block> filter, int max, int yLevelThreshold, int maxSearchRadius) {
|
||||||
|
return scanChunkRadius(ctx, new BlockOptionalMetaLookup(filter.toArray(new Block[0])), max, yLevelThreshold, maxSearchRadius);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans a single chunk for the specified blocks.
|
* Scans a single chunk for the specified blocks.
|
||||||
*
|
*
|
||||||
* @param ctx The {@link IPlayerContext} containing player and world info that the
|
* @param ctx The {@link IPlayerContext} containing player and world info that the scan is based upon
|
||||||
* scan is based upon
|
* @param filter The blocks to scan for
|
||||||
|
* @param pos The position of the target chunk
|
||||||
|
* @param max The maximum number of blocks to scan before cutoff
|
||||||
|
* @param yLevelThreshold If a block is found within this Y level, the current result will be returned, if the value
|
||||||
|
* is negative, then this condition doesn't apply.
|
||||||
|
* @return The matching block positions
|
||||||
|
*/
|
||||||
|
List<BlockPos> scanChunk(IPlayerContext ctx, BlockOptionalMetaLookup filter, ChunkPos pos, int max, int yLevelThreshold);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a single chunk for the specified blocks.
|
||||||
|
*
|
||||||
|
* @param ctx The {@link IPlayerContext} containing player and world info that the scan is based upon
|
||||||
* @param blocks The blocks to scan for
|
* @param blocks The blocks to scan for
|
||||||
* @param pos The position of the target chunk
|
* @param pos The position of the target chunk
|
||||||
* @param max The maximum number of blocks to scan before cutoff
|
* @param max The maximum number of blocks to scan before cutoff
|
||||||
* @param yLevelThreshold If a block is found within this Y level, the current result will be
|
* @param yLevelThreshold If a block is found within this Y level, the current result will be returned, if the value
|
||||||
* returned, if the value is negative, then this condition doesn't apply.
|
* is negative, then this condition doesn't apply.
|
||||||
* @return The matching block positions
|
* @return The matching block positions
|
||||||
*/
|
*/
|
||||||
List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold);
|
default List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold) {
|
||||||
|
return scanChunk(ctx, new BlockOptionalMetaLookup(blocks), pos, max, yLevelThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repacks 40 chunks around the player.
|
||||||
|
*
|
||||||
|
* @param ctx The player context for that player.
|
||||||
|
* @return The number of chunks queued for repacking.
|
||||||
|
*/
|
||||||
|
int repack(IPlayerContext ctx);
|
||||||
}
|
}
|
||||||
|
19
src/api/java/baritone/api/cache/Waypoint.java
vendored
19
src/api/java/baritone/api/cache/Waypoint.java
vendored
@ -18,7 +18,6 @@
|
|||||||
package baritone.api.cache;
|
package baritone.api.cache;
|
||||||
|
|
||||||
import baritone.api.utils.BetterBlockPos;
|
import baritone.api.utils.BetterBlockPos;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -32,9 +31,9 @@ public class Waypoint implements IWaypoint {
|
|||||||
private final String name;
|
private final String name;
|
||||||
private final Tag tag;
|
private final Tag tag;
|
||||||
private final long creationTimestamp;
|
private final long creationTimestamp;
|
||||||
private final BlockPos location;
|
private final BetterBlockPos location;
|
||||||
|
|
||||||
public Waypoint(String name, Tag tag, BlockPos location) {
|
public Waypoint(String name, Tag tag, BetterBlockPos location) {
|
||||||
this(name, tag, location, System.currentTimeMillis());
|
this(name, tag, location, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ public class Waypoint implements IWaypoint {
|
|||||||
* @param location The waypoint location
|
* @param location The waypoint location
|
||||||
* @param creationTimestamp When the waypoint was created
|
* @param creationTimestamp When the waypoint was created
|
||||||
*/
|
*/
|
||||||
public Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) {
|
public Waypoint(String name, Tag tag, BetterBlockPos location, long creationTimestamp) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.location = location;
|
this.location = location;
|
||||||
@ -56,7 +55,7 @@ public class Waypoint implements IWaypoint {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return name.hashCode() + tag.hashCode() + location.hashCode(); //lol
|
return name.hashCode() ^ tag.hashCode() ^ location.hashCode() ^ Long.hashCode(creationTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -75,17 +74,17 @@ public class Waypoint implements IWaypoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockPos getLocation() {
|
public BetterBlockPos getLocation() {
|
||||||
return this.location;
|
return this.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"%s %s %s",
|
"%s %s %s",
|
||||||
name,
|
name,
|
||||||
BetterBlockPos.from(location).toString(),
|
BetterBlockPos.from(location).toString(),
|
||||||
new Date(creationTimestamp).toString()
|
new Date(creationTimestamp).toString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
src/api/java/baritone/api/event/events/TabCompleteEvent.java
Normal file
53
src/api/java/baritone/api/event/events/TabCompleteEvent.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.event.events;
|
||||||
|
|
||||||
|
import baritone.api.event.events.type.Cancellable;
|
||||||
|
import baritone.api.event.events.type.Overrideable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LoganDark
|
||||||
|
*/
|
||||||
|
public abstract class TabCompleteEvent extends Cancellable {
|
||||||
|
|
||||||
|
public final Overrideable<String> prefix;
|
||||||
|
public final Overrideable<String[]> completions;
|
||||||
|
|
||||||
|
TabCompleteEvent(String prefix, String[] completions) {
|
||||||
|
this.prefix = new Overrideable<>(prefix);
|
||||||
|
this.completions = new Overrideable<>(completions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasModified() {
|
||||||
|
return prefix.wasModified() || completions.wasModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Pre extends TabCompleteEvent {
|
||||||
|
|
||||||
|
public Pre(String prefix) {
|
||||||
|
super(prefix, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Post extends TabCompleteEvent {
|
||||||
|
|
||||||
|
public Post(String prefix, String[] completions) {
|
||||||
|
super(prefix, completions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.event.events.type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author LoganDark
|
||||||
|
*/
|
||||||
|
public class Overrideable<T> {
|
||||||
|
|
||||||
|
private T value;
|
||||||
|
private boolean modified;
|
||||||
|
|
||||||
|
public Overrideable(T current) {
|
||||||
|
value = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(T newValue) {
|
||||||
|
value = newValue;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasModified() {
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"Overrideable{modified=%b,value=%s}",
|
||||||
|
modified,
|
||||||
|
value.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,12 @@ public interface AbstractGameEventListener extends IGameEventListener {
|
|||||||
@Override
|
@Override
|
||||||
default void onSendChatMessage(ChatEvent event) {}
|
default void onSendChatMessage(ChatEvent event) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void onPreTabComplete(TabCompleteEvent.Pre event) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void onPostTabComplete(TabCompleteEvent.Post event) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void onChunkEvent(ChunkEvent event) {}
|
default void onChunkEvent(ChunkEvent event) {}
|
||||||
|
|
||||||
|
@ -57,6 +57,21 @@ public interface IGameEventListener {
|
|||||||
*/
|
*/
|
||||||
void onSendChatMessage(ChatEvent event);
|
void onSendChatMessage(ChatEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs whenever the client player tries to tab complete in chat.
|
||||||
|
*
|
||||||
|
* @param event The event
|
||||||
|
*/
|
||||||
|
void onPreTabComplete(TabCompleteEvent.Pre event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs whenever the client player tries to tab complete in chat once completions have been recieved from the
|
||||||
|
* server. This will only be called if the {@link TabCompleteEvent#cancel()} method was not called.
|
||||||
|
*
|
||||||
|
* @param event The event
|
||||||
|
*/
|
||||||
|
void onPostTabComplete(TabCompleteEvent.Post event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs before and after whenever a chunk is either loaded, unloaded, or populated.
|
* Runs before and after whenever a chunk is either loaded, unloaded, or populated.
|
||||||
*
|
*
|
||||||
|
@ -69,10 +69,10 @@ public class GoalBlock implements Goal, IGoalRenderPos {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalBlock{x=%s,y=%s,z=%s}",
|
"GoalBlock{x=%s,y=%s,z=%s}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(y),
|
SettingsUtil.maybeCensor(y),
|
||||||
SettingsUtil.maybeCensor(z)
|
SettingsUtil.maybeCensor(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +63,10 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalGetToBlock{x=%s,y=%s,z=%s}",
|
"GoalGetToBlock{x=%s,y=%s,z=%s}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(y),
|
SettingsUtil.maybeCensor(y),
|
||||||
SettingsUtil.maybeCensor(z)
|
SettingsUtil.maybeCensor(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
src/api/java/baritone/api/pathing/goals/GoalInverted.java
Normal file
52
src/api/java/baritone/api/pathing/goals/GoalInverted.java
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.pathing.goals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invert any goal.
|
||||||
|
* <p>
|
||||||
|
* In the old chat control system, #invert just tried to pick a {@link GoalRunAway} that <i>effectively</i> inverted the
|
||||||
|
* current goal. This goal just reverses the heuristic to act as a TRUE invert. Inverting a Y level? Baritone tries to
|
||||||
|
* get away from that Y level. Inverting a GoalBlock? Baritone will try to make distance whether it's in the X, Y or Z
|
||||||
|
* directions. And of course, you can always invert a GoalXZ.
|
||||||
|
*
|
||||||
|
* @author LoganDark
|
||||||
|
*/
|
||||||
|
public class GoalInverted implements Goal {
|
||||||
|
|
||||||
|
public final Goal origin;
|
||||||
|
|
||||||
|
public GoalInverted(Goal origin) {
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInGoal(int x, int y, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double heuristic(int x, int y, int z) {
|
||||||
|
return -origin.heuristic(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("GoalInverted{%s}", origin.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import baritone.api.utils.interfaces.IGoalRenderPos;
|
|||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
public class GoalNear implements Goal, IGoalRenderPos {
|
public class GoalNear implements Goal, IGoalRenderPos {
|
||||||
|
|
||||||
private final int x;
|
private final int x;
|
||||||
private final int y;
|
private final int y;
|
||||||
private final int z;
|
private final int z;
|
||||||
@ -58,11 +59,11 @@ public class GoalNear implements Goal, IGoalRenderPos {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalNear{x=%s, y=%s, z=%s, rangeSq=%d}",
|
"GoalNear{x=%s, y=%s, z=%s, rangeSq=%d}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(y),
|
SettingsUtil.maybeCensor(y),
|
||||||
SettingsUtil.maybeCensor(z),
|
SettingsUtil.maybeCensor(z),
|
||||||
rangeSq
|
rangeSq
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,9 @@ public class GoalRunAway implements Goal {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
if (maintainY != null) {
|
if (maintainY != null) {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalRunAwayFromMaintainY y=%s, %s",
|
"GoalRunAwayFromMaintainY y=%s, %s",
|
||||||
SettingsUtil.maybeCensor(maintainY),
|
SettingsUtil.maybeCensor(maintainY),
|
||||||
Arrays.asList(from)
|
Arrays.asList(from)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return "GoalRunAwayFrom" + Arrays.asList(from);
|
return "GoalRunAwayFrom" + Arrays.asList(from);
|
||||||
|
@ -25,6 +25,7 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
* Dig a tunnel in a certain direction, but if you have to deviate from the path, go back to where you started
|
* Dig a tunnel in a certain direction, but if you have to deviate from the path, go back to where you started
|
||||||
*/
|
*/
|
||||||
public class GoalStrictDirection implements Goal {
|
public class GoalStrictDirection implements Goal {
|
||||||
|
|
||||||
public final int x;
|
public final int x;
|
||||||
public final int y;
|
public final int y;
|
||||||
public final int z;
|
public final int z;
|
||||||
@ -66,12 +67,12 @@ public class GoalStrictDirection implements Goal {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalStrictDirection{x=%s, y=%s, z=%s, dx=%s, dz=%s}",
|
"GoalStrictDirection{x=%s, y=%s, z=%s, dx=%s, dz=%s}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(y),
|
SettingsUtil.maybeCensor(y),
|
||||||
SettingsUtil.maybeCensor(z),
|
SettingsUtil.maybeCensor(z),
|
||||||
SettingsUtil.maybeCensor(dx),
|
SettingsUtil.maybeCensor(dx),
|
||||||
SettingsUtil.maybeCensor(dz)
|
SettingsUtil.maybeCensor(dz)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,10 +75,10 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalTwoBlocks{x=%s,y=%s,z=%s}",
|
"GoalTwoBlocks{x=%s,y=%s,z=%s}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(y),
|
SettingsUtil.maybeCensor(y),
|
||||||
SettingsUtil.maybeCensor(z)
|
SettingsUtil.maybeCensor(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package baritone.api.pathing.goals;
|
package baritone.api.pathing.goals;
|
||||||
|
|
||||||
import baritone.api.BaritoneAPI;
|
import baritone.api.BaritoneAPI;
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
import baritone.api.utils.SettingsUtil;
|
import baritone.api.utils.SettingsUtil;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
@ -46,6 +47,11 @@ public class GoalXZ implements Goal {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GoalXZ(BetterBlockPos pos) {
|
||||||
|
this.x = pos.x;
|
||||||
|
this.z = pos.z;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInGoal(int x, int y, int z) {
|
public boolean isInGoal(int x, int y, int z) {
|
||||||
return x == this.x && z == this.z;
|
return x == this.x && z == this.z;
|
||||||
@ -61,9 +67,9 @@ public class GoalXZ implements Goal {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalXZ{x=%s,z=%s}",
|
"GoalXZ{x=%s,z=%s}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(z)
|
SettingsUtil.maybeCensor(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +98,7 @@ public class GoalXZ implements Goal {
|
|||||||
float theta = (float) Math.toRadians(yaw);
|
float theta = (float) Math.toRadians(yaw);
|
||||||
double x = origin.x - MathHelper.sin(theta) * distance;
|
double x = origin.x - MathHelper.sin(theta) * distance;
|
||||||
double z = origin.z + MathHelper.cos(theta) * distance;
|
double z = origin.z + MathHelper.cos(theta) * distance;
|
||||||
return new GoalXZ((int) x, (int) z);
|
return new GoalXZ(MathHelper.floor(x), MathHelper.floor(z));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getX() {
|
public int getX() {
|
||||||
|
@ -61,8 +61,8 @@ public class GoalYLevel implements Goal, ActionCosts {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"GoalYLevel{y=%s}",
|
"GoalYLevel{y=%s}",
|
||||||
SettingsUtil.maybeCensor(level)
|
SettingsUtil.maybeCensor(level)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,13 @@
|
|||||||
package baritone.api.process;
|
package baritone.api.process;
|
||||||
|
|
||||||
import baritone.api.utils.ISchematic;
|
import baritone.api.utils.ISchematic;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3i;
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Brady
|
* @author Brady
|
||||||
@ -58,7 +60,16 @@ public interface IBuilderProcess extends IBaritoneProcess {
|
|||||||
|
|
||||||
void pause();
|
void pause();
|
||||||
|
|
||||||
|
boolean isPaused();
|
||||||
|
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
void clearArea(BlockPos corner1, BlockPos corner2);
|
void clearArea(BlockPos corner1, BlockPos corner2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A list of block states that are estimated to be placeable by this builder process. You can use this in
|
||||||
|
* schematics, for example, to pick a state that the builder process will be happy with, because any variation will
|
||||||
|
* cause it to give up. This is updated every tick, but only while the builder process is active.
|
||||||
|
*/
|
||||||
|
List<IBlockState> getApproxPlaceable();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package baritone.api.process;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
public interface IExploreProcess extends IBaritoneProcess {
|
public interface IExploreProcess extends IBaritoneProcess {
|
||||||
|
|
||||||
void explore(int centerX, int centerZ);
|
void explore(int centerX, int centerZ);
|
||||||
|
|
||||||
void applyJsonFilter(Path path, boolean invert) throws Exception;
|
void applyJsonFilter(Path path, boolean invert) throws Exception;
|
||||||
|
@ -18,5 +18,6 @@
|
|||||||
package baritone.api.process;
|
package baritone.api.process;
|
||||||
|
|
||||||
public interface IFarmProcess extends IBaritoneProcess {
|
public interface IFarmProcess extends IBaritoneProcess {
|
||||||
|
|
||||||
void farm();
|
void farm();
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,12 @@
|
|||||||
|
|
||||||
package baritone.api.process;
|
package baritone.api.process;
|
||||||
|
|
||||||
|
import baritone.api.utils.BlockOptionalMeta;
|
||||||
|
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Brady
|
* @author Brady
|
||||||
* @since 9/23/2018
|
* @since 9/23/2018
|
||||||
@ -28,9 +32,9 @@ public interface IMineProcess extends IBaritoneProcess {
|
|||||||
/**
|
/**
|
||||||
* Begin to search for and mine the specified blocks until
|
* Begin to search for and mine the specified blocks until
|
||||||
* the number of specified items to get from the blocks that
|
* the number of specified items to get from the blocks that
|
||||||
* are mined. This is based on the first target block to mine.
|
* are mined.
|
||||||
*
|
*
|
||||||
* @param quantity The number of items to get from blocks mined
|
* @param quantity The total number of items to get
|
||||||
* @param blocks The blocks to mine
|
* @param blocks The blocks to mine
|
||||||
*/
|
*/
|
||||||
void mineByName(int quantity, String... blocks);
|
void mineByName(int quantity, String... blocks);
|
||||||
@ -41,9 +45,18 @@ public interface IMineProcess extends IBaritoneProcess {
|
|||||||
* are mined. This is based on the first target block to mine.
|
* are mined. This is based on the first target block to mine.
|
||||||
*
|
*
|
||||||
* @param quantity The number of items to get from blocks mined
|
* @param quantity The number of items to get from blocks mined
|
||||||
* @param blocks The blocks to mine
|
* @param filter The blocks to mine
|
||||||
*/
|
*/
|
||||||
void mine(int quantity, Block... blocks);
|
void mine(int quantity, BlockOptionalMetaLookup filter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin to search for and mine the specified blocks.
|
||||||
|
*
|
||||||
|
* @param filter The blocks to mine
|
||||||
|
*/
|
||||||
|
default void mine(BlockOptionalMetaLookup filter) {
|
||||||
|
mine(0, filter);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin to search for and mine the specified blocks.
|
* Begin to search for and mine the specified blocks.
|
||||||
@ -54,6 +67,38 @@ public interface IMineProcess extends IBaritoneProcess {
|
|||||||
mineByName(0, blocks);
|
mineByName(0, blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin to search for and mine the specified blocks.
|
||||||
|
*
|
||||||
|
* @param boms The blocks to mine
|
||||||
|
*/
|
||||||
|
default void mine(int quantity, BlockOptionalMeta... boms) {
|
||||||
|
mine(quantity, new BlockOptionalMetaLookup(boms));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin to search for and mine the specified blocks.
|
||||||
|
*
|
||||||
|
* @param boms The blocks to mine
|
||||||
|
*/
|
||||||
|
default void mine(BlockOptionalMeta... boms) {
|
||||||
|
mine(0, boms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin to search for and mine the specified blocks.
|
||||||
|
*
|
||||||
|
* @param quantity The total number of items to get
|
||||||
|
* @param blocks The blocks to mine
|
||||||
|
*/
|
||||||
|
default void mine(int quantity, Block... blocks) {
|
||||||
|
mine(quantity, new BlockOptionalMetaLookup(
|
||||||
|
Stream.of(blocks)
|
||||||
|
.map(BlockOptionalMeta::new)
|
||||||
|
.toArray(BlockOptionalMeta[]::new)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begin to search for and mine the specified blocks.
|
* Begin to search for and mine the specified blocks.
|
||||||
*
|
*
|
||||||
|
48
src/api/java/baritone/api/schematic/AbstractSchematic.java
Normal file
48
src/api/java/baritone/api/schematic/AbstractSchematic.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
|
||||||
|
public abstract class AbstractSchematic implements ISchematic {
|
||||||
|
|
||||||
|
protected int x;
|
||||||
|
protected int y;
|
||||||
|
protected int z;
|
||||||
|
|
||||||
|
public AbstractSchematic(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int widthX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int heightY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int lengthZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
}
|
75
src/api/java/baritone/api/schematic/CompositeSchematic.java
Normal file
75
src/api/java/baritone/api/schematic/CompositeSchematic.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CompositeSchematic extends AbstractSchematic {
|
||||||
|
|
||||||
|
private final List<CompositeSchematicEntry> schematics;
|
||||||
|
private CompositeSchematicEntry[] schematicArr;
|
||||||
|
|
||||||
|
private void recalcArr() {
|
||||||
|
schematicArr = schematics.toArray(new CompositeSchematicEntry[0]);
|
||||||
|
for (CompositeSchematicEntry entry : schematicArr) {
|
||||||
|
this.x = Math.max(x, entry.x + entry.schematic.widthX());
|
||||||
|
this.y = Math.max(y, entry.y + entry.schematic.heightY());
|
||||||
|
this.z = Math.max(z, entry.z + entry.schematic.lengthZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompositeSchematic(int x, int y, int z) {
|
||||||
|
super(x, y, z);
|
||||||
|
schematics = new ArrayList<>();
|
||||||
|
recalcArr();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(ISchematic extra, int x, int y, int z) {
|
||||||
|
schematics.add(new CompositeSchematicEntry(extra, x, y, z));
|
||||||
|
recalcArr();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompositeSchematicEntry getSchematic(int x, int y, int z, IBlockState currentState) {
|
||||||
|
for (CompositeSchematicEntry entry : schematicArr) {
|
||||||
|
if (x >= entry.x && y >= entry.y && z >= entry.z &&
|
||||||
|
entry.schematic.inSchematic(x - entry.x, y - entry.y, z - entry.z, currentState)) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inSchematic(int x, int y, int z, IBlockState currentState) {
|
||||||
|
CompositeSchematicEntry entry = getSchematic(x, y, z, currentState);
|
||||||
|
return entry != null && entry.schematic.inSchematic(x - entry.x, y - entry.y, z - entry.z, currentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
||||||
|
CompositeSchematicEntry entry = getSchematic(x, y, z, current);
|
||||||
|
if (entry == null) {
|
||||||
|
throw new IllegalStateException("couldn't find schematic for this position");
|
||||||
|
}
|
||||||
|
return entry.schematic.desiredState(x - entry.x, y - entry.y, z - entry.z, current, approxPlaceable);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
|
||||||
|
public class CompositeSchematicEntry {
|
||||||
|
|
||||||
|
public final ISchematic schematic;
|
||||||
|
public final int x;
|
||||||
|
public final int y;
|
||||||
|
public final int z;
|
||||||
|
|
||||||
|
public CompositeSchematicEntry(ISchematic schematic, int x, int y, int z) {
|
||||||
|
this.schematic = schematic;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
}
|
53
src/api/java/baritone/api/schematic/FillSchematic.java
Normal file
53
src/api/java/baritone/api/schematic/FillSchematic.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.BlockOptionalMeta;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.init.Blocks;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FillSchematic extends AbstractSchematic {
|
||||||
|
|
||||||
|
private final BlockOptionalMeta bom;
|
||||||
|
|
||||||
|
public FillSchematic(int x, int y, int z, BlockOptionalMeta bom) {
|
||||||
|
super(x, y, z);
|
||||||
|
this.bom = bom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockOptionalMeta getBom() {
|
||||||
|
return bom;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
||||||
|
if (bom.matches(current)) {
|
||||||
|
return current;
|
||||||
|
} else if (current.getBlock() != Blocks.AIR) {
|
||||||
|
return Blocks.AIR.getDefaultState();
|
||||||
|
}
|
||||||
|
for (IBlockState placeable : approxPlaceable) {
|
||||||
|
if (bom.matches(placeable)) {
|
||||||
|
return placeable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bom.getAnyBlockState();
|
||||||
|
}
|
||||||
|
}
|
45
src/api/java/baritone/api/schematic/MaskSchematic.java
Normal file
45
src/api/java/baritone/api/schematic/MaskSchematic.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class MaskSchematic extends AbstractSchematic {
|
||||||
|
|
||||||
|
private final ISchematic schematic;
|
||||||
|
|
||||||
|
public MaskSchematic(ISchematic schematic) {
|
||||||
|
super(schematic.widthX(), schematic.heightY(), schematic.lengthZ());
|
||||||
|
this.schematic = schematic;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean partOfMask(int x, int y, int z, IBlockState currentState);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inSchematic(int x, int y, int z, IBlockState currentState) {
|
||||||
|
return schematic.inSchematic(x, y, z, currentState) && partOfMask(x, y, z, currentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
||||||
|
return schematic.desiredState(x, y, z, current, approxPlaceable);
|
||||||
|
}
|
||||||
|
}
|
42
src/api/java/baritone/api/schematic/ReplaceSchematic.java
Normal file
42
src/api/java/baritone/api/schematic/ReplaceSchematic.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
|
||||||
|
public class ReplaceSchematic extends MaskSchematic {
|
||||||
|
|
||||||
|
private final BlockOptionalMetaLookup filter;
|
||||||
|
private final Boolean[][][] cache;
|
||||||
|
|
||||||
|
public ReplaceSchematic(ISchematic schematic, BlockOptionalMetaLookup filter) {
|
||||||
|
super(schematic);
|
||||||
|
this.filter = filter;
|
||||||
|
this.cache = new Boolean[widthX()][heightY()][lengthZ()];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
|
||||||
|
if (cache[x][y][z] == null) {
|
||||||
|
cache[x][y][z] = filter.has(currentState);
|
||||||
|
}
|
||||||
|
return cache[x][y][z];
|
||||||
|
}
|
||||||
|
}
|
33
src/api/java/baritone/api/schematic/ShellSchematic.java
Normal file
33
src/api/java/baritone/api/schematic/ShellSchematic.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
|
||||||
|
public class ShellSchematic extends MaskSchematic {
|
||||||
|
|
||||||
|
public ShellSchematic(ISchematic schematic) {
|
||||||
|
super(schematic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
|
||||||
|
return x == 0 || y == 0 || z == 0 || x == widthX() - 1 || y == heightY() - 1 || z == lengthZ() - 1;
|
||||||
|
}
|
||||||
|
}
|
33
src/api/java/baritone/api/schematic/WallsSchematic.java
Normal file
33
src/api/java/baritone/api/schematic/WallsSchematic.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import baritone.api.utils.ISchematic;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
|
||||||
|
public class WallsSchematic extends MaskSchematic {
|
||||||
|
|
||||||
|
public WallsSchematic(ISchematic schematic) {
|
||||||
|
super(schematic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
|
||||||
|
return x == 0 || z == 0 || x == widthX() - 1 || z == lengthZ() - 1;
|
||||||
|
}
|
||||||
|
}
|
91
src/api/java/baritone/api/selection/ISelection.java
Normal file
91
src/api/java/baritone/api/selection/ISelection.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.selection;
|
||||||
|
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A selection is an immutable object representing the current selection. The selection is commonly used for certain
|
||||||
|
* types of build commands, however it can be used for anything.
|
||||||
|
*/
|
||||||
|
public interface ISelection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The first corner of this selection. This is meant to preserve the user's original first corner.
|
||||||
|
*/
|
||||||
|
BetterBlockPos pos1();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The second corner of this selection. This is meant to preserve the user's original second corner.
|
||||||
|
*/
|
||||||
|
BetterBlockPos pos2();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link BetterBlockPos} with the lowest x, y, and z position in the selection.
|
||||||
|
*/
|
||||||
|
BetterBlockPos min();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The opposite corner from the {@link #min()}.
|
||||||
|
*/
|
||||||
|
BetterBlockPos max();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The size of this ISelection.
|
||||||
|
*/
|
||||||
|
Vec3i size();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return An {@link AxisAlignedBB} encompassing all blocks in this selection.
|
||||||
|
*/
|
||||||
|
AxisAlignedBB aabb();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link ISelection} expanded in the specified direction by the specified number of blocks.
|
||||||
|
*
|
||||||
|
* @param direction The direction to expand the selection.
|
||||||
|
* @param blocks How many blocks to expand it.
|
||||||
|
* @return A new selection, expanded as specified.
|
||||||
|
*/
|
||||||
|
ISelection expand(EnumFacing direction, int blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link ISelection} contracted in the specified direction by the specified number of blocks.
|
||||||
|
* <p>
|
||||||
|
* Note that, for example, if the direction specified is UP, the bottom of the selection will be shifted up. If it
|
||||||
|
* is DOWN, the top of the selection will be shifted down.
|
||||||
|
*
|
||||||
|
* @param direction The direction to contract the selection.
|
||||||
|
* @param blocks How many blocks to contract it.
|
||||||
|
* @return A new selection, contracted as specified.
|
||||||
|
*/
|
||||||
|
ISelection contract(EnumFacing direction, int blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link ISelection} shifted in the specified direction by the specified number of blocks. This moves
|
||||||
|
* the whole selection.
|
||||||
|
*
|
||||||
|
* @param direction The direction to shift the selection.
|
||||||
|
* @param blocks How many blocks to shift it.
|
||||||
|
* @return A new selection, shifted as specified.
|
||||||
|
*/
|
||||||
|
ISelection shift(EnumFacing direction, int blocks);
|
||||||
|
}
|
116
src/api/java/baritone/api/selection/ISelectionManager.java
Normal file
116
src/api/java/baritone/api/selection/ISelectionManager.java
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.selection;
|
||||||
|
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selection manager handles setting Baritone's selections. You can set the selection here, as well as retrieving
|
||||||
|
* the current selection.
|
||||||
|
*/
|
||||||
|
public interface ISelectionManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new selection. The added selection is returned.
|
||||||
|
*
|
||||||
|
* @param selection The new selection to add.
|
||||||
|
*/
|
||||||
|
ISelection addSelection(ISelection selection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new {@link ISelection} constructed from the given block positions. The new selection is returned.
|
||||||
|
*
|
||||||
|
* @param pos1 One corner of the selection
|
||||||
|
* @param pos2 The new corner of the selection
|
||||||
|
*/
|
||||||
|
ISelection addSelection(BetterBlockPos pos1, BetterBlockPos pos2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the selection from the current selections.
|
||||||
|
*
|
||||||
|
* @param selection The selection to remove.
|
||||||
|
* @return The removed selection.
|
||||||
|
*/
|
||||||
|
ISelection removeSelection(ISelection selection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all selections.
|
||||||
|
*
|
||||||
|
* @return The selections that were removed, sorted from oldest to newest..
|
||||||
|
*/
|
||||||
|
ISelection[] removeAllSelections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The current selections, sorted from oldest to newest.
|
||||||
|
*/
|
||||||
|
ISelection[] getSelections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For anything expecting only one selection, this method is provided. However, to enforce multi-selection support,
|
||||||
|
* this method will only return a selection if there is ONLY one.
|
||||||
|
*
|
||||||
|
* @return The only selection, or null if there isn't only one.
|
||||||
|
*/
|
||||||
|
ISelection getOnlySelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will always return the last selection. ONLY use this if you want to, for example, modify the most
|
||||||
|
* recent selection based on user input. ALWAYS use {@link #getOnlySelection()} or, ideally,
|
||||||
|
* {@link #getSelections()} for retrieving the content of selections.
|
||||||
|
*
|
||||||
|
* @return The last selection, or null if it doesn't exist.
|
||||||
|
*/
|
||||||
|
ISelection getLastSelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the specified {@link ISelection} with one expanded in the specified direction by the specified number of
|
||||||
|
* blocks. Returns the new selection.
|
||||||
|
*
|
||||||
|
* @param selection The selection to expand.
|
||||||
|
* @param direction The direction to expand the selection.
|
||||||
|
* @param blocks How many blocks to expand it.
|
||||||
|
* @return The new selection, expanded as specified.
|
||||||
|
*/
|
||||||
|
ISelection expand(ISelection selection, EnumFacing direction, int blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the specified {@link ISelection} with one contracted in the specified direction by the specified number
|
||||||
|
* of blocks.
|
||||||
|
* <p>
|
||||||
|
* Note that, for example, if the direction specified is UP, the bottom of the selection will be shifted up. If it
|
||||||
|
* is DOWN, the top of the selection will be shifted down.
|
||||||
|
*
|
||||||
|
* @param selection The selection to contract.
|
||||||
|
* @param direction The direction to contract the selection.
|
||||||
|
* @param blocks How many blocks to contract it.
|
||||||
|
* @return The new selection, contracted as specified.
|
||||||
|
*/
|
||||||
|
ISelection contract(ISelection selection, EnumFacing direction, int blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the specified {@link ISelection} with one shifted in the specified direction by the specified number of
|
||||||
|
* blocks. This moves the whole selection.
|
||||||
|
*
|
||||||
|
* @param selection The selection to shift.
|
||||||
|
* @param direction The direction to shift the selection.
|
||||||
|
* @param blocks How many blocks to shift it.
|
||||||
|
* @return The new selection, shifted as specified.
|
||||||
|
*/
|
||||||
|
ISelection shift(ISelection selection, EnumFacing direction, int blocks);
|
||||||
|
}
|
@ -34,6 +34,9 @@ import javax.annotation.Nonnull;
|
|||||||
* @author leijurv
|
* @author leijurv
|
||||||
*/
|
*/
|
||||||
public final class BetterBlockPos extends BlockPos {
|
public final class BetterBlockPos extends BlockPos {
|
||||||
|
|
||||||
|
public static final BetterBlockPos ORIGIN = new BetterBlockPos(0, 0, 0);
|
||||||
|
|
||||||
public final int x;
|
public final int x;
|
||||||
public final int y;
|
public final int y;
|
||||||
public final int z;
|
public final int z;
|
||||||
@ -203,10 +206,10 @@ public final class BetterBlockPos extends BlockPos {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"BetterBlockPos{x=%s,y=%s,z=%s}",
|
"BetterBlockPos{x=%s,y=%s,z=%s}",
|
||||||
SettingsUtil.maybeCensor(x),
|
SettingsUtil.maybeCensor(x),
|
||||||
SettingsUtil.maybeCensor(y),
|
SettingsUtil.maybeCensor(y),
|
||||||
SettingsUtil.maybeCensor(z)
|
SettingsUtil.maybeCensor(z)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
299
src/api/java/baritone/api/utils/BlockOptionalMeta.java
Normal file
299
src/api/java/baritone/api/utils/BlockOptionalMeta.java
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils;
|
||||||
|
|
||||||
|
import baritone.api.accessor.IItemStack;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.properties.IProperty;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.regex.MatchResult;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public final class BlockOptionalMeta {
|
||||||
|
|
||||||
|
private final Block block;
|
||||||
|
private final int meta;
|
||||||
|
private final boolean noMeta;
|
||||||
|
private final Set<IBlockState> blockstates;
|
||||||
|
private final ImmutableSet<Integer> stateHashes;
|
||||||
|
private final ImmutableSet<Integer> stackHashes;
|
||||||
|
private static final Pattern pattern = Pattern.compile("^(.+?)(?::(\\d+))?$");
|
||||||
|
private static final Map<Object, Object> normalizations;
|
||||||
|
|
||||||
|
public BlockOptionalMeta(@Nonnull Block block, @Nullable Integer meta) {
|
||||||
|
this.block = block;
|
||||||
|
this.noMeta = meta == null;
|
||||||
|
this.meta = noMeta ? 0 : meta;
|
||||||
|
this.blockstates = getStates(block, meta);
|
||||||
|
this.stateHashes = getStateHashes(blockstates);
|
||||||
|
this.stackHashes = getStackHashes(blockstates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockOptionalMeta(@Nonnull Block block) {
|
||||||
|
this(block, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockOptionalMeta(@Nonnull String selector) {
|
||||||
|
Matcher matcher = pattern.matcher(selector);
|
||||||
|
|
||||||
|
if (!matcher.find()) {
|
||||||
|
throw new IllegalArgumentException("invalid block selector");
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchResult matchResult = matcher.toMatchResult();
|
||||||
|
noMeta = matchResult.group(2) == null;
|
||||||
|
|
||||||
|
ResourceLocation id = new ResourceLocation(matchResult.group(1));
|
||||||
|
|
||||||
|
if (!Block.REGISTRY.containsKey(id)) {
|
||||||
|
throw new IllegalArgumentException("Invalid block ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
block = Block.REGISTRY.getObject(id);
|
||||||
|
meta = noMeta ? 0 : Integer.parseInt(matchResult.group(2));
|
||||||
|
blockstates = getStates(block, getMeta());
|
||||||
|
stateHashes = getStateHashes(blockstates);
|
||||||
|
stackHashes = getStackHashes(blockstates);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
Map<Object, Object> _normalizations = new HashMap<>();
|
||||||
|
Consumer<Enum> put = instance -> _normalizations.put(instance.getClass(), instance);
|
||||||
|
put.accept(EnumFacing.NORTH);
|
||||||
|
put.accept(EnumFacing.Axis.Y);
|
||||||
|
put.accept(BlockLog.EnumAxis.Y);
|
||||||
|
put.accept(BlockStairs.EnumHalf.BOTTOM);
|
||||||
|
put.accept(BlockStairs.EnumShape.STRAIGHT);
|
||||||
|
put.accept(BlockLever.EnumOrientation.DOWN_X);
|
||||||
|
put.accept(BlockDoublePlant.EnumBlockHalf.LOWER);
|
||||||
|
put.accept(BlockSlab.EnumBlockHalf.BOTTOM);
|
||||||
|
put.accept(BlockDoor.EnumDoorHalf.LOWER);
|
||||||
|
put.accept(BlockDoor.EnumHingePosition.LEFT);
|
||||||
|
put.accept(BlockBed.EnumPartType.HEAD);
|
||||||
|
put.accept(BlockRailBase.EnumRailDirection.NORTH_SOUTH);
|
||||||
|
put.accept(BlockTrapDoor.DoorHalf.BOTTOM);
|
||||||
|
_normalizations.put(BlockBanner.ROTATION, 0);
|
||||||
|
_normalizations.put(BlockBed.OCCUPIED, false);
|
||||||
|
_normalizations.put(BlockBrewingStand.HAS_BOTTLE[0], false);
|
||||||
|
_normalizations.put(BlockBrewingStand.HAS_BOTTLE[1], false);
|
||||||
|
_normalizations.put(BlockBrewingStand.HAS_BOTTLE[2], false);
|
||||||
|
_normalizations.put(BlockButton.POWERED, false);
|
||||||
|
// _normalizations.put(BlockCactus.AGE, 0);
|
||||||
|
// _normalizations.put(BlockCauldron.LEVEL, 0);
|
||||||
|
// _normalizations.put(BlockChorusFlower.AGE, 0);
|
||||||
|
_normalizations.put(BlockChorusPlant.NORTH, false);
|
||||||
|
_normalizations.put(BlockChorusPlant.EAST, false);
|
||||||
|
_normalizations.put(BlockChorusPlant.SOUTH, false);
|
||||||
|
_normalizations.put(BlockChorusPlant.WEST, false);
|
||||||
|
_normalizations.put(BlockChorusPlant.UP, false);
|
||||||
|
_normalizations.put(BlockChorusPlant.DOWN, false);
|
||||||
|
// _normalizations.put(BlockCocoa.AGE, 0);
|
||||||
|
// _normalizations.put(BlockCrops.AGE, 0);
|
||||||
|
_normalizations.put(BlockDirt.SNOWY, false);
|
||||||
|
_normalizations.put(BlockDoor.OPEN, false);
|
||||||
|
_normalizations.put(BlockDoor.POWERED, false);
|
||||||
|
// _normalizations.put(BlockFarmland.MOISTURE, 0);
|
||||||
|
_normalizations.put(BlockFence.NORTH, false);
|
||||||
|
_normalizations.put(BlockFence.EAST, false);
|
||||||
|
_normalizations.put(BlockFence.WEST, false);
|
||||||
|
_normalizations.put(BlockFence.SOUTH, false);
|
||||||
|
// _normalizations.put(BlockFenceGate.POWERED, false);
|
||||||
|
// _normalizations.put(BlockFenceGate.IN_WALL, false);
|
||||||
|
_normalizations.put(BlockFire.AGE, 0);
|
||||||
|
_normalizations.put(BlockFire.NORTH, false);
|
||||||
|
_normalizations.put(BlockFire.EAST, false);
|
||||||
|
_normalizations.put(BlockFire.SOUTH, false);
|
||||||
|
_normalizations.put(BlockFire.WEST, false);
|
||||||
|
_normalizations.put(BlockFire.UPPER, false);
|
||||||
|
// _normalizations.put(BlockFrostedIce.AGE, 0);
|
||||||
|
_normalizations.put(BlockGrass.SNOWY, false);
|
||||||
|
// _normalizations.put(BlockHopper.ENABLED, true);
|
||||||
|
// _normalizations.put(BlockLever.POWERED, false);
|
||||||
|
// _normalizations.put(BlockLiquid.LEVEL, 0);
|
||||||
|
// _normalizations.put(BlockMycelium.SNOWY, false);
|
||||||
|
// _normalizations.put(BlockNetherWart.AGE, false);
|
||||||
|
_normalizations.put(BlockLeaves.CHECK_DECAY, false);
|
||||||
|
// _normalizations.put(BlockLeaves.DECAYABLE, false);
|
||||||
|
// _normalizations.put(BlockObserver.POWERED, false);
|
||||||
|
_normalizations.put(BlockPane.NORTH, false);
|
||||||
|
_normalizations.put(BlockPane.EAST, false);
|
||||||
|
_normalizations.put(BlockPane.WEST, false);
|
||||||
|
_normalizations.put(BlockPane.SOUTH, false);
|
||||||
|
// _normalizations.put(BlockPistonBase.EXTENDED, false);
|
||||||
|
// _normalizations.put(BlockPressurePlate.POWERED, false);
|
||||||
|
// _normalizations.put(BlockPressurePlateWeighted.POWER, false);
|
||||||
|
_normalizations.put(BlockQuartz.EnumType.LINES_X, BlockQuartz.EnumType.LINES_Y);
|
||||||
|
_normalizations.put(BlockQuartz.EnumType.LINES_Z, BlockQuartz.EnumType.LINES_Y);
|
||||||
|
// _normalizations.put(BlockRailDetector.POWERED, false);
|
||||||
|
// _normalizations.put(BlockRailPowered.POWERED, false);
|
||||||
|
_normalizations.put(BlockRedstoneWire.NORTH, false);
|
||||||
|
_normalizations.put(BlockRedstoneWire.EAST, false);
|
||||||
|
_normalizations.put(BlockRedstoneWire.SOUTH, false);
|
||||||
|
_normalizations.put(BlockRedstoneWire.WEST, false);
|
||||||
|
// _normalizations.put(BlockReed.AGE, false);
|
||||||
|
_normalizations.put(BlockSapling.STAGE, 0);
|
||||||
|
_normalizations.put(BlockSkull.NODROP, false);
|
||||||
|
_normalizations.put(BlockStandingSign.ROTATION, 0);
|
||||||
|
_normalizations.put(BlockStem.AGE, 0);
|
||||||
|
_normalizations.put(BlockTripWire.NORTH, false);
|
||||||
|
_normalizations.put(BlockTripWire.EAST, false);
|
||||||
|
_normalizations.put(BlockTripWire.WEST, false);
|
||||||
|
_normalizations.put(BlockTripWire.SOUTH, false);
|
||||||
|
_normalizations.put(BlockVine.NORTH, false);
|
||||||
|
_normalizations.put(BlockVine.EAST, false);
|
||||||
|
_normalizations.put(BlockVine.SOUTH, false);
|
||||||
|
_normalizations.put(BlockVine.WEST, false);
|
||||||
|
_normalizations.put(BlockVine.UP, false);
|
||||||
|
_normalizations.put(BlockWall.UP, false);
|
||||||
|
_normalizations.put(BlockWall.NORTH, false);
|
||||||
|
_normalizations.put(BlockWall.EAST, false);
|
||||||
|
_normalizations.put(BlockWall.WEST, false);
|
||||||
|
_normalizations.put(BlockWall.SOUTH, false);
|
||||||
|
normalizations = Collections.unmodifiableMap(_normalizations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <C extends Comparable<C>, P extends IProperty<C>> P castToIProperty(Object value) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return (P) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <C extends Comparable<C>, P extends IProperty<C>> C castToIPropertyValue(P iproperty, Object value) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return (C) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBlockState normalize(IBlockState state) {
|
||||||
|
IBlockState newState = state;
|
||||||
|
|
||||||
|
for (IProperty<?> property : state.getProperties().keySet()) {
|
||||||
|
Class<?> valueClass = property.getValueClass();
|
||||||
|
if (normalizations.containsKey(property)) {
|
||||||
|
try {
|
||||||
|
newState = newState.withProperty(
|
||||||
|
castToIProperty(property),
|
||||||
|
castToIPropertyValue(property, normalizations.get(property))
|
||||||
|
);
|
||||||
|
} catch (IllegalArgumentException ignored) {}
|
||||||
|
} else if (normalizations.containsKey(state.getValue(property))) {
|
||||||
|
try {
|
||||||
|
newState = newState.withProperty(
|
||||||
|
castToIProperty(property),
|
||||||
|
castToIPropertyValue(property, normalizations.get(state.getValue(property)))
|
||||||
|
);
|
||||||
|
} catch (IllegalArgumentException ignored) {}
|
||||||
|
} else if (normalizations.containsKey(valueClass)) {
|
||||||
|
try {
|
||||||
|
newState = newState.withProperty(
|
||||||
|
castToIProperty(property),
|
||||||
|
castToIPropertyValue(property, normalizations.get(valueClass))
|
||||||
|
);
|
||||||
|
} catch (IllegalArgumentException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int stateMeta(IBlockState state) {
|
||||||
|
return state.getBlock().getMetaFromState(normalize(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<IBlockState> getStates(@Nonnull Block block, @Nullable Integer meta) {
|
||||||
|
return block.getBlockState().getValidStates().stream()
|
||||||
|
.filter(blockstate -> meta == null || stateMeta(blockstate) == meta)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImmutableSet<Integer> getStateHashes(Set<IBlockState> blockstates) {
|
||||||
|
return ImmutableSet.copyOf(
|
||||||
|
blockstates.stream()
|
||||||
|
.map(IBlockState::hashCode)
|
||||||
|
.toArray(Integer[]::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImmutableSet<Integer> getStackHashes(Set<IBlockState> blockstates) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return ImmutableSet.copyOf(
|
||||||
|
blockstates.stream()
|
||||||
|
.map(state -> new ItemStack(
|
||||||
|
state.getBlock().getItemDropped(state, new Random(), 0),
|
||||||
|
state.getBlock().damageDropped(state)
|
||||||
|
))
|
||||||
|
.map(stack -> ((IItemStack) (Object) stack).getBaritoneHash())
|
||||||
|
.toArray(Integer[]::new)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block getBlock() {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMeta() {
|
||||||
|
return noMeta ? null : meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(@Nonnull Block block) {
|
||||||
|
return block == this.block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(@Nonnull IBlockState blockstate) {
|
||||||
|
Block block = blockstate.getBlock();
|
||||||
|
return block == this.block && stateHashes.contains(blockstate.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(ItemStack stack) {
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
int hash = ((IItemStack) (Object) stack).getBaritoneHash();
|
||||||
|
|
||||||
|
if (noMeta) {
|
||||||
|
hash -= stack.getItemDamage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return stackHashes.contains(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("BlockOptionalMeta{block=%s,meta=%s}", block, getMeta());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBlockState blockStateFromStack(ItemStack stack) {
|
||||||
|
//noinspection deprecation
|
||||||
|
return Block.getBlockFromItem(stack.getItem()).getStateFromMeta(stack.getMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBlockState getAnyBlockState() {
|
||||||
|
if (blockstates.size() > 0) {
|
||||||
|
return blockstates.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
95
src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java
Normal file
95
src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class BlockOptionalMetaLookup {
|
||||||
|
|
||||||
|
private final BlockOptionalMeta[] boms;
|
||||||
|
|
||||||
|
public BlockOptionalMetaLookup(BlockOptionalMeta... boms) {
|
||||||
|
this.boms = boms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockOptionalMetaLookup(Block... blocks) {
|
||||||
|
this.boms = Stream.of(blocks)
|
||||||
|
.map(BlockOptionalMeta::new)
|
||||||
|
.toArray(BlockOptionalMeta[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockOptionalMetaLookup(List<Block> blocks) {
|
||||||
|
this.boms = blocks.stream()
|
||||||
|
.map(BlockOptionalMeta::new)
|
||||||
|
.toArray(BlockOptionalMeta[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockOptionalMetaLookup(String... blocks) {
|
||||||
|
this.boms = Stream.of(blocks)
|
||||||
|
.map(BlockOptionalMeta::new)
|
||||||
|
.toArray(BlockOptionalMeta[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(Block block) {
|
||||||
|
for (BlockOptionalMeta bom : boms) {
|
||||||
|
if (bom.getBlock() == block) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(IBlockState state) {
|
||||||
|
for (BlockOptionalMeta bom : boms) {
|
||||||
|
if (bom.matches(state)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(ItemStack stack) {
|
||||||
|
for (BlockOptionalMeta bom : boms) {
|
||||||
|
if (bom.matches(stack)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BlockOptionalMeta> blocks() {
|
||||||
|
return Arrays.asList(boms);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"BlockOptionalMetaLookup{%s}",
|
||||||
|
Arrays.toString(boms)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -22,9 +22,9 @@ import net.minecraft.util.ResourceLocation;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class BlockUtils {
|
public class BlockUtils {
|
||||||
|
|
||||||
private static transient Map<String, Block> resourceCache = new HashMap<>();
|
private static transient Map<String, Block> resourceCache = new HashMap<>();
|
||||||
|
|
||||||
public static String blockToString(Block block) {
|
public static String blockToString(Block block) {
|
||||||
@ -39,7 +39,11 @@ public class BlockUtils {
|
|||||||
|
|
||||||
public static Block stringToBlockRequired(String name) {
|
public static Block stringToBlockRequired(String name) {
|
||||||
Block block = stringToBlockNullable(name);
|
Block block = stringToBlockNullable(name);
|
||||||
Objects.requireNonNull(block);
|
|
||||||
|
if (block == null) {
|
||||||
|
throw new IllegalArgumentException(String.format("Invalid block name %s", name));
|
||||||
|
}
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,755 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package baritone.api.utils;
|
|
||||||
|
|
||||||
import baritone.api.BaritoneAPI;
|
|
||||||
import baritone.api.IBaritone;
|
|
||||||
import baritone.api.Settings;
|
|
||||||
import baritone.api.behavior.IPathingBehavior;
|
|
||||||
import baritone.api.cache.IRememberedInventory;
|
|
||||||
import baritone.api.cache.IWaypoint;
|
|
||||||
import baritone.api.cache.Waypoint;
|
|
||||||
import baritone.api.event.events.ChatEvent;
|
|
||||||
import baritone.api.event.listener.AbstractGameEventListener;
|
|
||||||
import baritone.api.pathing.goals.*;
|
|
||||||
import baritone.api.process.IBaritoneProcess;
|
|
||||||
import baritone.api.process.ICustomGoalProcess;
|
|
||||||
import baritone.api.process.IGetToBlockProcess;
|
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.multiplayer.ChunkProviderClient;
|
|
||||||
import net.minecraft.crash.CrashReport;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.item.EntityItem;
|
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.util.ReportedException;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
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.world.DimensionType;
|
|
||||||
import net.minecraft.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static org.apache.commons.lang3.math.NumberUtils.isCreatable;
|
|
||||||
|
|
||||||
public class ExampleBaritoneControl implements Helper, AbstractGameEventListener {
|
|
||||||
private static final String COMMAND_PREFIX = "#";
|
|
||||||
|
|
||||||
public final IBaritone baritone;
|
|
||||||
public final IPlayerContext ctx;
|
|
||||||
|
|
||||||
public ExampleBaritoneControl(IBaritone baritone) {
|
|
||||||
this.baritone = baritone;
|
|
||||||
this.ctx = baritone.getPlayerContext();
|
|
||||||
baritone.getGameEventHandler().registerEventListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSendChatMessage(ChatEvent event) {
|
|
||||||
String msg = event.getMessage();
|
|
||||||
if (BaritoneAPI.getSettings().prefixControl.value && msg.startsWith(COMMAND_PREFIX)) {
|
|
||||||
if (!runCommand(msg.substring(COMMAND_PREFIX.length()))) {
|
|
||||||
logDirect("Invalid command");
|
|
||||||
}
|
|
||||||
event.cancel(); // always cancel if using prefixControl
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!BaritoneAPI.getSettings().chatControl.value && !BaritoneAPI.getSettings().removePrefix.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (runCommand(msg)) {
|
|
||||||
event.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean runCommand(String msg0) { // you may think this can be private, but impcat calls it from .b =)
|
|
||||||
String msg = msg0.toLowerCase(Locale.US).trim(); // don't reassign the argument LOL
|
|
||||||
IPathingBehavior pathingBehavior = baritone.getPathingBehavior();
|
|
||||||
ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess();
|
|
||||||
List<Settings.Setting<Boolean>> toggleable = BaritoneAPI.getSettings().getAllValuesByType(Boolean.class);
|
|
||||||
for (Settings.Setting<Boolean> setting : toggleable) {
|
|
||||||
if (msg.equalsIgnoreCase(setting.getName())) {
|
|
||||||
setting.value ^= true;
|
|
||||||
logDirect("Toggled " + setting.getName() + " to " + setting.value);
|
|
||||||
SettingsUtil.save(BaritoneAPI.getSettings());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (msg.equals("baritone") || msg.equals("modifiedsettings") || msg.startsWith("settings m") || msg.equals("modified")) {
|
|
||||||
logDirect("All settings that have been modified from their default values:");
|
|
||||||
for (Settings.Setting<?> setting : SettingsUtil.modifiedSettings(BaritoneAPI.getSettings())) {
|
|
||||||
logDirect(setting.toString());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("settings")) {
|
|
||||||
String rest = msg.substring("settings".length());
|
|
||||||
try {
|
|
||||||
int page = Integer.parseInt(rest.trim());
|
|
||||||
int min = page * 10;
|
|
||||||
int max = Math.min(BaritoneAPI.getSettings().allSettings.size(), (page + 1) * 10);
|
|
||||||
logDirect("Settings " + min + " to " + (max - 1) + ":");
|
|
||||||
for (int i = min; i < max; i++) {
|
|
||||||
logDirect(BaritoneAPI.getSettings().allSettings.get(i).toString());
|
|
||||||
}
|
|
||||||
} catch (Exception ex) { // NumberFormatException | ArrayIndexOutOfBoundsException and probably some others I'm forgetting lol
|
|
||||||
ex.printStackTrace();
|
|
||||||
logDirect("All settings:");
|
|
||||||
for (Settings.Setting<?> setting : BaritoneAPI.getSettings().allSettings) {
|
|
||||||
logDirect(setting.toString());
|
|
||||||
}
|
|
||||||
logDirect("To get one page of ten settings at a time, do settings <num>");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("") || msg.equals("help") || msg.equals("?")) {
|
|
||||||
ITextComponent component = MESSAGE_PREFIX.createCopy();
|
|
||||||
component.getStyle().setColor(TextFormatting.GRAY);
|
|
||||||
TextComponentString helpLink = new TextComponentString(" Click here for instructions on how to use Baritone (https://github.com/cabaletta/baritone/blob/master/USAGE.md)");
|
|
||||||
helpLink.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://github.com/cabaletta/baritone/blob/master/USAGE.md"));
|
|
||||||
component.appendSibling(helpLink);
|
|
||||||
BaritoneAPI.getSettings().logger.value.accept(component);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.contains(" ")) {
|
|
||||||
String settingName = msg.substring(0, msg.indexOf(' '));
|
|
||||||
String settingValue = msg.substring(msg.indexOf(' ') + 1);
|
|
||||||
Settings.Setting setting = BaritoneAPI.getSettings().byLowerName.get(settingName);
|
|
||||||
if (setting != null) {
|
|
||||||
if (settingValue.equals("reset")) {
|
|
||||||
logDirect("Resetting setting " + settingName + " to default value.");
|
|
||||||
setting.reset();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SettingsUtil.parseAndApply(BaritoneAPI.getSettings(), settingName, settingValue);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
logDirect("Unable to parse setting");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SettingsUtil.save(BaritoneAPI.getSettings());
|
|
||||||
logDirect(setting.toString());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (BaritoneAPI.getSettings().byLowerName.containsKey(msg)) {
|
|
||||||
Settings.Setting<?> setting = BaritoneAPI.getSettings().byLowerName.get(msg);
|
|
||||||
logDirect(setting.toString());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.startsWith("goal")) {
|
|
||||||
String rest = msg.substring(4).trim();
|
|
||||||
Goal goal;
|
|
||||||
if (rest.equals("clear") || rest.equals("none")) {
|
|
||||||
goal = null;
|
|
||||||
} else {
|
|
||||||
String[] params = rest.split(" ");
|
|
||||||
if (params[0].equals("")) {
|
|
||||||
params = new String[]{};
|
|
||||||
}
|
|
||||||
goal = parseGoal(params);
|
|
||||||
if (goal == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customGoalProcess.setGoal(goal);
|
|
||||||
logDirect("Goal: " + goal);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("crash")) {
|
|
||||||
StringBuilder meme = new StringBuilder();
|
|
||||||
CrashReport rep = new CrashReport("Manually triggered debug crash", new Throwable());
|
|
||||||
mc.addGraphicsAndWorldToCrashReport(rep);
|
|
||||||
new ReportedException(rep).printStackTrace();
|
|
||||||
rep.getSectionsInStringBuilder(meme);
|
|
||||||
System.out.println(meme);
|
|
||||||
logDirect(meme.toString());
|
|
||||||
logDirect("ok");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("path")) {
|
|
||||||
if (pathingBehavior.getGoal() == null) {
|
|
||||||
logDirect("No goal.");
|
|
||||||
} else if (pathingBehavior.getGoal().isInGoal(ctx.playerFeet())) {
|
|
||||||
logDirect("Already in goal");
|
|
||||||
} else if (pathingBehavior.isPathing()) {
|
|
||||||
logDirect("Currently executing a path. Please cancel it first.");
|
|
||||||
} else {
|
|
||||||
customGoalProcess.setGoalAndPath(pathingBehavior.getGoal());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/*if (msg.equals("fullpath")) {
|
|
||||||
if (pathingBehavior.getGoal() == null) {
|
|
||||||
logDirect("No goal.");
|
|
||||||
} else {
|
|
||||||
logDirect("Started segmented calculator");
|
|
||||||
SegmentedCalculator.calculateSegmentsThreaded(pathingBehavior.pathStart(), pathingBehavior.getGoal(), new CalculationContext(baritone, true), ipath -> {
|
|
||||||
logDirect("Found a path");
|
|
||||||
logDirect("Ends at " + ipath.getDest());
|
|
||||||
logDirect("Length " + ipath.length());
|
|
||||||
logDirect("Estimated time " + ipath.ticksRemainingFrom(0));
|
|
||||||
pathingBehavior.secretCursedFunctionDoNotCall(ipath); // it's okay when *I* do it
|
|
||||||
}, () -> {
|
|
||||||
logDirect("Path calculation failed, no path");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
if (msg.equals("proc")) {
|
|
||||||
Optional<IBaritoneProcess> proc = baritone.getPathingControlManager().mostRecentInControl();
|
|
||||||
if (!proc.isPresent()) {
|
|
||||||
logDirect("No process is in control");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
IBaritoneProcess p = proc.get();
|
|
||||||
logDirect("Class: " + p.getClass());
|
|
||||||
logDirect("Priority: " + p.priority());
|
|
||||||
logDirect("Temporary: " + p.isTemporary());
|
|
||||||
logDirect("Display name: " + p.displayName());
|
|
||||||
logDirect("Command: " + baritone.getPathingControlManager().mostRecentCommand());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("version")) {
|
|
||||||
String version = ExampleBaritoneControl.class.getPackage().getImplementationVersion();
|
|
||||||
if (version == null) {
|
|
||||||
logDirect("No version detected. Either dev environment or broken install.");
|
|
||||||
} else {
|
|
||||||
logDirect("You are using Baritone v" + version);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("repack") || msg.equals("rescan")) {
|
|
||||||
logDirect("Queued " + repack() + " chunks for repacking");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("build")) {
|
|
||||||
String file;
|
|
||||||
BlockPos origin;
|
|
||||||
try {
|
|
||||||
String[] coords = msg.substring("build".length()).trim().split(" ");
|
|
||||||
file = coords[0] + ".schematic";
|
|
||||||
origin = new BlockPos(parseOrDefault(coords[1], ctx.playerFeet().x, 1), parseOrDefault(coords[2], ctx.playerFeet().y, 1), parseOrDefault(coords[3], ctx.playerFeet().z, 1));
|
|
||||||
} catch (Exception ex) {
|
|
||||||
file = msg.substring(5).trim() + ".schematic";
|
|
||||||
origin = ctx.playerFeet();
|
|
||||||
}
|
|
||||||
logDirect("Loading '" + file + "' to build from origin " + origin);
|
|
||||||
boolean success = baritone.getBuilderProcess().build(file, origin);
|
|
||||||
logDirect(success ? "Loaded" : "Unable to load");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("schematica")) {
|
|
||||||
baritone.getBuilderProcess().buildOpenSchematic();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("come")) {
|
|
||||||
customGoalProcess.setGoalAndPath(new GoalBlock(new BlockPos(Helper.mc.getRenderViewEntity())));
|
|
||||||
logDirect("Coming");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("axis") || msg.equals("highway")) {
|
|
||||||
customGoalProcess.setGoalAndPath(new GoalAxis());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("cancel") || msg.equals("stop")) {
|
|
||||||
pathingBehavior.cancelEverything();
|
|
||||||
logDirect("ok canceled");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("forcecancel")) {
|
|
||||||
pathingBehavior.cancelEverything();
|
|
||||||
pathingBehavior.forceCancel();
|
|
||||||
logDirect("ok force canceled");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("gc")) {
|
|
||||||
System.gc();
|
|
||||||
logDirect("Called System.gc();");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("invert")) {
|
|
||||||
Goal goal = pathingBehavior.getGoal();
|
|
||||||
BlockPos runAwayFrom;
|
|
||||||
if (goal instanceof GoalXZ) {
|
|
||||||
runAwayFrom = new BlockPos(((GoalXZ) goal).getX(), 0, ((GoalXZ) goal).getZ());
|
|
||||||
} else if (goal instanceof GoalBlock) {
|
|
||||||
runAwayFrom = ((GoalBlock) goal).getGoalPos();
|
|
||||||
} else {
|
|
||||||
logDirect("Goal must be GoalXZ or GoalBlock to invert");
|
|
||||||
logDirect("Inverting goal of player feet");
|
|
||||||
runAwayFrom = ctx.playerFeet();
|
|
||||||
}
|
|
||||||
customGoalProcess.setGoalAndPath(new GoalRunAway(1, runAwayFrom) {
|
|
||||||
@Override
|
|
||||||
public boolean isInGoal(int x, int y, int z) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("cleararea")) {
|
|
||||||
String suffix = msg.substring("cleararea".length());
|
|
||||||
BlockPos corner1;
|
|
||||||
BlockPos corner2;
|
|
||||||
if (suffix.isEmpty()) {
|
|
||||||
// clear the area from the current goal to here
|
|
||||||
Goal goal = baritone.getPathingBehavior().getGoal();
|
|
||||||
if (!(goal instanceof GoalBlock)) {
|
|
||||||
logDirect("Need to specify goal of opposite corner");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
corner1 = ((GoalBlock) goal).getGoalPos();
|
|
||||||
corner2 = ctx.playerFeet();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
String[] spl = suffix.split(" ");
|
|
||||||
corner1 = ctx.playerFeet();
|
|
||||||
corner2 = new BlockPos(Integer.parseInt(spl[0]), Integer.parseInt(spl[1]), Integer.parseInt(spl[2]));
|
|
||||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException | NullPointerException ex) {
|
|
||||||
logDirect("unable to parse");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
baritone.getBuilderProcess().clearArea(corner1, corner2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("resume")) {
|
|
||||||
baritone.getBuilderProcess().resume();
|
|
||||||
logDirect("resumed");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("pause")) {
|
|
||||||
baritone.getBuilderProcess().pause();
|
|
||||||
logDirect("paused");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("reset")) {
|
|
||||||
for (Settings.Setting setting : BaritoneAPI.getSettings().allSettings) {
|
|
||||||
setting.reset();
|
|
||||||
}
|
|
||||||
SettingsUtil.save(BaritoneAPI.getSettings());
|
|
||||||
logDirect("Baritone settings reset");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("tunnel")) {
|
|
||||||
customGoalProcess.setGoalAndPath(new GoalStrictDirection(ctx.playerFeet(), ctx.player().getHorizontalFacing()));
|
|
||||||
logDirect("tunneling");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("render")) {
|
|
||||||
BetterBlockPos pf = ctx.playerFeet();
|
|
||||||
int dist = (Minecraft.getMinecraft().gameSettings.renderDistanceChunks + 1) * 16;
|
|
||||||
Minecraft.getMinecraft().renderGlobal.markBlockRangeForRenderUpdate(pf.x - dist, pf.y - 256, pf.z - dist, pf.x + dist, pf.y + 256, pf.z + dist);
|
|
||||||
logDirect("okay");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("farm")) {
|
|
||||||
baritone.getFarmProcess().farm();
|
|
||||||
logDirect("farming");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("chests")) {
|
|
||||||
for (Map.Entry<BlockPos, IRememberedInventory> entry : baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()) {
|
|
||||||
logDirect(BetterBlockPos.from(entry.getKey()) + "");
|
|
||||||
log(entry.getValue().getContents());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("followentities")) {
|
|
||||||
baritone.getFollowProcess().follow(Entity.class::isInstance);
|
|
||||||
logDirect("Following any entities");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("followplayers")) {
|
|
||||||
baritone.getFollowProcess().follow(EntityPlayer.class::isInstance); // O P P A
|
|
||||||
logDirect("Following any players");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("followentity")) {
|
|
||||||
String name = msg.substring(12).trim();
|
|
||||||
Optional<Entity> toFollow = Optional.empty();
|
|
||||||
for (Entity entity : ctx.world().loadedEntityList) {
|
|
||||||
String entityName = entity.getName().trim().toLowerCase();
|
|
||||||
if ((entityName.contains(name) || name.contains(entityName)) && !(entity instanceof EntityItem || entity instanceof EntityPlayer)) { // We dont want it following players while `#follow` exists.
|
|
||||||
toFollow = Optional.of(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!toFollow.isPresent()) {
|
|
||||||
logDirect("Entity not found");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Entity effectivelyFinal = toFollow.get();
|
|
||||||
baritone.getFollowProcess().follow(effectivelyFinal::equals);
|
|
||||||
logDirect("Following entity " + toFollow.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("follow")) {
|
|
||||||
String name = msg.substring(6).trim();
|
|
||||||
Optional<Entity> toFollow = Optional.empty();
|
|
||||||
if (name.length() == 0) {
|
|
||||||
toFollow = ctx.getSelectedEntity();
|
|
||||||
} else {
|
|
||||||
for (EntityPlayer pl : ctx.world().playerEntities) {
|
|
||||||
String theirName = pl.getName().trim().toLowerCase();
|
|
||||||
if (!theirName.equals(ctx.player().getName().trim().toLowerCase()) && (theirName.contains(name) || name.contains(theirName))) { // don't follow ourselves lol
|
|
||||||
toFollow = Optional.of(pl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!toFollow.isPresent()) {
|
|
||||||
logDirect("Not found");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Entity effectivelyFinal = toFollow.get();
|
|
||||||
baritone.getFollowProcess().follow(effectivelyFinal::equals);
|
|
||||||
logDirect("Following " + toFollow.get());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("explorefilter")) {
|
|
||||||
// explorefilter blah.json
|
|
||||||
// means that entries in blah.json are already explored
|
|
||||||
// explorefilter blah.json invert
|
|
||||||
// means that entries in blah.json are NOT already explored
|
|
||||||
String path = msg.substring("explorefilter".length()).trim();
|
|
||||||
String[] parts = path.split(" ");
|
|
||||||
Path path1 = Minecraft.getMinecraft().gameDir.toPath().resolve(parts[0]);
|
|
||||||
boolean invert = parts.length > 1;
|
|
||||||
try {
|
|
||||||
baritone.getExploreProcess().applyJsonFilter(path1, invert);
|
|
||||||
logDirect("Loaded filter. Inverted: " + invert);
|
|
||||||
if (invert) {
|
|
||||||
logDirect("Chunks on this list will be treated as possibly unexplored, all others will be treated as certainly explored");
|
|
||||||
} else {
|
|
||||||
logDirect("Chunks on this list will be treated as certainly explored, all others will be treated as possibly unexplored");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
logDirect("Unable to load " + path1);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("reloadall")) {
|
|
||||||
baritone.getWorldProvider().getCurrentWorld().getCachedWorld().reloadAllFromDisk();
|
|
||||||
logDirect("ok");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("saveall")) {
|
|
||||||
baritone.getWorldProvider().getCurrentWorld().getCachedWorld().save();
|
|
||||||
logDirect("ok");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("explore")) {
|
|
||||||
String rest = msg.substring("explore".length()).trim();
|
|
||||||
int centerX;
|
|
||||||
int centerZ;
|
|
||||||
try {
|
|
||||||
centerX = Integer.parseInt(rest.split(" ")[0]);
|
|
||||||
centerZ = Integer.parseInt(rest.split(" ")[1]);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
centerX = ctx.playerFeet().x;
|
|
||||||
centerZ = ctx.playerFeet().z;
|
|
||||||
}
|
|
||||||
baritone.getExploreProcess().explore(centerX, centerZ);
|
|
||||||
logDirect("Exploring from " + centerX + "," + centerZ);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("blacklist")) {
|
|
||||||
IGetToBlockProcess proc = baritone.getGetToBlockProcess();
|
|
||||||
if (!proc.isActive()) {
|
|
||||||
logDirect("GetToBlockProcess is not currently active");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (proc.blacklistClosest()) {
|
|
||||||
logDirect("Blacklisted closest instances");
|
|
||||||
} else {
|
|
||||||
logDirect("No known locations, unable to blacklist");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("find")) {
|
|
||||||
repack();
|
|
||||||
String blockType = msg.substring(4).trim();
|
|
||||||
ArrayList<BlockPos> locs = baritone.getWorldProvider().getCurrentWorld().getCachedWorld().getLocationsOf(blockType, 1, ctx.playerFeet().getX(), ctx.playerFeet().getZ(), 4);
|
|
||||||
logDirect("Have " + locs.size() + " locations");
|
|
||||||
for (BlockPos pos : locs) {
|
|
||||||
Block actually = ctx.world().getBlockState(pos).getBlock();
|
|
||||||
if (!BlockUtils.blockToString(actually).equalsIgnoreCase(blockType)) {
|
|
||||||
logDebug("Was looking for " + blockType + " but actually found " + actually + " " + BlockUtils.blockToString(actually));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("mine")) {
|
|
||||||
repack();
|
|
||||||
String[] blockTypes = msg.substring(4).trim().split(" ");
|
|
||||||
try {
|
|
||||||
int quantity = Integer.parseInt(blockTypes[1]);
|
|
||||||
Block block = BlockUtils.stringToBlockRequired(blockTypes[0]);
|
|
||||||
baritone.getMineProcess().mine(quantity, block);
|
|
||||||
logDirect("Will mine " + quantity + " " + blockTypes[0]);
|
|
||||||
return true;
|
|
||||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException | NullPointerException ex) {}
|
|
||||||
for (String s : blockTypes) {
|
|
||||||
if (BlockUtils.stringToBlockNullable(s) == null) {
|
|
||||||
logDirect(s + " isn't a valid block name");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
baritone.getMineProcess().mineByName(0, blockTypes);
|
|
||||||
logDirect("Started mining blocks of type " + Arrays.toString(blockTypes));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("click")) {
|
|
||||||
baritone.openClick();
|
|
||||||
logDirect("aight dude");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("thisway") || msg.startsWith("forward")) {
|
|
||||||
try {
|
|
||||||
Goal goal = GoalXZ.fromDirection(ctx.playerFeetAsVec(), ctx.player().rotationYaw, Double.parseDouble(msg.substring(7).trim()));
|
|
||||||
customGoalProcess.setGoal(goal);
|
|
||||||
logDirect("Goal: " + goal);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
logDirect("Error unable to parse '" + msg.substring(7).trim() + "' to a double.");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("list") || msg.startsWith("get ") || msg.startsWith("show")) {
|
|
||||||
String waypointType = msg.substring(4).trim();
|
|
||||||
if (waypointType.endsWith("s")) {
|
|
||||||
// for example, "show deaths"
|
|
||||||
waypointType = waypointType.substring(0, waypointType.length() - 1);
|
|
||||||
}
|
|
||||||
IWaypoint.Tag tag = IWaypoint.Tag.fromString(waypointType);
|
|
||||||
if (tag == null) {
|
|
||||||
logDirect("Not a valid tag. Tags are: " + Arrays.asList(IWaypoint.Tag.values()).toString().toLowerCase());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Set<IWaypoint> waypoints = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getByTag(tag);
|
|
||||||
// might as well show them from oldest to newest
|
|
||||||
List<IWaypoint> sorted = new ArrayList<>(waypoints);
|
|
||||||
sorted.sort(Comparator.comparingLong(IWaypoint::getCreationTimestamp));
|
|
||||||
logDirect("Waypoints under tag " + tag + ":");
|
|
||||||
for (IWaypoint waypoint : sorted) {
|
|
||||||
logDirect(waypoint.toString());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("save")) {
|
|
||||||
String name = msg.substring(4).trim();
|
|
||||||
BlockPos pos = ctx.playerFeet();
|
|
||||||
if (name.contains(" ")) {
|
|
||||||
logDirect("Name contains a space, assuming it's in the format 'save waypointName X Y Z'");
|
|
||||||
String[] parts = name.split(" ");
|
|
||||||
if (parts.length != 4) {
|
|
||||||
logDirect("Unable to parse, expected four things");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
pos = new BlockPos(Integer.parseInt(parts[1]), Integer.parseInt(parts[2]), Integer.parseInt(parts[3]));
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
logDirect("Unable to parse coordinate integers");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
name = parts[0];
|
|
||||||
}
|
|
||||||
for (IWaypoint.Tag tag : IWaypoint.Tag.values()) {
|
|
||||||
if (tag.name().equalsIgnoreCase(name)) {
|
|
||||||
logDirect("Unable to use tags as name. Tags are: " + Arrays.asList(IWaypoint.Tag.values()).toString().toLowerCase());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint(name, IWaypoint.Tag.USER, pos));
|
|
||||||
logDirect("Saved user defined position " + pos + " under name '" + name + "'. Say 'goto " + name + "' to set goal, say 'list user' to list custom waypoints.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("delete")) {
|
|
||||||
String name = msg.substring(6).trim();
|
|
||||||
IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getAllWaypoints().stream().filter(w -> w.getTag() == IWaypoint.Tag.USER && w.getName().equalsIgnoreCase(name)).findFirst().orElse(null);
|
|
||||||
if (waypoint == null) {
|
|
||||||
logDirect("No user defined position under the name '" + name + "' found.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
baritone.getWorldProvider().getCurrentWorld().getWaypoints().removeWaypoint(waypoint);
|
|
||||||
logDirect("Deleted user defined position under name '" + name + "'.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.startsWith("goto")) {
|
|
||||||
repack();
|
|
||||||
String waypointType = msg.substring(4).trim();
|
|
||||||
if (waypointType.endsWith("s") && IWaypoint.Tag.fromString(waypointType.substring(0, waypointType.length() - 1)) != null) {
|
|
||||||
// for example, "show deaths"
|
|
||||||
waypointType = waypointType.substring(0, waypointType.length() - 1);
|
|
||||||
}
|
|
||||||
IWaypoint.Tag tag = IWaypoint.Tag.fromString(waypointType);
|
|
||||||
IWaypoint waypoint;
|
|
||||||
if (tag == null) {
|
|
||||||
String mining = waypointType;
|
|
||||||
Block block = BlockUtils.stringToBlockNullable(mining);
|
|
||||||
//logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
|
|
||||||
if (block == null) {
|
|
||||||
waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getAllWaypoints().stream().filter(w -> w.getName().equalsIgnoreCase(mining)).max(Comparator.comparingLong(IWaypoint::getCreationTimestamp)).orElse(null);
|
|
||||||
if (waypoint == null) {
|
|
||||||
Goal goal = parseGoal(waypointType.split(" "));
|
|
||||||
if (goal != null) {
|
|
||||||
logDirect("Going to " + goal);
|
|
||||||
customGoalProcess.setGoalAndPath(goal);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
baritone.getGetToBlockProcess().getToBlock(block);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(tag);
|
|
||||||
if (waypoint == null) {
|
|
||||||
logDirect("None saved for tag " + tag);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Goal goal = waypoint.getTag() == IWaypoint.Tag.BED ? new GoalGetToBlock(waypoint.getLocation()) : new GoalBlock(waypoint.getLocation());
|
|
||||||
customGoalProcess.setGoalAndPath(goal);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("spawn") || msg.equals("bed")) {
|
|
||||||
IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(IWaypoint.Tag.BED);
|
|
||||||
if (waypoint == null) {
|
|
||||||
BlockPos spawnPoint = ctx.player().getBedLocation();
|
|
||||||
// for some reason the default spawnpoint is underground sometimes
|
|
||||||
Goal goal = new GoalXZ(spawnPoint.getX(), spawnPoint.getZ());
|
|
||||||
logDirect("spawn not saved, defaulting to world spawn. set goal to " + goal);
|
|
||||||
customGoalProcess.setGoalAndPath(goal);
|
|
||||||
} else {
|
|
||||||
Goal goal = new GoalGetToBlock(waypoint.getLocation());
|
|
||||||
customGoalProcess.setGoalAndPath(goal);
|
|
||||||
logDirect("Set goal to most recent bed " + goal);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("sethome")) {
|
|
||||||
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("", IWaypoint.Tag.HOME, ctx.playerFeet()));
|
|
||||||
logDirect("Saved. Say home to set goal.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("home")) {
|
|
||||||
IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(IWaypoint.Tag.HOME);
|
|
||||||
if (waypoint == null) {
|
|
||||||
logDirect("home not saved");
|
|
||||||
} else {
|
|
||||||
Goal goal = new GoalBlock(waypoint.getLocation());
|
|
||||||
customGoalProcess.setGoalAndPath(goal);
|
|
||||||
logDirect("Going to saved home " + goal);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (msg.equals("damn")) {
|
|
||||||
logDirect("daniel");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int repack() {
|
|
||||||
ChunkProviderClient cli = (ChunkProviderClient) ctx.world().getChunkProvider();
|
|
||||||
int playerChunkX = ctx.playerFeet().getX() >> 4;
|
|
||||||
int playerChunkZ = ctx.playerFeet().getZ() >> 4;
|
|
||||||
int count = 0;
|
|
||||||
for (int x = playerChunkX - 40; x <= playerChunkX + 40; x++) {
|
|
||||||
for (int z = playerChunkZ - 40; z <= playerChunkZ + 40; z++) {
|
|
||||||
Chunk chunk = cli.getLoadedChunk(x, z);
|
|
||||||
if (chunk != null && !chunk.isEmpty()) {
|
|
||||||
count++;
|
|
||||||
baritone.getWorldProvider().getCurrentWorld().getCachedWorld().queueForPacking(chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int parseOrDefault(String str, int i, double dimensionFactor) {
|
|
||||||
return str.equals("~") ? i : str.startsWith("~") ? (int) (Integer.parseInt(str.substring(1)) * dimensionFactor) + i : (int) (Integer.parseInt(str) * dimensionFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void log(List<ItemStack> stacks) {
|
|
||||||
for (ItemStack stack : stacks) {
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
logDirect(stack.getCount() + "x " + stack.getDisplayName() + "@" + stack.getItemDamage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Goal parseGoal(String[] params) {
|
|
||||||
Goal goal;
|
|
||||||
try {
|
|
||||||
BetterBlockPos playerFeet = ctx.playerFeet();
|
|
||||||
|
|
||||||
int length = params.length - 1; // length has to be smaller when a dimension parameter is added
|
|
||||||
if (params.length < 1 || (isCreatable(params[params.length - 1]) || params[params.length - 1].startsWith("~"))) {
|
|
||||||
length = params.length;
|
|
||||||
}
|
|
||||||
switch (length) {
|
|
||||||
case 0:
|
|
||||||
goal = new GoalBlock(playerFeet);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
goal = new GoalYLevel(parseOrDefault(params[0], playerFeet.y, 1));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
goal = new GoalXZ(parseOrDefault(params[0], playerFeet.x, calculateDimensionFactor(params[params.length - 1])), parseOrDefault(params[1], playerFeet.z, calculateDimensionFactor(params[params.length - 1])));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
goal = new GoalBlock(new BlockPos(parseOrDefault(params[0], playerFeet.x, calculateDimensionFactor(params[params.length - 1])), parseOrDefault(params[1], playerFeet.y, 1), parseOrDefault(params[2], playerFeet.z, calculateDimensionFactor(params[params.length - 1]))));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logDirect("unable to understand lol");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
logDirect("unable to parse integer " + ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return goal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private double calculateDimensionFactor(String to) {
|
|
||||||
return Math.pow(8, ctx.world().provider.getDimensionType().getId() - getDimensionByName(to.toLowerCase()).getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private DimensionType getDimensionByName(String name) {
|
|
||||||
if ("the_end".contains(name)) {
|
|
||||||
return DimensionType.THE_END;
|
|
||||||
}
|
|
||||||
if ("the_overworld".contains(name) || "surface".contains(name)) {
|
|
||||||
return DimensionType.OVERWORLD;
|
|
||||||
}
|
|
||||||
if ("the_nether".contains(name) || "hell".contains(name)) {
|
|
||||||
return DimensionType.NETHER;
|
|
||||||
}
|
|
||||||
return ctx.world().provider.getDimensionType();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -23,6 +23,9 @@ import net.minecraft.util.text.ITextComponent;
|
|||||||
import net.minecraft.util.text.TextComponentString;
|
import net.minecraft.util.text.TextComponentString;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Brady
|
* @author Brady
|
||||||
* @since 8/1/2018
|
* @since 8/1/2018
|
||||||
@ -34,16 +37,26 @@ public interface Helper {
|
|||||||
*/
|
*/
|
||||||
Helper HELPER = new Helper() {};
|
Helper HELPER = new Helper() {};
|
||||||
|
|
||||||
ITextComponent MESSAGE_PREFIX = new TextComponentString(String.format(
|
/**
|
||||||
"%s[%sBaritone%s]%s",
|
* Instance of the game
|
||||||
TextFormatting.DARK_PURPLE,
|
*/
|
||||||
TextFormatting.LIGHT_PURPLE,
|
|
||||||
TextFormatting.DARK_PURPLE,
|
|
||||||
TextFormatting.GRAY
|
|
||||||
));
|
|
||||||
|
|
||||||
Minecraft mc = Minecraft.getMinecraft();
|
Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
|
static ITextComponent getPrefix() {
|
||||||
|
// Inner text component
|
||||||
|
ITextComponent baritone = new TextComponentString(BaritoneAPI.getSettings().shortBaritonePrefix.value ? "B" : "Baritone");
|
||||||
|
baritone.getStyle().setColor(TextFormatting.LIGHT_PURPLE);
|
||||||
|
|
||||||
|
// Outer brackets
|
||||||
|
ITextComponent prefix = new TextComponentString("");
|
||||||
|
prefix.getStyle().setColor(TextFormatting.DARK_PURPLE);
|
||||||
|
prefix.appendText("[");
|
||||||
|
prefix.appendSibling(baritone);
|
||||||
|
prefix.appendText("]");
|
||||||
|
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to chat only if chatDebug is on
|
* Send a message to chat only if chatDebug is on
|
||||||
*
|
*
|
||||||
@ -59,14 +72,40 @@ public interface Helper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to chat regardless of chatDebug (should only be used for critically important messages, or as a direct response to a chat command)
|
* Send components to chat with the [Baritone] prefix
|
||||||
|
*
|
||||||
|
* @param components The components to send
|
||||||
|
*/
|
||||||
|
default void logDirect(ITextComponent... components) {
|
||||||
|
ITextComponent component = new TextComponentString("");
|
||||||
|
component.appendSibling(getPrefix());
|
||||||
|
component.appendSibling(new TextComponentString(" "));
|
||||||
|
Arrays.asList(components).forEach(component::appendSibling);
|
||||||
|
Minecraft.getMinecraft().addScheduledTask(() -> BaritoneAPI.getSettings().logger.value.accept(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to chat regardless of chatDebug (should only be used for critically important messages, or as a
|
||||||
|
* direct response to a chat command)
|
||||||
|
*
|
||||||
|
* @param message The message to display in chat
|
||||||
|
* @param color The color to print that message in
|
||||||
|
*/
|
||||||
|
default void logDirect(String message, TextFormatting color) {
|
||||||
|
Stream.of(message.split("\n")).forEach(line -> {
|
||||||
|
ITextComponent component = new TextComponentString(line.replace("\t", " "));
|
||||||
|
component.getStyle().setColor(color);
|
||||||
|
logDirect(component);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to chat regardless of chatDebug (should only be used for critically important messages, or as a
|
||||||
|
* direct response to a chat command)
|
||||||
*
|
*
|
||||||
* @param message The message to display in chat
|
* @param message The message to display in chat
|
||||||
*/
|
*/
|
||||||
default void logDirect(String message) {
|
default void logDirect(String message) {
|
||||||
ITextComponent component = MESSAGE_PREFIX.createCopy();
|
logDirect(message, TextFormatting.GRAY);
|
||||||
component.getStyle().setColor(TextFormatting.GRAY);
|
|
||||||
component.appendSibling(new TextComponentString(" " + message));
|
|
||||||
Minecraft.getMinecraft().addScheduledTask(() -> BaritoneAPI.getSettings().logger.value.accept(component));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,21 @@ public interface IPlayerContext {
|
|||||||
default BetterBlockPos playerFeet() {
|
default BetterBlockPos playerFeet() {
|
||||||
// TODO find a better way to deal with soul sand!!!!!
|
// TODO find a better way to deal with soul sand!!!!!
|
||||||
BetterBlockPos feet = new BetterBlockPos(player().posX, player().posY + 0.1251, player().posZ);
|
BetterBlockPos feet = new BetterBlockPos(player().posX, player().posY + 0.1251, player().posZ);
|
||||||
if (world().getBlockState(feet).getBlock() instanceof BlockSlab) {
|
|
||||||
return feet.up();
|
// sometimes when calling this from another thread or while world is null, it'll throw a NullPointerException
|
||||||
}
|
// that causes the game to immediately crash
|
||||||
|
//
|
||||||
|
// so of course crashing on 2b is horribly bad due to queue times and logout spot
|
||||||
|
// catch the NPE and ignore it if it does happen
|
||||||
|
//
|
||||||
|
// this does not impact performance at all since we're not null checking constantly
|
||||||
|
// if there is an exception, the only overhead is Java generating the exception object... so we can ignore it
|
||||||
|
try {
|
||||||
|
if (world().getBlockState(feet).getBlock() instanceof BlockSlab) {
|
||||||
|
return feet.up();
|
||||||
|
}
|
||||||
|
} catch (NullPointerException ignored) {}
|
||||||
|
|
||||||
return feet;
|
return feet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,11 @@ package baritone.api.utils;
|
|||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.util.EnumFacing;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic representation of a schematic. Provides the dimensions and
|
* Basic representation of a schematic. Provides the dimensions and the desired state for a given position relative to
|
||||||
* the desired statefor a given position relative to the origin.
|
* the origin.
|
||||||
*
|
*
|
||||||
* @author leijurv
|
* @author leijurv
|
||||||
*/
|
*/
|
||||||
@ -36,12 +38,13 @@ public interface ISchematic {
|
|||||||
* However, in the case of something like a map art, anything that's below the level of the map art doesn't matter,
|
* However, in the case of something like a map art, anything that's below the level of the map art doesn't matter,
|
||||||
* so this function should return false in that case. (i.e. it doesn't really have to be air below the art blocks)
|
* so this function should return false in that case. (i.e. it doesn't really have to be air below the art blocks)
|
||||||
*
|
*
|
||||||
* @param x The x position of the block, relative to the origin
|
* @param x The x position of the block, relative to the origin
|
||||||
* @param y The y position of the block, relative to the origin
|
* @param y The y position of the block, relative to the origin
|
||||||
* @param z The z position of the block, relative to the origin
|
* @param z The z position of the block, relative to the origin
|
||||||
|
* @param currentState The current state of that block in the world, or null
|
||||||
* @return Whether or not the specified position is within the bounds of this schematic
|
* @return Whether or not the specified position is within the bounds of this schematic
|
||||||
*/
|
*/
|
||||||
default boolean inSchematic(int x, int y, int z) {
|
default boolean inSchematic(int x, int y, int z, IBlockState currentState) {
|
||||||
return x >= 0 && x < widthX() && y >= 0 && y < heightY() && z >= 0 && z < lengthZ();
|
return x >= 0 && x < widthX() && y >= 0 && y < heightY() && z >= 0 && z < lengthZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,12 +64,14 @@ public interface ISchematic {
|
|||||||
/**
|
/**
|
||||||
* Returns the desired block state at a given (X, Y, Z) position relative to the origin (0, 0, 0).
|
* Returns the desired block state at a given (X, Y, Z) position relative to the origin (0, 0, 0).
|
||||||
*
|
*
|
||||||
* @param x The x position of the block, relative to the origin
|
* @param x The x position of the block, relative to the origin
|
||||||
* @param y The y position of the block, relative to the origin
|
* @param y The y position of the block, relative to the origin
|
||||||
* @param z The z position of the block, relative to the origin
|
* @param z The z position of the block, relative to the origin
|
||||||
|
* @param current The current state of that block in the world, or null
|
||||||
|
* @param approxPlaceable The list of blockstates estimated to be placeable
|
||||||
* @return The desired block state at the specified position
|
* @return The desired block state at the specified position
|
||||||
*/
|
*/
|
||||||
IBlockState desiredState(int x, int y, int z);
|
IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The width (X axis length) of this schematic
|
* @return The width (X axis length) of this schematic
|
||||||
@ -82,4 +87,4 @@ public interface ISchematic {
|
|||||||
* @return The length (Z axis length) of this schematic
|
* @return The length (Z axis length) of this schematic
|
||||||
*/
|
*/
|
||||||
int lengthZ();
|
int lengthZ();
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,4 @@ public class MyChunkPos {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return x + ", " + z;
|
return x + ", " + z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.NoSuchFileException;
|
import java.nio.file.NoSuchFileException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -42,6 +41,7 @@ import java.util.function.Function;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static net.minecraft.client.Minecraft.getMinecraft;
|
import static net.minecraft.client.Minecraft.getMinecraft;
|
||||||
|
|
||||||
@ -121,6 +121,40 @@ public class SettingsUtil {
|
|||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of a setting and returns it as a string, with package names stripped.
|
||||||
|
* <p>
|
||||||
|
* For example, if the setting type is {@code java.util.List<java.lang.String>}, this function returns
|
||||||
|
* {@code List<String>}.
|
||||||
|
*
|
||||||
|
* @param setting The setting
|
||||||
|
* @return The type
|
||||||
|
*/
|
||||||
|
public static String settingTypeToString(Settings.Setting setting) {
|
||||||
|
return setting.getType().getTypeName()
|
||||||
|
.replaceAll("(?:\\w+\\.)+(\\w+)", "$1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> String settingValueToString(Settings.Setting<T> setting, T value) throws IllegalArgumentException {
|
||||||
|
Parser io = Parser.getParser(setting.getType());
|
||||||
|
|
||||||
|
if (io == null) {
|
||||||
|
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.toString(new ParserContext(setting), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String settingValueToString(Settings.Setting setting) throws IllegalArgumentException {
|
||||||
|
//noinspection unchecked
|
||||||
|
return settingValueToString(setting, setting.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String settingDefaultToString(Settings.Setting setting) throws IllegalArgumentException {
|
||||||
|
//noinspection unchecked
|
||||||
|
return settingValueToString(setting, setting.defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
public static String maybeCensor(int coord) {
|
public static String maybeCensor(int coord) {
|
||||||
if (BaritoneAPI.getSettings().censorCoordinates.value) {
|
if (BaritoneAPI.getSettings().censorCoordinates.value) {
|
||||||
return "<censored>";
|
return "<censored>";
|
||||||
@ -133,11 +167,8 @@ public class SettingsUtil {
|
|||||||
if (setting.getName().equals("logger")) {
|
if (setting.getName().equals("logger")) {
|
||||||
return "logger";
|
return "logger";
|
||||||
}
|
}
|
||||||
Parser io = Parser.getParser(setting.getType());
|
|
||||||
if (io == null) {
|
return setting.getName() + " " + settingValueToString(setting);
|
||||||
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting.getName());
|
|
||||||
}
|
|
||||||
return setting.getName() + " " + io.toString(new ParserContext(setting), setting.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
|
public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
|
||||||
@ -183,6 +214,7 @@ public class SettingsUtil {
|
|||||||
INTEGER(Integer.class, Integer::parseInt),
|
INTEGER(Integer.class, Integer::parseInt),
|
||||||
FLOAT(Float.class, Float::parseFloat),
|
FLOAT(Float.class, Float::parseFloat),
|
||||||
LONG(Long.class, Long::parseLong),
|
LONG(Long.class, Long::parseLong),
|
||||||
|
STRING(String.class, String::new),
|
||||||
ENUMFACING(EnumFacing.class, EnumFacing::byName),
|
ENUMFACING(EnumFacing.class, EnumFacing::byName),
|
||||||
COLOR(
|
COLOR(
|
||||||
Color.class,
|
Color.class,
|
||||||
@ -210,7 +242,7 @@ public class SettingsUtil {
|
|||||||
Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
|
Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
|
||||||
Parser parser = Parser.getParser(type);
|
Parser parser = Parser.getParser(type);
|
||||||
|
|
||||||
return Arrays.stream(raw.split(","))
|
return Stream.of(raw.split(","))
|
||||||
.map(s -> parser.parse(context, s))
|
.map(s -> parser.parse(context, s))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@ -269,7 +301,7 @@ public class SettingsUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Parser getParser(Type type) {
|
public static Parser getParser(Type type) {
|
||||||
return Arrays.stream(values())
|
return Stream.of(values())
|
||||||
.filter(parser -> parser.accepts(type))
|
.filter(parser -> parser.accepts(type))
|
||||||
.findFirst().orElse(null);
|
.findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
112
src/api/java/baritone/api/utils/command/Command.java
Normal file
112
src/api/java/baritone/api/utils/command/Command.java
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command;
|
||||||
|
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.utils.Helper;
|
||||||
|
import baritone.api.utils.IPlayerContext;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.execution.ICommandExecution;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public abstract class Command implements Helper {
|
||||||
|
|
||||||
|
protected IBaritone baritone;
|
||||||
|
protected IPlayerContext ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names of this command. This is what you put after the command prefix.
|
||||||
|
*/
|
||||||
|
public final List<String> names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Baritone control command.
|
||||||
|
*
|
||||||
|
* @param names The names of this command. This is what you put after the command prefix.
|
||||||
|
*/
|
||||||
|
protected Command(IBaritone baritone, List<String> names) {
|
||||||
|
this.names = names.stream()
|
||||||
|
.map(s -> s.toLowerCase(Locale.US))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
this.baritone = baritone;
|
||||||
|
this.ctx = baritone.getPlayerContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Command(IBaritone baritone, String name) {
|
||||||
|
this(baritone, Collections.singletonList(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes this command with the specified arguments.
|
||||||
|
*
|
||||||
|
* @param execution The command execution to execute this command with
|
||||||
|
*/
|
||||||
|
public final void execute(ICommandExecution execution) throws CommandException {
|
||||||
|
this.executed(execution.getLabel(), execution.getArguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab completes this command with the specified arguments. Any exception that is thrown by
|
||||||
|
* {@link #tabCompleted(String, ArgConsumer)} will be caught by this method, and then {@link Stream#empty()}
|
||||||
|
* will be returned.
|
||||||
|
*
|
||||||
|
* @param execution The command execution to tab complete
|
||||||
|
* @return The list of completions.
|
||||||
|
*/
|
||||||
|
public final Stream<String> tabComplete(ICommandExecution execution) {
|
||||||
|
try {
|
||||||
|
return this.tabCompleted(execution.getLabel(), execution.getArguments());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this command is executed.
|
||||||
|
*/
|
||||||
|
protected abstract void executed(String label, ArgConsumer args) throws CommandException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the command needs to tab complete. Return a Stream representing the entries to put in the completions
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
protected abstract Stream<String> tabCompleted(String label, ArgConsumer args) throws CommandException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A <b>single-line</b> string containing a short description of this command's purpose.
|
||||||
|
*/
|
||||||
|
public abstract String getShortDesc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A list of lines that will be printed by the help command when the user wishes to view them.
|
||||||
|
*/
|
||||||
|
public abstract List<String> getLongDesc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if this command should be hidden from the help menu
|
||||||
|
*/
|
||||||
|
public boolean hiddenFromHelp() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command;
|
||||||
|
|
||||||
|
import baritone.api.Settings;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Brady
|
||||||
|
* @since 9/26/2019
|
||||||
|
*/
|
||||||
|
public interface IBaritoneChatControl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In certain cases chat components need to execute commands for you. For example, the paginator automatically runs
|
||||||
|
* commands when you click the forward and back arrows to show you the previous/next page.
|
||||||
|
* <p>
|
||||||
|
* If the prefix is changed in the meantime, then the command will go to chat. That's no good. So here's a permanent
|
||||||
|
* prefix that forces a command to run, regardless of the current prefix, chat/prefix control being enabled, etc.
|
||||||
|
* <p>
|
||||||
|
* If used right (by both developers and users), it should be impossible to expose a command accidentally to the
|
||||||
|
* server. As a rule of thumb, if you have a clickable chat component, always use this prefix. If you're suggesting
|
||||||
|
* a command (a component that puts text into your text box, or something else), use {@link Settings#prefix}.
|
||||||
|
*/
|
||||||
|
String FORCE_COMMAND_PREFIX = String.format("<<%s>>", UUID.randomUUID().toString());
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.argparser;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||||
|
import baritone.api.utils.command.exception.CommandNoParserForTypeException;
|
||||||
|
import baritone.api.utils.command.exception.CommandUnhandledException;
|
||||||
|
import baritone.api.utils.command.registry.Registry;
|
||||||
|
|
||||||
|
public class ArgParserManager {
|
||||||
|
|
||||||
|
public static final Registry<IArgParser> REGISTRY = new Registry<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
DefaultArgParsers.ALL.forEach(REGISTRY::register);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type The type trying to be parsed
|
||||||
|
* @return A parser that can parse arguments into this class, if found.
|
||||||
|
*/
|
||||||
|
public static <T> IArgParser.Stateless<T> getParserStateless(Class<T> type) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return REGISTRY.descendingStream()
|
||||||
|
.filter(IArgParser.Stateless.class::isInstance)
|
||||||
|
.map(IArgParser.Stateless.class::cast)
|
||||||
|
.filter(parser -> parser.getTarget().isAssignableFrom(type))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type The type trying to be parsed
|
||||||
|
* @return A parser that can parse arguments into this class, if found.
|
||||||
|
*/
|
||||||
|
public static <T, S> IArgParser.Stated<T, S> getParserStated(Class<T> type, Class<S> stateKlass) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return REGISTRY.descendingStream()
|
||||||
|
.filter(IArgParser.Stated.class::isInstance)
|
||||||
|
.map(IArgParser.Stated.class::cast)
|
||||||
|
.filter(parser -> parser.getTarget().isAssignableFrom(type))
|
||||||
|
.filter(parser -> parser.getStateType().isAssignableFrom(stateKlass))
|
||||||
|
.map(IArgParser.Stated.class::cast)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to parse the specified argument with a stateless {@link IArgParser} that outputs the specified class.
|
||||||
|
*
|
||||||
|
* @param type The type to try and parse the argument into.
|
||||||
|
* @param arg The argument to parse.
|
||||||
|
* @return An instance of the specified class.
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
*/
|
||||||
|
public static <T> T parseStateless(Class<T> type, CommandArgument arg) throws CommandInvalidTypeException {
|
||||||
|
IArgParser.Stateless<T> parser = getParserStateless(type);
|
||||||
|
if (parser == null) {
|
||||||
|
throw new CommandNoParserForTypeException(type);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return parser.parseArg(arg);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
throw new CommandInvalidTypeException(arg, type.getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to parse the specified argument with a stated {@link IArgParser} that outputs the specified class.
|
||||||
|
*
|
||||||
|
* @param type The type to try and parse the argument into.
|
||||||
|
* @param arg The argument to parse.
|
||||||
|
* @param state The state to pass to the {@link IArgParser.Stated}.
|
||||||
|
* @return An instance of the specified class.
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
* @see IArgParser.Stated
|
||||||
|
*/
|
||||||
|
public static <T, S> T parseStated(Class<T> type, Class<S> stateKlass, CommandArgument arg, S state) throws CommandInvalidTypeException {
|
||||||
|
IArgParser.Stated<T, S> parser = getParserStated(type, stateKlass);
|
||||||
|
if (parser == null) {
|
||||||
|
throw new CommandNoParserForTypeException(type);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return parser.parseArg(arg, state);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
throw new CommandInvalidTypeException(arg, type.getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.argparser;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class DefaultArgParsers {
|
||||||
|
|
||||||
|
public enum IntArgumentParser implements IArgParser.Stateless<Integer> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Integer> getTarget() {
|
||||||
|
return Integer.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer parseArg(CommandArgument arg) throws RuntimeException {
|
||||||
|
return Integer.parseInt(arg.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LongArgumentParser implements IArgParser.Stateless<Long> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Long> getTarget() {
|
||||||
|
return Long.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long parseArg(CommandArgument arg) throws RuntimeException {
|
||||||
|
return Long.parseLong(arg.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FloatArgumentParser implements IArgParser.Stateless<Float> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Float> getTarget() {
|
||||||
|
return Float.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float parseArg(CommandArgument arg) throws RuntimeException {
|
||||||
|
String value = arg.value;
|
||||||
|
if (!value.matches("^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$")) {
|
||||||
|
throw new IllegalArgumentException("failed float format check");
|
||||||
|
}
|
||||||
|
return Float.parseFloat(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DoubleArgumentParser implements IArgParser.Stateless<Double> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Double> getTarget() {
|
||||||
|
return Double.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double parseArg(CommandArgument arg) throws RuntimeException {
|
||||||
|
String value = arg.value;
|
||||||
|
if (!value.matches("^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$")) {
|
||||||
|
throw new IllegalArgumentException("failed double format check");
|
||||||
|
}
|
||||||
|
return Double.parseDouble(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BooleanArgumentParser implements IArgParser.Stateless<Boolean> {
|
||||||
|
|
||||||
|
public static final BooleanArgumentParser INSTANCE = new BooleanArgumentParser();
|
||||||
|
public static final List<String> TRUTHY_VALUES = Arrays.asList("1", "true", "yes", "t", "y", "on", "enable");
|
||||||
|
public static final List<String> FALSY_VALUES = Arrays.asList("0", "false", "no", "f", "n", "off", "disable");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Boolean> getTarget() {
|
||||||
|
return Boolean.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean parseArg(CommandArgument arg) throws RuntimeException {
|
||||||
|
String value = arg.value;
|
||||||
|
if (TRUTHY_VALUES.contains(value.toLowerCase(Locale.US))) {
|
||||||
|
return true;
|
||||||
|
} else if (FALSY_VALUES.contains(value.toLowerCase(Locale.US))) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("invalid boolean");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final List<IArgParser<?>> ALL = Arrays.asList(
|
||||||
|
IntArgumentParser.INSTANCE,
|
||||||
|
LongArgumentParser.INSTANCE,
|
||||||
|
FloatArgumentParser.INSTANCE,
|
||||||
|
DoubleArgumentParser.INSTANCE,
|
||||||
|
BooleanArgumentParser.INSTANCE
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.argparser;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
|
||||||
|
public interface IArgParser<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the class of this parser.
|
||||||
|
*/
|
||||||
|
Class<T> getTarget();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stateless argument parser is just that. It takes a {@link CommandArgument} and outputs its type.
|
||||||
|
*
|
||||||
|
* @see ArgParserManager#REGISTRY
|
||||||
|
*/
|
||||||
|
interface Stateless<T> extends IArgParser<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param arg The argument to parse.
|
||||||
|
* @return What it was parsed into.
|
||||||
|
* @throws RuntimeException if you want the parsing to fail. The exception will be caught and turned into an
|
||||||
|
* appropriate error.
|
||||||
|
*/
|
||||||
|
T parseArg(CommandArgument arg) throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stated argument parser is similar to a stateless one. It also takes a {@link CommandArgument}, but it also
|
||||||
|
* takes a second argument that can be any type, referred to as the state.
|
||||||
|
*
|
||||||
|
* @see ArgParserManager#REGISTRY
|
||||||
|
*/
|
||||||
|
interface Stated<T, S> extends IArgParser<T> {
|
||||||
|
|
||||||
|
Class<S> getStateType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param arg The argument to parse.
|
||||||
|
* @param state Can be anything.
|
||||||
|
* @return What it was parsed into.
|
||||||
|
* @throws RuntimeException if you want the parsing to fail. The exception will be caught and turned into an
|
||||||
|
* appropriate error.
|
||||||
|
*/
|
||||||
|
T parseArg(CommandArgument arg, S state) throws Exception;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.argument;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argparser.ArgParserManager;
|
||||||
|
import baritone.api.utils.command.argparser.IArgParser;
|
||||||
|
import baritone.api.utils.command.exception.CommandInvalidArgumentException;
|
||||||
|
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link CommandArgument} is an immutable object representing one command argument. It contains data on the index of
|
||||||
|
* that argument, its value, and the rest of the string that argument was found in
|
||||||
|
* <p>
|
||||||
|
* You're recommended to use {@link ArgConsumer}s to handle these.
|
||||||
|
*/
|
||||||
|
public class CommandArgument {
|
||||||
|
|
||||||
|
public final int index;
|
||||||
|
public final String value;
|
||||||
|
public final String rawRest;
|
||||||
|
public final static Pattern argPattern = Pattern.compile("\\S+");
|
||||||
|
|
||||||
|
private CommandArgument(int index, String value, String rawRest) {
|
||||||
|
this.index = index;
|
||||||
|
this.value = value;
|
||||||
|
this.rawRest = rawRest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an enum value from the enum class with the same name as this argument's value
|
||||||
|
* <p>
|
||||||
|
* For example if you getEnum as an {@link EnumFacing}, and this argument's value is "up", it will return {@link
|
||||||
|
* EnumFacing#UP}
|
||||||
|
*
|
||||||
|
* @param enumClass The enum class to search
|
||||||
|
* @return An enum constant of that class with the same name as this argument's value
|
||||||
|
* @throws CommandInvalidTypeException If the constant couldn't be found
|
||||||
|
* @see ArgConsumer#peekEnum(Class)
|
||||||
|
* @see ArgConsumer#peekEnum(Class, int)
|
||||||
|
* @see ArgConsumer#peekEnumOrNull(Class)
|
||||||
|
* @see ArgConsumer#peekEnumOrNull(Class, int)
|
||||||
|
* @see ArgConsumer#getEnum(Class)
|
||||||
|
* @see ArgConsumer#getEnumOrNull(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E getEnum(Class<E> enumClass) throws CommandInvalidTypeException {
|
||||||
|
return Stream.of(enumClass.getEnumConstants())
|
||||||
|
.filter(e -> e.name().equalsIgnoreCase(value))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new CommandInvalidTypeException(this, enumClass.getSimpleName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse this argument into the specified class
|
||||||
|
*
|
||||||
|
* @param type The class to parse this argument into
|
||||||
|
* @return An instance of the specified type
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
*/
|
||||||
|
public <T> T getAs(Class<T> type) throws CommandInvalidTypeException {
|
||||||
|
return ArgParserManager.parseStateless(type, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse this argument into the specified class
|
||||||
|
*
|
||||||
|
* @param type The class to parse this argument into
|
||||||
|
* @return If the parser succeeded
|
||||||
|
*/
|
||||||
|
public <T> boolean is(Class<T> type) {
|
||||||
|
try {
|
||||||
|
getAs(type);
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stated</b> {@link IArgParser} to parse this argument into the specified class
|
||||||
|
*
|
||||||
|
* @param type The class to parse this argument into
|
||||||
|
* @return An instance of the specified type
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedReturnValue")
|
||||||
|
public <T, S> T getAs(Class<T> type, Class<S> stateType, S state) throws CommandInvalidTypeException {
|
||||||
|
return ArgParserManager.parseStated(type, stateType, this, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stated</b> {@link IArgParser} to parse this argument into the specified class
|
||||||
|
*
|
||||||
|
* @param type The class to parse this argument into
|
||||||
|
* @return If the parser succeeded
|
||||||
|
*/
|
||||||
|
public <T, S> boolean is(Class<T> type, Class<S> stateType, S state) {
|
||||||
|
try {
|
||||||
|
getAs(type, stateType, state);
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn a string into a list of {@link CommandArgument}s. This is needed because of {@link CommandArgument#rawRest}
|
||||||
|
*
|
||||||
|
* @param string The string to convert
|
||||||
|
* @param preserveEmptyLast If the string ends with whitespace, add an empty {@link CommandArgument} to the end This
|
||||||
|
* is useful for tab completion
|
||||||
|
* @return A list of {@link CommandArgument}s
|
||||||
|
*/
|
||||||
|
public static List<CommandArgument> from(String string, boolean preserveEmptyLast) {
|
||||||
|
List<CommandArgument> args = new ArrayList<>();
|
||||||
|
Matcher argMatcher = argPattern.matcher(string);
|
||||||
|
int lastEnd = -1;
|
||||||
|
while (argMatcher.find()) {
|
||||||
|
args.add(new CommandArgument(
|
||||||
|
args.size(),
|
||||||
|
argMatcher.group(),
|
||||||
|
string.substring(argMatcher.start())
|
||||||
|
));
|
||||||
|
lastEnd = argMatcher.end();
|
||||||
|
}
|
||||||
|
if (preserveEmptyLast && lastEnd < string.length()) {
|
||||||
|
args.add(new CommandArgument(args.size(), "", ""));
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #from(String, boolean)
|
||||||
|
*/
|
||||||
|
public static List<CommandArgument> from(String string) {
|
||||||
|
return from(string, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an "unknown" {@link CommandArgument}. This shouldn't be used unless you absolutely have no information -
|
||||||
|
* ESPECIALLY not with {@link CommandInvalidArgumentException}s
|
||||||
|
*
|
||||||
|
* @return The unknown {@link CommandArgument}
|
||||||
|
*/
|
||||||
|
public static CommandArgument unknown() {
|
||||||
|
return new CommandArgument(-1, "<unknown>", "");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.init.Blocks;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum BlockById implements IDatatypeFor<Block> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Block get(IDatatypeContext ctx) throws CommandException {
|
||||||
|
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
|
||||||
|
Block block;
|
||||||
|
if ((block = Block.REGISTRY.getObject(id)) == Blocks.AIR) {
|
||||||
|
throw new IllegalArgumentException("no block found by that id");
|
||||||
|
}
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(
|
||||||
|
Block.REGISTRY.getKeys()
|
||||||
|
.stream()
|
||||||
|
.map(Object::toString)
|
||||||
|
)
|
||||||
|
.filterPrefixNamespaced(ctx.getConsumer().getString())
|
||||||
|
.sortAlphabetically()
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityList;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum EntityClassById implements IDatatypeFor<Class<? extends Entity>> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Entity> get(IDatatypeContext ctx) throws CommandException {
|
||||||
|
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
|
||||||
|
Class<? extends Entity> entity;
|
||||||
|
if ((entity = EntityList.REGISTRY.getObject(id)) == null) {
|
||||||
|
throw new IllegalArgumentException("no entity found by that id");
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(EntityList.getEntityNameList().stream().map(Object::toString))
|
||||||
|
.filterPrefixNamespaced(ctx.getConsumer().getString())
|
||||||
|
.sortAlphabetically()
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.BlockOptionalMeta;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum ForBlockOptionalMeta implements IDatatypeFor<BlockOptionalMeta> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockOptionalMeta get(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return new BlockOptionalMeta(ctx.getConsumer().getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||||
|
return ctx.getConsumer().tabCompleteDatatype(BlockById.INSTANCE);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum ForEnumFacing implements IDatatypeFor<EnumFacing> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumFacing get(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return EnumFacing.valueOf(ctx.getConsumer().getString().toUpperCase(Locale.US));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(Stream.of(EnumFacing.values())
|
||||||
|
.map(EnumFacing::getName).map(String::toLowerCase))
|
||||||
|
.filterPrefix(ctx.getConsumer().getString())
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.cache.IWaypoint;
|
||||||
|
import baritone.api.cache.IWaypointCollection;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum ForWaypoints implements IDatatypeFor<IWaypoint[]> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IWaypoint[] get(IDatatypeContext ctx) throws CommandException {
|
||||||
|
final String input = ctx.getConsumer().getString();
|
||||||
|
final IWaypoint.Tag tag = IWaypoint.Tag.getByName(input);
|
||||||
|
|
||||||
|
// If the input doesn't resolve to a valid tag, resolve by name
|
||||||
|
return tag == null
|
||||||
|
? getWaypointsByName(ctx.getBaritone(), input)
|
||||||
|
: getWaypointsByTag(ctx.getBaritone(), tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(getWaypointNames(ctx.getBaritone()))
|
||||||
|
.sortAlphabetically()
|
||||||
|
.prepend(IWaypoint.Tag.getAllNames())
|
||||||
|
.filterPrefix(ctx.getConsumer().getString())
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWaypointCollection waypoints(IBaritone baritone) {
|
||||||
|
return baritone.getWorldProvider().getCurrentWorld().getWaypoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWaypoint[] getWaypoints(IBaritone baritone) {
|
||||||
|
return waypoints(baritone).getAllWaypoints().stream()
|
||||||
|
.sorted(Comparator.comparingLong(IWaypoint::getCreationTimestamp).reversed())
|
||||||
|
.toArray(IWaypoint[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getWaypointNames(IBaritone baritone) {
|
||||||
|
return Stream.of(getWaypoints(baritone))
|
||||||
|
.map(IWaypoint::getName)
|
||||||
|
.filter(name -> !name.isEmpty())
|
||||||
|
.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWaypoint[] getWaypointsByTag(IBaritone baritone, IWaypoint.Tag tag) {
|
||||||
|
return waypoints(baritone).getByTag(tag).stream()
|
||||||
|
.sorted(Comparator.comparingLong(IWaypoint::getCreationTimestamp).reversed())
|
||||||
|
.toArray(IWaypoint[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWaypoint[] getWaypointsByName(IBaritone baritone, String name) {
|
||||||
|
return Stream.of(getWaypoints(baritone))
|
||||||
|
.filter(waypoint -> waypoint.getName().equalsIgnoreCase(name))
|
||||||
|
.toArray(IWaypoint[]::new);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argparser.IArgParser;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link IDatatype} is similar to an {@link IArgParser} in the sense that it is capable of consuming an argument
|
||||||
|
* to transform it into a usable form as the code desires.
|
||||||
|
* <p>
|
||||||
|
* A fundamental difference is that an {@link IDatatype} is capable of consuming multiple arguments. For example,
|
||||||
|
* {@link RelativeBlockPos} is an {@link IDatatypePost} which requires at least 3 {@link RelativeCoordinate} arguments
|
||||||
|
* to be specified.
|
||||||
|
* <p>
|
||||||
|
* Another difference is that an {@link IDatatype} can be tab-completed, providing comprehensive auto completion
|
||||||
|
* that can substitute based on existing input or provide possibilities for the next piece of input.
|
||||||
|
*
|
||||||
|
* @see IDatatypeContext
|
||||||
|
* @see IDatatypeFor
|
||||||
|
* @see IDatatypePost
|
||||||
|
*/
|
||||||
|
public interface IDatatype {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to complete missing or partial input provided through the {@link ArgConsumer} provided by
|
||||||
|
* {@link IDatatypeContext#getConsumer()} in order to aide the user in executing commands.
|
||||||
|
* <p>
|
||||||
|
* One benefit over datatypes over {@link IArgParser}s is that instead of each command trying to guess what values
|
||||||
|
* the datatype will accept, or simply not tab completing at all, datatypes that support tab completion can provide
|
||||||
|
* accurate information using the same methods used to parse arguments in the first place.
|
||||||
|
*
|
||||||
|
* @param ctx The argument consumer to tab complete
|
||||||
|
* @return A stream representing the strings that can be tab completed. DO NOT INCLUDE SPACES IN ANY STRINGS.
|
||||||
|
* @see ArgConsumer#tabCompleteDatatype(IDatatype)
|
||||||
|
*/
|
||||||
|
Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException;
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an {@link IDatatype} with contextual information so
|
||||||
|
* that it can perform the desired operation on the target level.
|
||||||
|
*
|
||||||
|
* @see IDatatype
|
||||||
|
*
|
||||||
|
* @author Brady
|
||||||
|
* @since 9/26/2019
|
||||||
|
*/
|
||||||
|
public interface IDatatypeContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the {@link IBaritone} instance that is associated with the action relating to datatype handling.
|
||||||
|
*
|
||||||
|
* @return The context {@link IBaritone} instance.
|
||||||
|
*/
|
||||||
|
IBaritone getBaritone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the {@link ArgConsumer} to fetch input information from.
|
||||||
|
*
|
||||||
|
* @return The context {@link ArgConsumer}.
|
||||||
|
*/
|
||||||
|
ArgConsumer getConsumer();
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link IDatatype} which acts as a {@link Supplier}, in essence. The only difference
|
||||||
|
* is that it requires an {@link IDatatypeContext} to be provided due to the expectation that
|
||||||
|
* implementations of {@link IDatatype} are singletons.
|
||||||
|
*/
|
||||||
|
public interface IDatatypeFor<T> extends IDatatype {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consumes the desired amount of arguments from the specified {@link IDatatypeContext}, and
|
||||||
|
* then returns the parsed value. This method will more than likely return a {@link IllegalArgumentException}
|
||||||
|
* if the expected input does not conform to a parseable value. As far as a {@link CommandException} being
|
||||||
|
* thrown is concerned, see the note below for specifics.
|
||||||
|
*
|
||||||
|
* @see IDatatypeContext
|
||||||
|
*
|
||||||
|
* @param ctx The context
|
||||||
|
* @return The parsed data-type
|
||||||
|
* @throws CommandException If there was an issue parsing using another type or arguments could not be polled.
|
||||||
|
*/
|
||||||
|
T get(IDatatypeContext ctx) throws CommandException;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link IDatatype} which acts as a {@link Function}, in essence. The only difference
|
||||||
|
* is that it requires an {@link IDatatypeContext} to be provided due to the expectation that
|
||||||
|
* implementations of {@link IDatatype} are singletons.
|
||||||
|
*/
|
||||||
|
public interface IDatatypePost<T, O> extends IDatatype {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the expected input and transforms it based on the value held by {@code original}. If {@code original}
|
||||||
|
* is null, it is expected that the implementation of this method has a case to handle it, such that a
|
||||||
|
* {@link NullPointerException} will never be thrown as a result.
|
||||||
|
*
|
||||||
|
* @param ctx The datatype context
|
||||||
|
* @param original The transformable value
|
||||||
|
* @return The transformed value
|
||||||
|
*/
|
||||||
|
T apply(IDatatypeContext ctx, O original) throws CommandException;
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Brady
|
||||||
|
* @since 9/26/2019
|
||||||
|
*/
|
||||||
|
public interface IDatatypePostFunction<T, O> {
|
||||||
|
|
||||||
|
T apply(O original) throws CommandException;
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link IDatatype} used to resolve nearby players, those within
|
||||||
|
* render distance of the target {@link IBaritone} instance.
|
||||||
|
*/
|
||||||
|
public enum NearbyPlayer implements IDatatypeFor<EntityPlayer> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityPlayer get(IDatatypeContext ctx) throws CommandException {
|
||||||
|
final String username = ctx.getConsumer().getString();
|
||||||
|
return getPlayers(ctx).stream()
|
||||||
|
.filter(s -> s.getName().equalsIgnoreCase(username))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(getPlayers(ctx).stream().map(EntityPlayer::getName))
|
||||||
|
.filterPrefix(ctx.getConsumer().getString())
|
||||||
|
.sortAlphabetically()
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<EntityPlayer> getPlayers(IDatatypeContext ctx) {
|
||||||
|
return ctx.getBaritone().getPlayerContext().world().playerEntities;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum RelativeBlockPos implements IDatatypePost<BetterBlockPos, BetterBlockPos> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BetterBlockPos apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
|
||||||
|
if (origin == null) {
|
||||||
|
origin = BetterBlockPos.ORIGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
return new BetterBlockPos(
|
||||||
|
consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x),
|
||||||
|
consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y),
|
||||||
|
consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
if (consumer.hasAny() && !consumer.has(4)) {
|
||||||
|
while (consumer.has(2)) {
|
||||||
|
if (consumer.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
consumer.get();
|
||||||
|
}
|
||||||
|
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum RelativeCoordinate implements IDatatypePost<Double, Double> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double apply(IDatatypeContext ctx, Double origin) throws CommandException {
|
||||||
|
if (origin == null) {
|
||||||
|
origin = 0.0D;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = PATTERN.matcher(ctx.getConsumer().getString());
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
throw new IllegalArgumentException("pattern doesn't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isRelative = !matcher.group(1).isEmpty();
|
||||||
|
double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2));
|
||||||
|
|
||||||
|
if (isRelative) {
|
||||||
|
return origin + offset;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
if (!consumer.has(2) && consumer.getString().matches("^(~|$)")) {
|
||||||
|
return Stream.of("~");
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.InvalidPathException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static baritone.api.utils.Helper.HELPER;
|
||||||
|
|
||||||
|
public enum RelativeFile implements IDatatypePost<File, File> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File apply(IDatatypeContext ctx, File original) throws CommandException {
|
||||||
|
if (original == null) {
|
||||||
|
original = new File("./");
|
||||||
|
}
|
||||||
|
|
||||||
|
Path path;
|
||||||
|
try {
|
||||||
|
path = FileSystems.getDefault().getPath(ctx.getConsumer().getString());
|
||||||
|
} catch (InvalidPathException e) {
|
||||||
|
throw new IllegalArgumentException("invalid path");
|
||||||
|
}
|
||||||
|
return getCanonicalFileUnchecked(original.toPath().resolve(path).toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seriously
|
||||||
|
*
|
||||||
|
* @param file File
|
||||||
|
* @return Canonical file of file
|
||||||
|
* @author LoganDark
|
||||||
|
*/
|
||||||
|
private static File getCanonicalFileUnchecked(File file) {
|
||||||
|
try {
|
||||||
|
return file.getCanonicalFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<String> tabComplete(ArgConsumer consumer, File base0) throws CommandException {
|
||||||
|
// I will not make the caller deal with this, seriously
|
||||||
|
// Tab complete code is beautiful and I'm not going to bloat it with dumb ass checked exception bullshit -LoganDark
|
||||||
|
|
||||||
|
// lol owned -Brady
|
||||||
|
|
||||||
|
File base = getCanonicalFileUnchecked(base0);
|
||||||
|
String currentPathStringThing = consumer.getString();
|
||||||
|
Path currentPath = FileSystems.getDefault().getPath(currentPathStringThing);
|
||||||
|
Path basePath = currentPath.isAbsolute() ? currentPath.getRoot() : base.toPath();
|
||||||
|
boolean useParent = !currentPathStringThing.isEmpty() && !currentPathStringThing.endsWith(File.separator);
|
||||||
|
File currentFile = currentPath.isAbsolute() ? currentPath.toFile() : new File(base, currentPathStringThing);
|
||||||
|
return Stream.of(Objects.requireNonNull(getCanonicalFileUnchecked(
|
||||||
|
useParent
|
||||||
|
? currentFile.getParentFile()
|
||||||
|
: currentFile
|
||||||
|
).listFiles()))
|
||||||
|
.map(f -> (currentPath.isAbsolute() ? f : basePath.relativize(f.toPath()).toString()) +
|
||||||
|
(f.isDirectory() ? File.separator : ""))
|
||||||
|
.filter(s -> s.toLowerCase(Locale.US).startsWith(currentPathStringThing.toLowerCase(Locale.US)))
|
||||||
|
.filter(s -> !s.contains(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File gameDir() {
|
||||||
|
File gameDir = HELPER.mc.gameDir.getAbsoluteFile();
|
||||||
|
if (gameDir.getName().equals(".")) {
|
||||||
|
return gameDir.getParentFile();
|
||||||
|
}
|
||||||
|
return gameDir;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.pathing.goals.Goal;
|
||||||
|
import baritone.api.pathing.goals.GoalBlock;
|
||||||
|
import baritone.api.pathing.goals.GoalXZ;
|
||||||
|
import baritone.api.pathing.goals.GoalYLevel;
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum RelativeGoal implements IDatatypePost<Goal, BetterBlockPos> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Goal apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
|
||||||
|
if (origin == null) {
|
||||||
|
origin = BetterBlockPos.ORIGIN;
|
||||||
|
}
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
|
||||||
|
List<IDatatypePostFunction<Double, Double>> coords = new ArrayList<>();
|
||||||
|
final ArgConsumer copy = consumer.copy(); // This is a hack and should be fixed in the future probably
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (copy.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) {
|
||||||
|
coords.add(o -> consumer.getDatatypePost(RelativeCoordinate.INSTANCE, o));
|
||||||
|
copy.get(); // Consume so we actually decrement the remaining arguments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (coords.size()) {
|
||||||
|
case 0:
|
||||||
|
return new GoalBlock(origin);
|
||||||
|
case 1:
|
||||||
|
return new GoalYLevel(
|
||||||
|
MathHelper.floor(coords.get(0).apply((double) origin.y))
|
||||||
|
);
|
||||||
|
case 2:
|
||||||
|
return new GoalXZ(
|
||||||
|
MathHelper.floor(coords.get(0).apply((double) origin.x)),
|
||||||
|
MathHelper.floor(coords.get(1).apply((double) origin.z))
|
||||||
|
);
|
||||||
|
case 3:
|
||||||
|
return new GoalBlock(
|
||||||
|
MathHelper.floor(coords.get(0).apply((double) origin.x)),
|
||||||
|
MathHelper.floor(coords.get(1).apply((double) origin.y)),
|
||||||
|
MathHelper.floor(coords.get(2).apply((double) origin.z))
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unexpected coords size: " + coords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||||
|
return ctx.getConsumer().tabCompleteDatatype(RelativeCoordinate.INSTANCE);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.pathing.goals.GoalBlock;
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum RelativeGoalBlock implements IDatatypePost<GoalBlock, BetterBlockPos> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GoalBlock apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
|
||||||
|
if (origin == null) {
|
||||||
|
origin = BetterBlockPos.ORIGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
return new GoalBlock(
|
||||||
|
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x)),
|
||||||
|
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y)),
|
||||||
|
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.z))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
if (consumer.hasAtMost(3)) {
|
||||||
|
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.pathing.goals.GoalXZ;
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum RelativeGoalXZ implements IDatatypePost<GoalXZ, BetterBlockPos> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GoalXZ apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
|
||||||
|
if (origin == null) {
|
||||||
|
origin = BetterBlockPos.ORIGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
return new GoalXZ(
|
||||||
|
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x)),
|
||||||
|
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
if (consumer.hasAtMost(2)) {
|
||||||
|
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.pathing.goals.GoalYLevel;
|
||||||
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum RelativeGoalYLevel implements IDatatypePost<GoalYLevel, BetterBlockPos> {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GoalYLevel apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
|
||||||
|
if (origin == null) {
|
||||||
|
origin = BetterBlockPos.ORIGIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GoalYLevel(
|
||||||
|
MathHelper.floor(ctx.getConsumer().getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||||
|
final ArgConsumer consumer = ctx.getConsumer();
|
||||||
|
if (consumer.hasAtMost(1)) {
|
||||||
|
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
public abstract class CommandErrorMessageException extends CommandException {
|
||||||
|
|
||||||
|
protected CommandErrorMessageException(String reason) {
|
||||||
|
super(reason);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
public abstract class CommandException extends Exception implements ICommandException {
|
||||||
|
|
||||||
|
protected CommandException(String reason) {
|
||||||
|
super(reason);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
|
||||||
|
public abstract class CommandInvalidArgumentException extends CommandErrorMessageException {
|
||||||
|
|
||||||
|
public final CommandArgument arg;
|
||||||
|
|
||||||
|
protected CommandInvalidArgumentException(CommandArgument arg, String reason) {
|
||||||
|
super(String.format(
|
||||||
|
"Error at argument #%s: %s",
|
||||||
|
arg.index == -1 ? "<unknown>" : Integer.toString(arg.index + 1),
|
||||||
|
reason
|
||||||
|
));
|
||||||
|
this.arg = arg;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
public class CommandInvalidStateException extends CommandErrorMessageException {
|
||||||
|
|
||||||
|
public CommandInvalidStateException(String reason) {
|
||||||
|
super(reason);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
|
||||||
|
public class CommandInvalidTypeException extends CommandInvalidArgumentException {
|
||||||
|
|
||||||
|
public CommandInvalidTypeException(CommandArgument arg, String expected) {
|
||||||
|
super(arg, String.format("Expected %s", expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandInvalidTypeException(CommandArgument arg, String expected, Throwable cause) {
|
||||||
|
super(arg, String.format("Expected %s.\nMore details: %s", expected, cause.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandInvalidTypeException(CommandArgument arg, String expected, String got) {
|
||||||
|
super(arg, String.format("Expected %s, but got %s instead", expected, got));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandInvalidTypeException(CommandArgument arg, String expected, String got, Throwable cause) {
|
||||||
|
super(arg, String.format("Expected %s, but got %s instead.\nMore details: %s", expected, got, cause.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
public class CommandNoParserForTypeException extends CommandUnhandledException {
|
||||||
|
|
||||||
|
public CommandNoParserForTypeException(Class<?> klass) {
|
||||||
|
super(String.format("Could not find a handler for type %s", klass.getSimpleName()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
public class CommandNotEnoughArgumentsException extends CommandErrorMessageException {
|
||||||
|
|
||||||
|
public CommandNotEnoughArgumentsException(int minArgs) {
|
||||||
|
super(String.format("Not enough arguments (expected at least %d)", minArgs));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.Command;
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static baritone.api.utils.Helper.HELPER;
|
||||||
|
|
||||||
|
public class CommandNotFoundException extends CommandException {
|
||||||
|
|
||||||
|
public final String command;
|
||||||
|
|
||||||
|
public CommandNotFoundException(String command) {
|
||||||
|
super(String.format("Command not found: %s", command));
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Command command, List<CommandArgument> args) {
|
||||||
|
HELPER.logDirect(getMessage());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
public class CommandTooManyArgumentsException extends CommandErrorMessageException {
|
||||||
|
|
||||||
|
public CommandTooManyArgumentsException(int maxArgs) {
|
||||||
|
super(String.format("Too many arguments (expected at most %d)", maxArgs));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.Command;
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static baritone.api.utils.Helper.HELPER;
|
||||||
|
|
||||||
|
public class CommandUnhandledException extends RuntimeException implements ICommandException {
|
||||||
|
|
||||||
|
public CommandUnhandledException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandUnhandledException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Command command, List<CommandArgument> args) {
|
||||||
|
HELPER.logDirect("An unhandled exception occurred." +
|
||||||
|
"The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
|
||||||
|
TextFormatting.RED);
|
||||||
|
|
||||||
|
this.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.exception;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.Command;
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static baritone.api.utils.Helper.HELPER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base for a Baritone Command Exception, checked or unchecked. Provides a
|
||||||
|
* {@link #handle(Command, List)} method that is used to provide useful output
|
||||||
|
* to the user for diagnosing issues that may have occurred during execution.
|
||||||
|
* <p>
|
||||||
|
* Anything implementing this interface should be assignable to {@link Exception}.
|
||||||
|
*
|
||||||
|
* @author Brady
|
||||||
|
* @since 9/20/2019
|
||||||
|
*/
|
||||||
|
public interface ICommandException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Exception#getMessage()
|
||||||
|
* @return The exception details
|
||||||
|
*/
|
||||||
|
String getMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this exception is thrown, to handle the exception.
|
||||||
|
*
|
||||||
|
* @param command The command that threw it.
|
||||||
|
* @param args The arguments the command was called with.
|
||||||
|
*/
|
||||||
|
default void handle(Command command, List<CommandArgument> args) {
|
||||||
|
HELPER.logDirect(this.getMessage(), TextFormatting.RED);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.execution;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.Command;
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import net.minecraft.util.Tuple;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Brady
|
||||||
|
* @since 9/28/2019
|
||||||
|
*/
|
||||||
|
public interface ICommandExecution {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The label that was used to target the {@link Command}
|
||||||
|
*/
|
||||||
|
String getLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The arguments to be passed to the {@link Command}
|
||||||
|
*/
|
||||||
|
ArgConsumer getArguments();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the target command for this {@link ICommandExecution}. This method should never
|
||||||
|
* {@code throw} any exception, anything that is thrown during the target command execution
|
||||||
|
* should be safely handled.
|
||||||
|
*/
|
||||||
|
void execute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forwards this {@link ICommandExecution} to the target {@link Command} to perform a tab-completion.
|
||||||
|
* If the tab-completion operation is a failure, then {@link Stream#empty()} will be returned.
|
||||||
|
*
|
||||||
|
* @return The tab-completed arguments, if possible.
|
||||||
|
*/
|
||||||
|
Stream<String> tabComplete();
|
||||||
|
|
||||||
|
static Tuple<String, List<CommandArgument>> expand(String string, boolean preserveEmptyLast) {
|
||||||
|
String label = string.split("\\s", 2)[0];
|
||||||
|
List<CommandArgument> args = CommandArgument.from(string.substring(label.length()), preserveEmptyLast);
|
||||||
|
return new Tuple<>(label, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Tuple<String, List<CommandArgument>> expand(String string) {
|
||||||
|
return expand(string, false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,818 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.helpers.arguments;
|
||||||
|
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.utils.Helper;
|
||||||
|
import baritone.api.utils.command.Command;
|
||||||
|
import baritone.api.utils.command.argparser.IArgParser;
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
import baritone.api.utils.command.datatypes.IDatatype;
|
||||||
|
import baritone.api.utils.command.datatypes.IDatatypeContext;
|
||||||
|
import baritone.api.utils.command.datatypes.IDatatypeFor;
|
||||||
|
import baritone.api.utils.command.datatypes.IDatatypePost;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||||
|
import baritone.api.utils.command.exception.CommandNotEnoughArgumentsException;
|
||||||
|
import baritone.api.utils.command.exception.CommandTooManyArgumentsException;
|
||||||
|
import baritone.api.utils.command.manager.ICommandManager;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ArgConsumer} is how {@link Command}s read the arguments passed to them. This class has many benefits:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Mutability. The whole concept of the {@link ArgConsumer} is to let you gradually consume arguments in any way
|
||||||
|
* you'd like. You can change your consumption based on earlier arguments, for subcommands for example.</li>
|
||||||
|
* <li>You don't need to keep track of your consumption. The {@link ArgConsumer} keeps track of the arguments you
|
||||||
|
* consume so that it can throw detailed exceptions whenever something is out of the ordinary. Additionally, if you
|
||||||
|
* need to retrieve an argument after you've already consumed it - look no further than {@link #consumed()}!</li>
|
||||||
|
* <li>Easy retrieval of many different types. If you need to retrieve an instance of an int or float for example,
|
||||||
|
* look no further than {@link #getAs(Class)}. If you need a more powerful way of retrieving data, try out the many
|
||||||
|
* {@code getDatatype...} methods.</li>
|
||||||
|
* <li>It's very easy to throw detailed exceptions. The {@link ArgConsumer} has many different methods that can
|
||||||
|
* enforce the number of arguments, the type of arguments, and more, throwing different types of
|
||||||
|
* {@link CommandException}s if something seems off. You're recommended to do all validation and store all needed
|
||||||
|
* data in variables BEFORE logging any data to chat via {@link Helper#logDirect(String)}, so that the error
|
||||||
|
* handlers can do their job and log the error to chat.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public class ArgConsumer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent {@link ICommandManager} for this {@link ArgConsumer}. Used by {@link #context}.
|
||||||
|
*/
|
||||||
|
private final ICommandManager manager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link IDatatypeContext} instance for this {@link ArgConsumer}, passed to
|
||||||
|
* datatypes when an operation is performed upon them.
|
||||||
|
*
|
||||||
|
* @see IDatatype
|
||||||
|
* @see IDatatypeContext
|
||||||
|
*/
|
||||||
|
private final IDatatypeContext context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of arguments in this ArgConsumer
|
||||||
|
*/
|
||||||
|
public final LinkedList<CommandArgument> args;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of consumed arguments for this ArgConsumer. The most recently consumed argument is the last one
|
||||||
|
*/
|
||||||
|
public final Deque<CommandArgument> consumed;
|
||||||
|
|
||||||
|
private ArgConsumer(ICommandManager manager, Deque<CommandArgument> args, Deque<CommandArgument> consumed) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.context = this.new Context();
|
||||||
|
this.args = new LinkedList<>(args);
|
||||||
|
this.consumed = new LinkedList<>(consumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArgConsumer(ICommandManager manager, List<CommandArgument> args) {
|
||||||
|
this(manager, new LinkedList<>(args), new LinkedList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param num The number of arguments to check for
|
||||||
|
* @return {@code true} if there are <i>at least</i> {@code num} arguments left in this {@link ArgConsumer}
|
||||||
|
* @see #hasAny()
|
||||||
|
* @see #hasAtMost(int)
|
||||||
|
* @see #hasExactly(int)
|
||||||
|
*/
|
||||||
|
public boolean has(int num) {
|
||||||
|
return args.size() >= num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if there is <i>at least</i> 1 argument left in this {@link ArgConsumer}
|
||||||
|
* @see #has(int)
|
||||||
|
* @see #hasAtMostOne()
|
||||||
|
* @see #hasExactlyOne()
|
||||||
|
*/
|
||||||
|
public boolean hasAny() {
|
||||||
|
return has(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param num The number of arguments to check for
|
||||||
|
* @return {@code true} if there are <i>at most</i> {@code num} arguments left in this {@link ArgConsumer}
|
||||||
|
* @see #has(int)
|
||||||
|
* @see #hasAtMost(int)
|
||||||
|
* @see #hasExactly(int)
|
||||||
|
*/
|
||||||
|
public boolean hasAtMost(int num) {
|
||||||
|
return args.size() <= num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if there is <i>at most</i> 1 argument left in this {@link ArgConsumer}
|
||||||
|
* @see #hasAny()
|
||||||
|
* @see #hasAtMostOne()
|
||||||
|
* @see #hasExactlyOne()
|
||||||
|
*/
|
||||||
|
public boolean hasAtMostOne() {
|
||||||
|
return hasAtMost(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param num The number of arguments to check for
|
||||||
|
* @return {@code true} if there are <i>exactly</i> {@code num} arguments left in this {@link ArgConsumer}
|
||||||
|
* @see #has(int)
|
||||||
|
* @see #hasAtMost(int)
|
||||||
|
*/
|
||||||
|
public boolean hasExactly(int num) {
|
||||||
|
return args.size() == num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if there is <i>exactly</i> 1 argument left in this {@link ArgConsumer}
|
||||||
|
* @see #hasAny()
|
||||||
|
* @see #hasAtMostOne()
|
||||||
|
*/
|
||||||
|
public boolean hasExactlyOne() {
|
||||||
|
return hasExactly(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index The index to peek
|
||||||
|
* @return The argument at index {@code index} in this {@link ArgConsumer}, with 0 being the next one. This does not
|
||||||
|
* mutate the {@link ArgConsumer}
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there is less than {@code index + 1} arguments left
|
||||||
|
* @see #peek()
|
||||||
|
* @see #peekString(int)
|
||||||
|
* @see #peekAs(Class, int)
|
||||||
|
* @see #get()
|
||||||
|
*/
|
||||||
|
public CommandArgument peek(int index) throws CommandNotEnoughArgumentsException {
|
||||||
|
requireMin(index + 1);
|
||||||
|
return args.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The next argument in this {@link ArgConsumer}. This does not mutate the {@link ArgConsumer}
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there is less than one argument left
|
||||||
|
* @see #peek(int)
|
||||||
|
* @see #peekString()
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #get()
|
||||||
|
*/
|
||||||
|
public CommandArgument peek() throws CommandNotEnoughArgumentsException {
|
||||||
|
return peek(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index The index to peek
|
||||||
|
* @param type The type to check for
|
||||||
|
* @return If an ArgParser.Stateless for the specified {@code type} would succeed in parsing the next
|
||||||
|
* argument
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there is less than {@code index + 1} arguments left
|
||||||
|
* @see #peek()
|
||||||
|
* @see #getAs(Class)
|
||||||
|
*/
|
||||||
|
public boolean is(Class<?> type, int index) throws CommandNotEnoughArgumentsException {
|
||||||
|
return peek(index).is(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type The type to check for
|
||||||
|
* @return If an ArgParser.Stateless for the specified {@code type} would succeed in parsing the next
|
||||||
|
* argument
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there is less than one argument left
|
||||||
|
* @see #peek()
|
||||||
|
* @see #getAs(Class)
|
||||||
|
*/
|
||||||
|
public boolean is(Class<?> type) throws CommandNotEnoughArgumentsException {
|
||||||
|
return is(type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index The index to peek
|
||||||
|
* @return The value of the argument at index {@code index} in this {@link ArgConsumer}, with 0 being the next one
|
||||||
|
* This does not mutate the {@link ArgConsumer}
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there is less than {@code index + 1} arguments left
|
||||||
|
* @see #peek()
|
||||||
|
* @see #peekString()
|
||||||
|
*/
|
||||||
|
public String peekString(int index) throws CommandNotEnoughArgumentsException {
|
||||||
|
return peek(index).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The value of the next argument in this {@link ArgConsumer}. This does not mutate the {@link ArgConsumer}
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there is less than one argument left
|
||||||
|
* @see #peekString(int)
|
||||||
|
* @see #getString()
|
||||||
|
*/
|
||||||
|
public String peekString() throws CommandNotEnoughArgumentsException {
|
||||||
|
return peekString(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index The index to peek
|
||||||
|
* @param enumClass The class to search
|
||||||
|
* @return From the specified enum class, an enum constant of that class. The enum constant's name will match the
|
||||||
|
* next argument's value
|
||||||
|
* @throws java.util.NoSuchElementException If the constant couldn't be found
|
||||||
|
* @see #peekEnumOrNull(Class)
|
||||||
|
* @see #getEnum(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E peekEnum(Class<E> enumClass, int index) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return peek(index).getEnum(enumClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param enumClass The class to search
|
||||||
|
* @return From the specified enum class, an enum constant of that class. The enum constant's name will match the
|
||||||
|
* next argument's value
|
||||||
|
* @throws CommandInvalidTypeException If the constant couldn't be found
|
||||||
|
* @see #peekEnumOrNull(Class)
|
||||||
|
* @see #getEnum(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E peekEnum(Class<E> enumClass) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return peekEnum(enumClass, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index The index to peek
|
||||||
|
* @param enumClass The class to search
|
||||||
|
* @return From the specified enum class, an enum constant of that class. The enum constant's name will match the
|
||||||
|
* next argument's value. If no constant could be found, null
|
||||||
|
* @see #peekEnum(Class)
|
||||||
|
* @see #getEnumOrNull(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E peekEnumOrNull(Class<E> enumClass, int index) throws CommandNotEnoughArgumentsException {
|
||||||
|
try {
|
||||||
|
return peekEnum(enumClass, index);
|
||||||
|
} catch (CommandInvalidTypeException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param enumClass The class to search
|
||||||
|
* @return From the specified enum class, an enum constant of that class. The enum constant's name will match the
|
||||||
|
* next argument's value. If no constant could be found, null
|
||||||
|
* @see #peekEnum(Class)
|
||||||
|
* @see #getEnumOrNull(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E peekEnumOrNull(Class<E> enumClass) throws CommandNotEnoughArgumentsException {
|
||||||
|
return peekEnumOrNull(enumClass, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the argument at the specified index into the specified
|
||||||
|
* class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @param index The index to peek
|
||||||
|
* @return An instance of the specified type
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #peekAsOrDefault(Class, Object, int)
|
||||||
|
* @see #peekAsOrNull(Class, int)
|
||||||
|
*/
|
||||||
|
public <T> T peekAs(Class<T> type, int index) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return peek(index).getAs(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the next argument into the specified class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @return An instance of the specified type
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #peekAs(Class, int)
|
||||||
|
* @see #peekAsOrDefault(Class, Object)
|
||||||
|
* @see #peekAsOrNull(Class)
|
||||||
|
*/
|
||||||
|
public <T> T peekAs(Class<T> type) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return peekAs(type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the argument at the specified index into the specified
|
||||||
|
* class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @param def The value to return if the argument can't be parsed
|
||||||
|
* @param index The index to peek
|
||||||
|
* @return An instance of the specified type, or {@code def} if it couldn't be parsed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #peekAsOrDefault(Class, Object)
|
||||||
|
* @see #peekAs(Class, int)
|
||||||
|
* @see #peekAsOrNull(Class, int)
|
||||||
|
*/
|
||||||
|
public <T> T peekAsOrDefault(Class<T> type, T def, int index) throws CommandNotEnoughArgumentsException {
|
||||||
|
try {
|
||||||
|
return peekAs(type, index);
|
||||||
|
} catch (CommandInvalidTypeException e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the next argument into the specified class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @param def The value to return if the argument can't be parsed
|
||||||
|
* @return An instance of the specified type, or {@code def} if it couldn't be parsed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #peekAsOrDefault(Class, Object, int)
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #peekAsOrNull(Class)
|
||||||
|
*/
|
||||||
|
public <T> T peekAsOrDefault(Class<T> type, T def) throws CommandNotEnoughArgumentsException {
|
||||||
|
return peekAsOrDefault(type, def, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the argument at the specified index into the specified
|
||||||
|
* class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @param index The index to peek
|
||||||
|
* @return An instance of the specified type, or {@code null} if it couldn't be parsed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #peekAsOrNull(Class)
|
||||||
|
* @see #peekAs(Class, int)
|
||||||
|
* @see #peekAsOrDefault(Class, Object, int)
|
||||||
|
*/
|
||||||
|
public <T> T peekAsOrNull(Class<T> type, int index) throws CommandNotEnoughArgumentsException {
|
||||||
|
return peekAsOrDefault(type, null, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the next argument into the specified class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @return An instance of the specified type, or {@code null} if it couldn't be parsed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #peekAsOrNull(Class, int)
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #peekAsOrDefault(Class, Object)
|
||||||
|
*/
|
||||||
|
public <T> T peekAsOrNull(Class<T> type) throws CommandNotEnoughArgumentsException {
|
||||||
|
return peekAsOrNull(type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T peekDatatype(IDatatypeFor<T> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return copy().getDatatypeFor(datatype);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O> T peekDatatype(IDatatypePost<T, O> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return this.peekDatatype(datatype, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O> T peekDatatype(IDatatypePost<T, O> datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return copy().getDatatypePost(datatype, original);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T peekDatatypeOrNull(IDatatypeFor<T> datatype) {
|
||||||
|
return copy().getDatatypeForOrNull(datatype);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O> T peekDatatypeOrNull(IDatatypePost<T, O> datatype) {
|
||||||
|
return copy().getDatatypePostOrNull(datatype, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePost(D datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return copy().getDatatypePost(datatype, original);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePostOrDefault(D datatype, O original, T def) {
|
||||||
|
return copy().getDatatypePostOrDefault(datatype, original, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePostOrNull(D datatype, O original) {
|
||||||
|
return peekDatatypePostOrDefault(datatype, original, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to get the specified {@link IDatatypeFor} from this ArgConsumer
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
* <p>
|
||||||
|
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
|
||||||
|
*
|
||||||
|
* @param datatype The datatype to get
|
||||||
|
* @return The datatype instance
|
||||||
|
* @see IDatatype
|
||||||
|
* @see IDatatypeFor
|
||||||
|
*/
|
||||||
|
public <T, D extends IDatatypeFor<T>> T peekDatatypeFor(Class<D> datatype) {
|
||||||
|
return copy().peekDatatypeFor(datatype);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to get the specified {@link IDatatypeFor} from this ArgConsumer
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
* <p>
|
||||||
|
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
|
||||||
|
*
|
||||||
|
* @param datatype The datatype to get
|
||||||
|
* @param def The default value
|
||||||
|
* @return The datatype instance, or {@code def} if it throws an exception
|
||||||
|
* @see IDatatype
|
||||||
|
* @see IDatatypeFor
|
||||||
|
*/
|
||||||
|
public <T, D extends IDatatypeFor<T>> T peekDatatypeForOrDefault(Class<D> datatype, T def) {
|
||||||
|
return copy().peekDatatypeForOrDefault(datatype, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to get the specified {@link IDatatypeFor} from this ArgConsumer
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
* <p>
|
||||||
|
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
|
||||||
|
*
|
||||||
|
* @param datatype The datatype to get
|
||||||
|
* @return The datatype instance, or {@code null} if it throws an exception
|
||||||
|
* @see IDatatype
|
||||||
|
* @see IDatatypeFor
|
||||||
|
*/
|
||||||
|
public <T, D extends IDatatypeFor<T>> T peekDatatypeForOrNull(Class<D> datatype) {
|
||||||
|
return peekDatatypeForOrDefault(datatype, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next argument and returns it. This consumes the first argument so that subsequent calls will return
|
||||||
|
* later arguments
|
||||||
|
*
|
||||||
|
* @return The next argument
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there's less than one argument left
|
||||||
|
*/
|
||||||
|
public CommandArgument get() throws CommandNotEnoughArgumentsException {
|
||||||
|
requireMin(1);
|
||||||
|
CommandArgument arg = args.removeFirst();
|
||||||
|
consumed.add(arg);
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the next argument and returns it. This consumes the first argument so that subsequent calls
|
||||||
|
* will return later arguments
|
||||||
|
*
|
||||||
|
* @return The value of the next argument
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there's less than one argument left
|
||||||
|
*/
|
||||||
|
public String getString() throws CommandNotEnoughArgumentsException {
|
||||||
|
return get().value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an enum value from the enum class with the same name as the next argument's value
|
||||||
|
* <p>
|
||||||
|
* For example if you getEnum as an {@link EnumFacing}, and the next argument's value is "up", this will return
|
||||||
|
* {@link EnumFacing#UP}
|
||||||
|
*
|
||||||
|
* @param enumClass The enum class to search
|
||||||
|
* @return An enum constant of that class with the same name as the next argument's value
|
||||||
|
* @throws CommandInvalidTypeException If the constant couldn't be found
|
||||||
|
* @see #peekEnum(Class)
|
||||||
|
* @see #getEnumOrNull(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E getEnum(Class<E> enumClass) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return get().getEnum(enumClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an enum value from the enum class with the same name as the next argument's value
|
||||||
|
* <p>
|
||||||
|
* For example if you getEnum as an {@link EnumFacing}, and the next argument's value is "up", this will return
|
||||||
|
* {@link EnumFacing#UP}
|
||||||
|
*
|
||||||
|
* @param enumClass The enum class to search
|
||||||
|
* @param def The default value
|
||||||
|
* @return An enum constant of that class with the same name as the next argument's value, or {@code def} if it
|
||||||
|
* couldn't be found
|
||||||
|
* @see #getEnum(Class)
|
||||||
|
* @see #getEnumOrNull(Class)
|
||||||
|
* @see #peekEnumOrNull(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E getEnumOrDefault(Class<E> enumClass, E def) throws CommandNotEnoughArgumentsException {
|
||||||
|
try {
|
||||||
|
peekEnum(enumClass);
|
||||||
|
return getEnum(enumClass);
|
||||||
|
} catch (CommandInvalidTypeException e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an enum value from the enum class with the same name as the next argument's value
|
||||||
|
* <p>
|
||||||
|
* For example if you getEnum as an {@link EnumFacing}, and the next argument's value is "up", this will return
|
||||||
|
* {@link EnumFacing#UP}
|
||||||
|
*
|
||||||
|
* @param enumClass The enum class to search
|
||||||
|
* @return An enum constant of that class with the same name as the next argument's value, or {@code null} if it
|
||||||
|
* couldn't be found
|
||||||
|
* @see #getEnum(Class)
|
||||||
|
* @see #getEnumOrDefault(Class, Enum)
|
||||||
|
* @see #peekEnumOrNull(Class)
|
||||||
|
* @see CommandArgument#getEnum(Class)
|
||||||
|
*/
|
||||||
|
public <E extends Enum<?>> E getEnumOrNull(Class<E> enumClass) throws CommandNotEnoughArgumentsException {
|
||||||
|
return getEnumOrDefault(enumClass, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the next argument into the specified class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @return An instance of the specified type
|
||||||
|
* @throws CommandInvalidTypeException If the parsing failed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #get()
|
||||||
|
* @see #getAsOrDefault(Class, Object)
|
||||||
|
* @see #getAsOrNull(Class)
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #peekAsOrDefault(Class, Object, int)
|
||||||
|
* @see #peekAsOrNull(Class, int)
|
||||||
|
*/
|
||||||
|
public <T> T getAs(Class<T> type) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
return get().getAs(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the next argument into the specified class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @param def The default value
|
||||||
|
* @return An instance of the specified type, or {@code def} if it couldn't be parsed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #get()
|
||||||
|
* @see #getAs(Class)
|
||||||
|
* @see #getAsOrNull(Class)
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #peekAsOrDefault(Class, Object, int)
|
||||||
|
* @see #peekAsOrNull(Class, int)
|
||||||
|
*/
|
||||||
|
public <T> T getAsOrDefault(Class<T> type, T def) throws CommandNotEnoughArgumentsException {
|
||||||
|
try {
|
||||||
|
T val = peek().getAs(type);
|
||||||
|
get();
|
||||||
|
return val;
|
||||||
|
} catch (CommandInvalidTypeException e) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to use a <b>stateless</b> {@link IArgParser} to parse the next argument into the specified class
|
||||||
|
* <p>
|
||||||
|
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
|
||||||
|
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
|
||||||
|
* {@link ArgConsumer}.
|
||||||
|
*
|
||||||
|
* @param type The type to peek as
|
||||||
|
* @return An instance of the specified type, or {@code null} if it couldn't be parsed
|
||||||
|
* @see IArgParser
|
||||||
|
* @see #get()
|
||||||
|
* @see #getAs(Class)
|
||||||
|
* @see #getAsOrDefault(Class, Object)
|
||||||
|
* @see #peekAs(Class)
|
||||||
|
* @see #peekAsOrDefault(Class, Object, int)
|
||||||
|
* @see #peekAsOrNull(Class, int)
|
||||||
|
*/
|
||||||
|
public <T> T getAsOrNull(Class<T> type) throws CommandNotEnoughArgumentsException {
|
||||||
|
return getAsOrDefault(type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePost(D datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
try {
|
||||||
|
return datatype.apply(this.context, original);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePostOrDefault(D datatype, O original, T _default) {
|
||||||
|
final List<CommandArgument> argsSnapshot = new ArrayList<>(this.args);
|
||||||
|
final List<CommandArgument> consumedSnapshot = new ArrayList<>(this.consumed);
|
||||||
|
try {
|
||||||
|
return this.getDatatypePost(datatype, original);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.args.clear();
|
||||||
|
this.args.addAll(argsSnapshot);
|
||||||
|
this.consumed.clear();
|
||||||
|
this.consumed.addAll(consumedSnapshot);
|
||||||
|
return _default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePostOrNull(D datatype, O original) {
|
||||||
|
return this.getDatatypePostOrDefault(datatype, original, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, D extends IDatatypeFor<T>> T getDatatypeFor(D datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
|
||||||
|
try {
|
||||||
|
return datatype.get(this.context);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, D extends IDatatypeFor<T>> T getDatatypeForOrDefault(D datatype, T def) {
|
||||||
|
final List<CommandArgument> argsSnapshot = new ArrayList<>(this.args);
|
||||||
|
final List<CommandArgument> consumedSnapshot = new ArrayList<>(this.consumed);
|
||||||
|
try {
|
||||||
|
return this.getDatatypeFor(datatype);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.args.clear();
|
||||||
|
this.args.addAll(argsSnapshot);
|
||||||
|
this.consumed.clear();
|
||||||
|
this.consumed.addAll(consumedSnapshot);
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, D extends IDatatypeFor<T>> T getDatatypeForOrNull(D datatype) {
|
||||||
|
return this.getDatatypeForOrDefault(datatype, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends IDatatype> Stream<String> tabCompleteDatatype(T datatype) {
|
||||||
|
try {
|
||||||
|
return datatype.tabComplete(this.context);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the "raw rest" of the string. For example, from a string <code>arg1 arg2 arg3</code>, split
|
||||||
|
* into three {@link CommandArgument}s {@code "arg1"}, {@code "arg2"}, and {@code "arg3"}:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code rawRest()} would return <code>arg1 arg2 arg3</code></li>
|
||||||
|
* <li>After calling {@link #get()}, {@code rawRest()} would return <code>arg2 arg3</code> (note the
|
||||||
|
* double space - it is preserved!)</li>
|
||||||
|
* <li>After calling {@link #get()} again, {@code rawRest()} would return {@code "arg3"}</li>
|
||||||
|
* <li>After calling {@link #get()} one last time, {@code rawRest()} would return {@code ""}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @return The "raw rest" of the string.
|
||||||
|
*/
|
||||||
|
public String rawRest() {
|
||||||
|
return args.size() > 0 ? args.getFirst().rawRest : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param min The minimum amount of arguments to require.
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there are less than {@code min} arguments left.
|
||||||
|
* @see #requireMax(int)
|
||||||
|
* @see #requireExactly(int)
|
||||||
|
*/
|
||||||
|
public void requireMin(int min) throws CommandNotEnoughArgumentsException {
|
||||||
|
if (args.size() < min) {
|
||||||
|
throw new CommandNotEnoughArgumentsException(min + consumed.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param max The maximum amount of arguments allowed.
|
||||||
|
* @throws CommandTooManyArgumentsException If there are more than {@code max} arguments left.
|
||||||
|
* @see #requireMin(int)
|
||||||
|
* @see #requireExactly(int)
|
||||||
|
*/
|
||||||
|
public void requireMax(int max) throws CommandTooManyArgumentsException {
|
||||||
|
if (args.size() > max) {
|
||||||
|
throw new CommandTooManyArgumentsException(max + consumed.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param args The exact amount of arguments to require.
|
||||||
|
* @throws CommandNotEnoughArgumentsException If there are less than {@code args} arguments left.
|
||||||
|
* @throws CommandTooManyArgumentsException If there are more than {@code args} arguments left.
|
||||||
|
* @see #requireMin(int)
|
||||||
|
* @see #requireMax(int)
|
||||||
|
*/
|
||||||
|
public void requireExactly(int args) throws CommandException {
|
||||||
|
requireMin(args);
|
||||||
|
requireMax(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If this {@link ArgConsumer} has consumed at least one argument.
|
||||||
|
* @see #consumed()
|
||||||
|
* @see #consumedString()
|
||||||
|
*/
|
||||||
|
public boolean hasConsumed() {
|
||||||
|
return !consumed.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The last argument this {@link ArgConsumer} has consumed, or the {@link CommandArgument#unknown() unknown}
|
||||||
|
* argument if no arguments have been consumed yet.
|
||||||
|
* @see #consumedString()
|
||||||
|
* @see #hasConsumed()
|
||||||
|
*/
|
||||||
|
public CommandArgument consumed() {
|
||||||
|
return consumed.size() > 0 ? consumed.getLast() : CommandArgument.unknown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The value of thelast argument this {@link ArgConsumer} has consumed, or an empty string if no arguments
|
||||||
|
* have been consumed yet
|
||||||
|
* @see #consumed()
|
||||||
|
* @see #hasConsumed()
|
||||||
|
*/
|
||||||
|
public String consumedString() {
|
||||||
|
return consumed().value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A copy of this {@link ArgConsumer}. It has the same arguments (both consumed and not), but does not
|
||||||
|
* affect or mutate this instance. Useful for the various {@code peek} functions
|
||||||
|
*/
|
||||||
|
public ArgConsumer copy() {
|
||||||
|
return new ArgConsumer(manager, args, consumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class Context implements IDatatypeContext {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final IBaritone getBaritone() {
|
||||||
|
return ArgConsumer.this.manager.getBaritone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ArgConsumer getConsumer() {
|
||||||
|
return ArgConsumer.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.helpers.pagination;
|
||||||
|
|
||||||
|
import baritone.api.utils.Helper;
|
||||||
|
import baritone.api.utils.command.exception.CommandException;
|
||||||
|
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
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.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class Paginator<E> implements Helper {
|
||||||
|
|
||||||
|
public final List<E> entries;
|
||||||
|
public int pageSize = 8;
|
||||||
|
public int page = 1;
|
||||||
|
|
||||||
|
public Paginator(List<E> entries) {
|
||||||
|
this.entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Paginator(E... entries) {
|
||||||
|
this.entries = Arrays.asList(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Paginator<E> setPageSize(int pageSize) {
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxPage() {
|
||||||
|
return (entries.size() - 1) / pageSize + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validPage(int page) {
|
||||||
|
return page > 0 && page <= getMaxPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Paginator<E> skipPages(int pages) {
|
||||||
|
page += pages;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Function<E, ITextComponent> transform, String commandPrefix) {
|
||||||
|
int offset = (page - 1) * pageSize;
|
||||||
|
for (int i = offset; i < offset + pageSize; i++) {
|
||||||
|
if (i < entries.size()) {
|
||||||
|
logDirect(transform.apply(entries.get(i)));
|
||||||
|
} else {
|
||||||
|
logDirect("--", TextFormatting.DARK_GRAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean hasPrevPage = commandPrefix != null && validPage(page - 1);
|
||||||
|
boolean hasNextPage = commandPrefix != null && validPage(page + 1);
|
||||||
|
ITextComponent prevPageComponent = new TextComponentString("<<");
|
||||||
|
if (hasPrevPage) {
|
||||||
|
prevPageComponent.getStyle()
|
||||||
|
.setClickEvent(new ClickEvent(
|
||||||
|
ClickEvent.Action.RUN_COMMAND,
|
||||||
|
String.format("%s %d", commandPrefix, page - 1)
|
||||||
|
))
|
||||||
|
.setHoverEvent(new HoverEvent(
|
||||||
|
HoverEvent.Action.SHOW_TEXT,
|
||||||
|
new TextComponentString("Click to view previous page")
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
prevPageComponent.getStyle().setColor(TextFormatting.DARK_GRAY);
|
||||||
|
}
|
||||||
|
ITextComponent nextPageComponent = new TextComponentString(">>");
|
||||||
|
if (hasNextPage) {
|
||||||
|
nextPageComponent.getStyle()
|
||||||
|
.setClickEvent(new ClickEvent(
|
||||||
|
ClickEvent.Action.RUN_COMMAND,
|
||||||
|
String.format("%s %d", commandPrefix, page + 1)
|
||||||
|
))
|
||||||
|
.setHoverEvent(new HoverEvent(
|
||||||
|
HoverEvent.Action.SHOW_TEXT,
|
||||||
|
new TextComponentString("Click to view next page")
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
nextPageComponent.getStyle().setColor(TextFormatting.DARK_GRAY);
|
||||||
|
}
|
||||||
|
ITextComponent pagerComponent = new TextComponentString("");
|
||||||
|
pagerComponent.getStyle().setColor(TextFormatting.GRAY);
|
||||||
|
pagerComponent.appendSibling(prevPageComponent);
|
||||||
|
pagerComponent.appendText(" | ");
|
||||||
|
pagerComponent.appendSibling(nextPageComponent);
|
||||||
|
pagerComponent.appendText(String.format(" %d/%d", page, getMaxPage()));
|
||||||
|
logDirect(pagerComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display(Function<E, ITextComponent> transform) {
|
||||||
|
display(transform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Runnable pre, Function<T, ITextComponent> transform, String commandPrefix) throws CommandException {
|
||||||
|
int page = 1;
|
||||||
|
consumer.requireMax(1);
|
||||||
|
if (consumer.hasAny()) {
|
||||||
|
page = consumer.getAs(Integer.class);
|
||||||
|
if (!pagi.validPage(page)) {
|
||||||
|
throw new CommandInvalidTypeException(
|
||||||
|
consumer.consumed(),
|
||||||
|
String.format(
|
||||||
|
"a valid page (1-%d)",
|
||||||
|
pagi.getMaxPage()
|
||||||
|
),
|
||||||
|
consumer.consumed().value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pagi.skipPages(page - pagi.page);
|
||||||
|
if (pre != null) {
|
||||||
|
pre.run();
|
||||||
|
}
|
||||||
|
pagi.display(transform, commandPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Runnable pre, Function<T, ITextComponent> transform, String commandPrefix) throws CommandException {
|
||||||
|
paginate(consumer, new Paginator<>(elems), pre, transform, commandPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, T[] elems, Runnable pre, Function<T, ITextComponent> transform, String commandPrefix) throws CommandException {
|
||||||
|
paginate(consumer, Arrays.asList(elems), pre, transform, commandPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Function<T, ITextComponent> transform, String commandPrefix) throws CommandException {
|
||||||
|
paginate(consumer, pagi, null, transform, commandPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Function<T, ITextComponent> transform, String commandPrefix) throws CommandException {
|
||||||
|
paginate(consumer, new Paginator<>(elems), null, transform, commandPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, T[] elems, Function<T, ITextComponent> transform, String commandPrefix) throws CommandException {
|
||||||
|
paginate(consumer, Arrays.asList(elems), null, transform, commandPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Runnable pre, Function<T, ITextComponent> transform) throws CommandException {
|
||||||
|
paginate(consumer, pagi, pre, transform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Runnable pre, Function<T, ITextComponent> transform) throws CommandException {
|
||||||
|
paginate(consumer, new Paginator<>(elems), pre, transform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, T[] elems, Runnable pre, Function<T, ITextComponent> transform) throws CommandException {
|
||||||
|
paginate(consumer, Arrays.asList(elems), pre, transform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Function<T, ITextComponent> transform) throws CommandException {
|
||||||
|
paginate(consumer, pagi, null, transform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Function<T, ITextComponent> transform) throws CommandException {
|
||||||
|
paginate(consumer, new Paginator<>(elems), null, transform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void paginate(ArgConsumer consumer, T[] elems, Function<T, ITextComponent> transform) throws CommandException {
|
||||||
|
paginate(consumer, Arrays.asList(elems), null, transform, null);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.helpers.tabcomplete;
|
||||||
|
|
||||||
|
import baritone.api.BaritoneAPI;
|
||||||
|
import baritone.api.Settings;
|
||||||
|
import baritone.api.event.events.TabCompleteEvent;
|
||||||
|
import baritone.api.utils.SettingsUtil;
|
||||||
|
import baritone.api.utils.command.datatypes.IDatatype;
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import baritone.api.utils.command.manager.ICommandManager;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link TabCompleteHelper} is a <b>single-use</b> object that helps you handle tab completion. It includes helper
|
||||||
|
* methods for appending and prepending streams, sorting, filtering by prefix, and so on.
|
||||||
|
* <p>
|
||||||
|
* The recommended way to use this class is:
|
||||||
|
* <ul>
|
||||||
|
* <li>Create a new instance with the empty constructor</li>
|
||||||
|
* <li>Use {@code append}, {@code prepend} or {@code add<something>} methods to add completions</li>
|
||||||
|
* <li>Sort using {@link #sort(Comparator)} or {@link #sortAlphabetically()} and then filter by prefix using
|
||||||
|
* {@link #filterPrefix(String)}</li>
|
||||||
|
* <li>Get the stream using {@link #stream()}</li>
|
||||||
|
* <li>Pass it up to whatever's calling your tab complete function (i.e.
|
||||||
|
* {@link ICommandManager#tabComplete(String)} or {@link ArgConsumer#tabCompleteDatatype(IDatatype)})</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* For advanced users: if you're intercepting {@link TabCompleteEvent}s directly, use {@link #build()} instead for an
|
||||||
|
* array.
|
||||||
|
*/
|
||||||
|
public class TabCompleteHelper {
|
||||||
|
|
||||||
|
private Stream<String> stream;
|
||||||
|
|
||||||
|
public TabCompleteHelper(String[] base) {
|
||||||
|
stream = Stream.of(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabCompleteHelper(List<String> base) {
|
||||||
|
stream = base.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabCompleteHelper() {
|
||||||
|
stream = Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the specified stream to this {@link TabCompleteHelper} and returns it for chaining
|
||||||
|
*
|
||||||
|
* @param source The stream to append
|
||||||
|
* @return This {@link TabCompleteHelper} after having appended the stream
|
||||||
|
* @see #append(String...)
|
||||||
|
* @see #append(Class)
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper append(Stream<String> source) {
|
||||||
|
stream = Stream.concat(stream, source);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the specified strings to this {@link TabCompleteHelper} and returns it for chaining
|
||||||
|
*
|
||||||
|
* @param source The stream to append
|
||||||
|
* @return This {@link TabCompleteHelper} after having appended the strings
|
||||||
|
* @see #append(Stream)
|
||||||
|
* @see #append(Class)
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper append(String... source) {
|
||||||
|
return append(Stream.of(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends all values of the specified enum to this {@link TabCompleteHelper} and returns it for chaining
|
||||||
|
*
|
||||||
|
* @param num The enum to append the values of
|
||||||
|
* @return This {@link TabCompleteHelper} after having appended the values
|
||||||
|
* @see #append(Stream)
|
||||||
|
* @see #append(String...)
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper append(Class<? extends Enum<?>> num) {
|
||||||
|
return append(
|
||||||
|
Stream.of(num.getEnumConstants())
|
||||||
|
.map(Enum::name)
|
||||||
|
.map(String::toLowerCase)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepends the specified stream to this {@link TabCompleteHelper} and returns it for chaining
|
||||||
|
*
|
||||||
|
* @param source The stream to prepend
|
||||||
|
* @return This {@link TabCompleteHelper} after having prepended the stream
|
||||||
|
* @see #prepend(String...)
|
||||||
|
* @see #prepend(Class)
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper prepend(Stream<String> source) {
|
||||||
|
stream = Stream.concat(source, stream);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepends the specified strings to this {@link TabCompleteHelper} and returns it for chaining
|
||||||
|
*
|
||||||
|
* @param source The stream to prepend
|
||||||
|
* @return This {@link TabCompleteHelper} after having prepended the strings
|
||||||
|
* @see #prepend(Stream)
|
||||||
|
* @see #prepend(Class)
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper prepend(String... source) {
|
||||||
|
return prepend(Stream.of(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepends all values of the specified enum to this {@link TabCompleteHelper} and returns it for chaining
|
||||||
|
*
|
||||||
|
* @param num The enum to prepend the values of
|
||||||
|
* @return This {@link TabCompleteHelper} after having prepended the values
|
||||||
|
* @see #prepend(Stream)
|
||||||
|
* @see #prepend(String...)
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper prepend(Class<? extends Enum<?>> num) {
|
||||||
|
return prepend(
|
||||||
|
Stream.of(num.getEnumConstants())
|
||||||
|
.map(Enum::name)
|
||||||
|
.map(String::toLowerCase)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the specified {@code transform} to every element <b>currently</b> in this {@link TabCompleteHelper} and
|
||||||
|
* return this object for chaining
|
||||||
|
*
|
||||||
|
* @param transform The transform to apply
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper map(Function<String, String> transform) {
|
||||||
|
stream = stream.map(transform);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the specified {@code filter} to every element <b>currently</b> in this {@link TabCompleteHelper} and return
|
||||||
|
* this object for chaining
|
||||||
|
*
|
||||||
|
* @param filter The filter to apply
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper filter(Predicate<String> filter) {
|
||||||
|
stream = stream.filter(filter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the specified {@code sort} to every element <b>currently</b> in this {@link TabCompleteHelper} and return
|
||||||
|
* this object for chaining
|
||||||
|
*
|
||||||
|
* @param comparator The comparator to use
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper sort(Comparator<String> comparator) {
|
||||||
|
stream = stream.sorted(comparator);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort every element <b>currently</b> in this {@link TabCompleteHelper} alphabetically and return this object for
|
||||||
|
* chaining
|
||||||
|
*
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper sortAlphabetically() {
|
||||||
|
return sort(String.CASE_INSENSITIVE_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter out any element that doesn't start with {@code prefix} and return this object for chaining
|
||||||
|
*
|
||||||
|
* @param prefix The prefix to filter for
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper filterPrefix(String prefix) {
|
||||||
|
return filter(x -> x.toLowerCase(Locale.US).startsWith(prefix.toLowerCase(Locale.US)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter out any element that doesn't start with {@code prefix} and return this object for chaining
|
||||||
|
* <p>
|
||||||
|
* Assumes every element in this {@link TabCompleteHelper} is a {@link ResourceLocation}
|
||||||
|
*
|
||||||
|
* @param prefix The prefix to filter for
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper filterPrefixNamespaced(String prefix) {
|
||||||
|
return filterPrefix(new ResourceLocation(prefix).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return An array containing every element in this {@link TabCompleteHelper}
|
||||||
|
* @see #stream()
|
||||||
|
*/
|
||||||
|
public String[] build() {
|
||||||
|
return stream.toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A stream containing every element in this {@link TabCompleteHelper}
|
||||||
|
* @see #build()
|
||||||
|
*/
|
||||||
|
public Stream<String> stream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends every command in the specified {@link ICommandManager} to this {@link TabCompleteHelper}
|
||||||
|
*
|
||||||
|
* @param manager A command manager
|
||||||
|
*
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper addCommands(ICommandManager manager) {
|
||||||
|
return append(manager.getRegistry().descendingStream()
|
||||||
|
.flatMap(command -> command.names.stream())
|
||||||
|
.distinct()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends every setting in the {@link Settings} to this {@link TabCompleteHelper}
|
||||||
|
*
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper addSettings() {
|
||||||
|
return append(
|
||||||
|
BaritoneAPI.getSettings().allSettings.stream()
|
||||||
|
.map(Settings.Setting::getName)
|
||||||
|
.filter(s -> !s.equalsIgnoreCase("logger"))
|
||||||
|
.sorted(String.CASE_INSENSITIVE_ORDER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends every modified setting in the {@link Settings} to this {@link TabCompleteHelper}
|
||||||
|
*
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper addModifiedSettings() {
|
||||||
|
return append(
|
||||||
|
SettingsUtil.modifiedSettings(BaritoneAPI.getSettings()).stream()
|
||||||
|
.map(Settings.Setting::getName)
|
||||||
|
.sorted(String.CASE_INSENSITIVE_ORDER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends every {@link Boolean} setting in the {@link Settings} to this {@link TabCompleteHelper}
|
||||||
|
*
|
||||||
|
* @return This {@link TabCompleteHelper}
|
||||||
|
*/
|
||||||
|
public TabCompleteHelper addToggleableSettings() {
|
||||||
|
return append(
|
||||||
|
BaritoneAPI.getSettings().getAllValuesByType(Boolean.class).stream()
|
||||||
|
.map(Settings.Setting::getName)
|
||||||
|
.sorted(String.CASE_INSENSITIVE_ORDER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.manager;
|
||||||
|
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.utils.command.Command;
|
||||||
|
import baritone.api.utils.command.argument.CommandArgument;
|
||||||
|
import baritone.api.utils.command.registry.Registry;
|
||||||
|
import net.minecraft.util.Tuple;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Brady
|
||||||
|
* @since 9/21/2019
|
||||||
|
*/
|
||||||
|
public interface ICommandManager {
|
||||||
|
|
||||||
|
IBaritone getBaritone();
|
||||||
|
|
||||||
|
Registry<Command> getRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name The command name to search for.
|
||||||
|
* @return The command, if found.
|
||||||
|
*/
|
||||||
|
Command getCommand(String name);
|
||||||
|
|
||||||
|
boolean execute(String string);
|
||||||
|
|
||||||
|
boolean execute(Tuple<String, List<CommandArgument>> expanded);
|
||||||
|
|
||||||
|
Stream<String> tabComplete(Tuple<String, List<CommandArgument>> expanded);
|
||||||
|
|
||||||
|
Stream<String> tabComplete(String prefix);
|
||||||
|
}
|
135
src/api/java/baritone/api/utils/command/registry/Registry.java
Normal file
135
src/api/java/baritone/api/utils/command/registry/Registry.java
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.utils.command.registry;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This registry class allows for registration and unregistration of a certain type. This is mainly designed for use by
|
||||||
|
* event handlers where newly registered ones are encountered first during iteration and can therefore override older
|
||||||
|
* ones. In Baritone, this is used for commands and argument parsers so that mods and addons can extend Baritone's
|
||||||
|
* functionality without resorting to hacks, wrappers, or mixins.
|
||||||
|
*
|
||||||
|
* @param <V> The entry type that will be stored in this registry. This can be anything, really - preferably anything
|
||||||
|
* that works as a HashMap key, as that's what's used to keep track of which entries are registered or not.
|
||||||
|
*/
|
||||||
|
public class Registry<V> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An internal linked list of all the entries that are currently registered. This is a linked list so that entries
|
||||||
|
* can be inserted at the beginning, which means that newer entries are encountered first during iteration. This is
|
||||||
|
* an important property of the registry that makes it more useful than a simple list, and also the reason it does
|
||||||
|
* not just use a map.
|
||||||
|
*/
|
||||||
|
private final Deque<V> _entries = new LinkedList<>();
|
||||||
|
/**
|
||||||
|
* A HashSet containing every entry currently registered. Entries are added to this set when something is registered
|
||||||
|
* and removed from the set when they are unregistered. An entry being present in this set indicates that it is
|
||||||
|
* currently registered, can be removed, and should not be reregistered until it is removed.
|
||||||
|
*/
|
||||||
|
private final Set<V> registered = new HashSet<>();
|
||||||
|
/**
|
||||||
|
* The collection of entries that are currently in this registry. This is a collection (and not a list) because,
|
||||||
|
* internally, entries are stored in a linked list, which is not the same as a normal list.
|
||||||
|
*/
|
||||||
|
public final Collection<V> entries = Collections.unmodifiableCollection(_entries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param entry The entry to check.
|
||||||
|
* @return If this entry is currently registered in this registry.
|
||||||
|
*/
|
||||||
|
public boolean registered(V entry) {
|
||||||
|
return registered.contains(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the entry {@code entry} is registered.
|
||||||
|
*
|
||||||
|
* @param entry The entry to register.
|
||||||
|
* @return A boolean indicating whether or not this is a new registration. No matter the value of this boolean, the
|
||||||
|
* entry is always guaranteed to now be in this registry. This boolean simply indicates if the entry was <i>not</i>
|
||||||
|
* in the map prior to this method call.
|
||||||
|
*/
|
||||||
|
public boolean register(V entry) {
|
||||||
|
if (!registered(entry)) {
|
||||||
|
_entries.addFirst(entry);
|
||||||
|
registered.add(entry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this entry from this registry. After this method call, the entry is guaranteed to be removed from the
|
||||||
|
* registry, since each entry only ever appears once.
|
||||||
|
*
|
||||||
|
* @param entry The entry to unregister.
|
||||||
|
*/
|
||||||
|
public void unregister(V entry) {
|
||||||
|
if (registered(entry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_entries.remove(entry);
|
||||||
|
registered.remove(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator that iterates over each entry in this registry, with the newest elements iterated over first.
|
||||||
|
* Internally, as new elements are prepended to the registry rather than appended to the end, this order is the best
|
||||||
|
* way to search through the registry if you want to discover newer items first.
|
||||||
|
*/
|
||||||
|
public Iterator<V> iterator() {
|
||||||
|
return _entries.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator that iterates over each entry in this registry, in the order they were added. Internally,
|
||||||
|
* this iterates through the registry backwards, as new elements are prepended to the registry rather than appended
|
||||||
|
* to the end. You should only do this when you need to, for example, list elements in order - it is almost always
|
||||||
|
* fine to simply use {@link Iterable#forEach(Consumer) forEach} on the {@link #entries} collection instead.
|
||||||
|
*/
|
||||||
|
public Iterator<V> descendingIterator() {
|
||||||
|
return _entries.descendingIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a stream that contains each entry in this registry, with the newest elements ordered first. Internally,
|
||||||
|
* as new elements are prepended to the registry rather than appended to the end, this order is the best way to
|
||||||
|
* search through the registry if you want to discover newer items first.
|
||||||
|
*/
|
||||||
|
public Stream<V> stream() {
|
||||||
|
return _entries.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a stream that returns each entry in this registry, in the order they were added. Internally, this orders
|
||||||
|
* the registry backwards, as new elements are prepended to the registry rather than appended to the end. You should
|
||||||
|
* only use this when you need to, for example, list elements in order - it is almost always fine to simply use the
|
||||||
|
* regular {@link #stream()} method instead.
|
||||||
|
*/
|
||||||
|
public Stream<V> descendingStream() {
|
||||||
|
return StreamSupport.stream(Spliterators.spliterator(
|
||||||
|
descendingIterator(),
|
||||||
|
_entries.size(),
|
||||||
|
Spliterator.SIZED | Spliterator.SUBSIZED
|
||||||
|
), false);
|
||||||
|
}
|
||||||
|
}
|
@ -20,5 +20,6 @@ package baritone.api.utils.interfaces;
|
|||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
public interface IGoalRenderPos {
|
public interface IGoalRenderPos {
|
||||||
|
|
||||||
BlockPos getGoalPos();
|
BlockPos getGoalPos();
|
||||||
}
|
}
|
||||||
|
91
src/launch/java/baritone/launch/mixins/MixinBitArray.java
Normal file
91
src/launch/java/baritone/launch/mixins/MixinBitArray.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import baritone.utils.accessor.IBitArray;
|
||||||
|
import net.minecraft.util.BitArray;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(BitArray.class)
|
||||||
|
public abstract class MixinBitArray implements IBitArray {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private long[] longArray;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private int bitsPerEntry;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private long maxEntryValue;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private int arraySize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* why did mojang divide by 64 instead of shifting right by 6 (2^6=64)?
|
||||||
|
* why did mojang modulo by 64 instead of ANDing with 63?
|
||||||
|
* also removed validation check
|
||||||
|
*
|
||||||
|
* @author LoganDark
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Unique
|
||||||
|
public int getAtFast(int index) {
|
||||||
|
final int b = bitsPerEntry;
|
||||||
|
final long mev = maxEntryValue;
|
||||||
|
final int i = index * b;
|
||||||
|
final int j = i >> 6;
|
||||||
|
final int l = i & 63;
|
||||||
|
final int k = ((index + 1) * b - 1) >> 6;
|
||||||
|
|
||||||
|
if (j == k) {
|
||||||
|
return (int) (this.longArray[j] >>> l & mev);
|
||||||
|
} else {
|
||||||
|
return (int) ((this.longArray[j] >>> l | longArray[k] << (64 - l)) & mev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Unique
|
||||||
|
public int[] toArray() {
|
||||||
|
int[] out = new int[arraySize];
|
||||||
|
|
||||||
|
for (int idx = 0, kl = bitsPerEntry - 1; idx < arraySize; idx++, kl += bitsPerEntry) {
|
||||||
|
final int i = idx * bitsPerEntry;
|
||||||
|
final int j = i >> 6;
|
||||||
|
final int l = i & 63;
|
||||||
|
final int k = kl >> 6;
|
||||||
|
final long jl = longArray[j] >>> l;
|
||||||
|
|
||||||
|
if (j == k) {
|
||||||
|
out[idx] = (int) (jl & maxEntryValue);
|
||||||
|
} else {
|
||||||
|
out[idx] = (int) ((jl | longArray[k] << (64 - l)) & maxEntryValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import baritone.utils.accessor.IBitArray;
|
||||||
|
import baritone.utils.accessor.IBlockStateContainer;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.util.BitArray;
|
||||||
|
import net.minecraft.world.chunk.BlockStateContainer;
|
||||||
|
import net.minecraft.world.chunk.IBlockStatePalette;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(BlockStateContainer.class)
|
||||||
|
public abstract class MixinBlockStateContainer implements IBlockStateContainer {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected BitArray storage;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected IBlockStatePalette palette;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Accessor
|
||||||
|
public abstract BitArray getStorage();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Accessor
|
||||||
|
public abstract IBlockStatePalette getPalette();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Unique
|
||||||
|
public IBlockState getFast(int index) {
|
||||||
|
return palette.getBlockState(((IBitArray) storage).getAtFast(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockState getAtPalette(int index) {
|
||||||
|
return palette.getBlockState(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] storageArray() {
|
||||||
|
return ((IBitArray) storage).toArray();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.GuiChat;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(GuiChat.ChatTabCompleter.class)
|
||||||
|
public abstract class MixinChatTabCompleter extends MixinTabCompleter {
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "<init>*",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void onConstruction(CallbackInfo ci) {
|
||||||
|
isChatCompleter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "complete",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void onComplete(CallbackInfo ci) {
|
||||||
|
if (dontComplete) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
src/launch/java/baritone/launch/mixins/MixinGuiChat.java
Normal file
45
src/launch/java/baritone/launch/mixins/MixinGuiChat.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import baritone.utils.accessor.ITabCompleter;
|
||||||
|
import net.minecraft.client.gui.GuiChat;
|
||||||
|
import net.minecraft.util.TabCompleter;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(GuiChat.class)
|
||||||
|
public abstract class MixinGuiChat implements net.minecraft.util.ITabCompleter {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private TabCompleter tabCompleter;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "setCompletions",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void onSetCompletions(String[] newCompl, CallbackInfo ci) {
|
||||||
|
if (((ITabCompleter) tabCompleter).onGuiChatSetCompletions(newCompl)) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/launch/java/baritone/launch/mixins/MixinGuiScreen.java
Normal file
33
src/launch/java/baritone/launch/mixins/MixinGuiScreen.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import baritone.api.accessor.IGuiScreen;
|
||||||
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
@Mixin(GuiScreen.class)
|
||||||
|
public abstract class MixinGuiScreen implements IGuiScreen {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Invoker("openWebLink")
|
||||||
|
public abstract void openLink(URI url);
|
||||||
|
}
|
68
src/launch/java/baritone/launch/mixins/MixinItemStack.java
Normal file
68
src/launch/java/baritone/launch/mixins/MixinItemStack.java
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import baritone.api.accessor.IItemStack;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(ItemStack.class)
|
||||||
|
public abstract class MixinItemStack implements IItemStack {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private Item item;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private int itemDamage;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int baritoneHash;
|
||||||
|
|
||||||
|
private void recalculateHash() {
|
||||||
|
baritoneHash = item == null ? -1 : item.hashCode() + itemDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "<init>*",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void onInit(CallbackInfo ci) {
|
||||||
|
recalculateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "setItemDamage",
|
||||||
|
at = @At("TAIL")
|
||||||
|
)
|
||||||
|
private void onItemDamageSet(CallbackInfo ci) {
|
||||||
|
recalculateHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaritoneHash() {
|
||||||
|
return baritoneHash;
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package baritone.launch.mixins;
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
import baritone.Baritone;
|
|
||||||
import baritone.api.BaritoneAPI;
|
import baritone.api.BaritoneAPI;
|
||||||
import baritone.api.IBaritone;
|
import baritone.api.IBaritone;
|
||||||
import baritone.api.event.events.BlockInteractEvent;
|
import baritone.api.event.events.BlockInteractEvent;
|
||||||
@ -59,7 +58,7 @@ public class MixinMinecraft {
|
|||||||
at = @At("RETURN")
|
at = @At("RETURN")
|
||||||
)
|
)
|
||||||
private void postInit(CallbackInfo ci) {
|
private void postInit(CallbackInfo ci) {
|
||||||
((Baritone) BaritoneAPI.getProvider().getPrimaryBaritone()).init();
|
BaritoneAPI.getProvider().getPrimaryBaritone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(
|
@Inject(
|
||||||
|
@ -26,6 +26,7 @@ import org.spongepowered.asm.mixin.gen.Invoker;
|
|||||||
|
|
||||||
@Mixin(PlayerControllerMP.class)
|
@Mixin(PlayerControllerMP.class)
|
||||||
public abstract class MixinPlayerControllerMP implements IPlayerControllerMP {
|
public abstract class MixinPlayerControllerMP implements IPlayerControllerMP {
|
||||||
|
|
||||||
@Accessor
|
@Accessor
|
||||||
@Override
|
@Override
|
||||||
public abstract void setIsHittingBlock(boolean isHittingBlock);
|
public abstract void setIsHittingBlock(boolean isHittingBlock);
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import net.minecraft.block.properties.IProperty;
|
||||||
|
import org.spongepowered.asm.mixin.*;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(targets = "net.minecraft.block.state.BlockStateContainer$StateImplementation")
|
||||||
|
public abstract class MixinStateImplementation {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private ImmutableMap<IProperty<?>, Comparable<?>> properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block states are fucking immutable
|
||||||
|
*/
|
||||||
|
@Unique
|
||||||
|
private int hashCode;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "<init>*",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void onInit(CallbackInfo ci) {
|
||||||
|
hashCode = properties.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache this instead of using the fucking map every time
|
||||||
|
*
|
||||||
|
* @author LoganDark
|
||||||
|
* @reason Regular IBlockState generates a new hash every fucking time. This is not needed when scanning millions
|
||||||
|
* per second
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Overwrite
|
||||||
|
public int hashCode() {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
130
src/launch/java/baritone/launch/mixins/MixinTabCompleter.java
Normal file
130
src/launch/java/baritone/launch/mixins/MixinTabCompleter.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.launch.mixins;
|
||||||
|
|
||||||
|
import baritone.api.BaritoneAPI;
|
||||||
|
import baritone.api.IBaritone;
|
||||||
|
import baritone.api.event.events.TabCompleteEvent;
|
||||||
|
import baritone.utils.accessor.ITabCompleter;
|
||||||
|
import net.minecraft.client.gui.GuiTextField;
|
||||||
|
import net.minecraft.util.TabCompleter;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(TabCompleter.class)
|
||||||
|
public abstract class MixinTabCompleter implements ITabCompleter {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected GuiTextField textField;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected boolean requestedCompletions;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract void setCompletions(String... newCompl);
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
protected boolean isChatCompleter = false;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
protected boolean dontComplete = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPrefix() {
|
||||||
|
return textField.getText().substring(0, textField.getCursorPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPrefix(String prefix) {
|
||||||
|
textField.setText(prefix + textField.getText().substring(textField.getCursorPosition()));
|
||||||
|
textField.setCursorPosition(prefix.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "requestCompletions",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void onRequestCompletions(String prefix, CallbackInfo ci) {
|
||||||
|
if (!isChatCompleter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
|
||||||
|
|
||||||
|
TabCompleteEvent.Pre event = new TabCompleteEvent.Pre(prefix);
|
||||||
|
baritone.getGameEventHandler().onPreTabComplete(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.prefix.wasModified()) {
|
||||||
|
setPrefix(event.prefix.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.completions.wasModified()) {
|
||||||
|
ci.cancel();
|
||||||
|
|
||||||
|
dontComplete = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
requestedCompletions = true;
|
||||||
|
setCompletions(event.completions.get());
|
||||||
|
} finally {
|
||||||
|
dontComplete = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onGuiChatSetCompletions(String[] newCompl) {
|
||||||
|
IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
|
||||||
|
|
||||||
|
if (baritone == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TabCompleteEvent.Post event = new TabCompleteEvent.Post(getPrefix(), newCompl);
|
||||||
|
baritone.getGameEventHandler().onPostTabComplete(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.prefix.wasModified()) {
|
||||||
|
String prefix = event.prefix.get();
|
||||||
|
textField.setText(prefix + textField.getText().substring(textField.getCursorPosition()));
|
||||||
|
textField.setCursorPosition(prefix.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.completions.wasModified()) {
|
||||||
|
setCompletions(event.completions.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,9 @@
|
|||||||
},
|
},
|
||||||
"client": [
|
"client": [
|
||||||
"MixinAnvilChunkLoader",
|
"MixinAnvilChunkLoader",
|
||||||
|
"MixinBitArray",
|
||||||
|
"MixinBlockStateContainer",
|
||||||
|
"MixinChatTabCompleter",
|
||||||
"MixinChunkProviderClient",
|
"MixinChunkProviderClient",
|
||||||
"MixinChunkProviderServer",
|
"MixinChunkProviderServer",
|
||||||
"MixinChunkRenderContainer",
|
"MixinChunkRenderContainer",
|
||||||
@ -16,12 +19,17 @@
|
|||||||
"MixinEntityLivingBase",
|
"MixinEntityLivingBase",
|
||||||
"MixinEntityPlayerSP",
|
"MixinEntityPlayerSP",
|
||||||
"MixinEntityRenderer",
|
"MixinEntityRenderer",
|
||||||
|
"MixinGuiChat",
|
||||||
|
"MixinGuiScreen",
|
||||||
|
"MixinItemStack",
|
||||||
"MixinMinecraft",
|
"MixinMinecraft",
|
||||||
"MixinNetHandlerPlayClient",
|
"MixinNetHandlerPlayClient",
|
||||||
"MixinNetworkManager",
|
"MixinNetworkManager",
|
||||||
"MixinPlayerControllerMP",
|
"MixinPlayerControllerMP",
|
||||||
"MixinRenderChunk",
|
"MixinRenderChunk",
|
||||||
"MixinRenderList",
|
"MixinRenderList",
|
||||||
|
"MixinStateImplementation",
|
||||||
|
"MixinTabCompleter",
|
||||||
"MixinVboRenderList",
|
"MixinVboRenderList",
|
||||||
"MixinWorldClient"
|
"MixinWorldClient"
|
||||||
]
|
]
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user