2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,6 +14,8 @@ classes/
|
||||
# IntelliJ Files
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
/logs/
|
||||
|
||||
# Copyright Files
|
||||
|
5
scripts/proguard.pro
vendored
5
scripts/proguard.pro
vendored
@@ -17,6 +17,11 @@
|
||||
|
||||
-keep class baritone.api.** { *; } # this is the keep api
|
||||
|
||||
# Proguard does not know the commands framework better than I do
|
||||
# It needs its empty constructors and simple names to work correctly
|
||||
-keep class baritone.api.utils.command.** { *; }
|
||||
-keepclasseswithmembernames class baritone.api.utils.command.** { *; }
|
||||
|
||||
# service provider needs these class names
|
||||
-keep class baritone.BaritoneProvider
|
||||
-keep class baritone.api.IBaritoneProvider
|
||||
|
@@ -23,6 +23,7 @@ import baritone.api.cache.IWorldProvider;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.pathing.calc.IPathingControlManager;
|
||||
import baritone.api.process.*;
|
||||
import baritone.api.selection.ISelectionManager;
|
||||
import baritone.api.utils.IInputOverrideHandler;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
|
||||
@@ -128,6 +129,12 @@ public interface IBaritone {
|
||||
*/
|
||||
IEventBus getGameEventHandler();
|
||||
|
||||
/**
|
||||
* @return The {@link ISelectionManager} instance
|
||||
* @see ISelectionManager
|
||||
*/
|
||||
ISelectionManager getSelectionManager();
|
||||
|
||||
/**
|
||||
* Open click
|
||||
*/
|
||||
|
@@ -495,15 +495,20 @@ public final class Settings {
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@@ -604,21 +609,41 @@ public final class Settings {
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@@ -938,6 +963,51 @@ public final class Settings {
|
||||
*/
|
||||
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<>(1F);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
24
src/api/java/baritone/api/accessor/IGuiScreen.java
Normal file
24
src/api/java/baritone/api/accessor/IGuiScreen.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
22
src/api/java/baritone/api/accessor/IItemStack.java
Normal file
22
src/api/java/baritone/api/accessor/IItemStack.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
51
src/api/java/baritone/api/cache/IWaypoint.java
vendored
51
src/api/java/baritone/api/cache/IWaypoint.java
vendored
@@ -17,12 +17,15 @@
|
||||
|
||||
package baritone.api.cache;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* A marker for a position in the world.
|
||||
@@ -60,7 +63,7 @@ public interface IWaypoint {
|
||||
*
|
||||
* @return The block position of this waypoint
|
||||
*/
|
||||
BlockPos getLocation();
|
||||
BetterBlockPos getLocation();
|
||||
|
||||
enum Tag {
|
||||
|
||||
@@ -92,20 +95,48 @@ public interface IWaypoint {
|
||||
/**
|
||||
* 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) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a tag from one of the names that could be used to identify said tag.
|
||||
*
|
||||
* @param name The name of the tag
|
||||
* @return The tag, if one is found, otherwise, {@code null}
|
||||
* @return A name that can be passed to {@link #getByName(String)} to retrieve this tag
|
||||
*/
|
||||
public static Tag fromString(String name) {
|
||||
return TAG_LIST.stream().filter(tag -> ArrayUtils.contains(tag.names, name.toLowerCase())).findFirst().orElse(null);
|
||||
public String getName() {
|
||||
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(asList(tag.names));
|
||||
}
|
||||
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.cache;
|
||||
|
||||
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import net.minecraft.block.Block;
|
||||
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.
|
||||
*
|
||||
* @param ctx The {@link IPlayerContext} containing player and world info that the
|
||||
* scan is based upon
|
||||
* @param blocks The blocks to scan for
|
||||
* @param ctx The {@link IPlayerContext} containing player and world info that the scan is based upon
|
||||
* @param filter The blocks to scan for
|
||||
* @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.
|
||||
* @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.
|
||||
* @param maxSearchRadius The maximum chunk search radius
|
||||
* @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.
|
||||
*
|
||||
* @param ctx The {@link IPlayerContext} containing player and world info that the
|
||||
* scan is based upon
|
||||
* @param ctx The {@link IPlayerContext} containing player and world info that the 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 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.
|
||||
* @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, 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);
|
||||
}
|
||||
|
10
src/api/java/baritone/api/cache/Waypoint.java
vendored
10
src/api/java/baritone/api/cache/Waypoint.java
vendored
@@ -32,9 +32,9 @@ public class Waypoint implements IWaypoint {
|
||||
private final String name;
|
||||
private final Tag tag;
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class Waypoint implements IWaypoint {
|
||||
* @param location The waypoint location
|
||||
* @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.tag = tag;
|
||||
this.location = location;
|
||||
@@ -56,7 +56,7 @@ public class Waypoint implements IWaypoint {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() + tag.hashCode() + location.hashCode(); //lol
|
||||
return name.hashCode() ^ tag.hashCode() ^ location.hashCode() ^ Long.hashCode(creationTimestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,7 +75,7 @@ public class Waypoint implements IWaypoint {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getLocation() {
|
||||
public BetterBlockPos getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
|
50
src/api/java/baritone/api/event/events/TabCompleteEvent.java
Normal file
50
src/api/java/baritone/api/event/events/TabCompleteEvent.java
Normal file
@@ -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.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,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.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
|
||||
default void onSendChatMessage(ChatEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onPreTabComplete(TabCompleteEvent.Pre event) {};
|
||||
|
||||
@Override
|
||||
default void onPostTabComplete(TabCompleteEvent.Post event) {};
|
||||
|
||||
@Override
|
||||
default void onChunkEvent(ChunkEvent event) {}
|
||||
|
||||
|
@@ -57,6 +57,21 @@ public interface IGameEventListener {
|
||||
*/
|
||||
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.Pre#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.
|
||||
*
|
||||
|
51
src/api/java/baritone/api/pathing/goals/GoalInverted.java
Normal file
51
src/api/java/baritone/api/pathing/goals/GoalInverted.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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());
|
||||
}
|
||||
}
|
@@ -18,6 +18,7 @@
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -46,6 +47,11 @@ public class GoalXZ implements Goal {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public GoalXZ(BetterBlockPos pos) {
|
||||
this.x = pos.x;
|
||||
this.z = pos.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGoal(int x, int y, int z) {
|
||||
return x == this.x && z == this.z;
|
||||
@@ -92,7 +98,7 @@ public class GoalXZ implements Goal {
|
||||
float theta = (float) Math.toRadians(yaw);
|
||||
double x = origin.x - MathHelper.sin(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() {
|
||||
|
@@ -18,11 +18,13 @@
|
||||
package baritone.api.process;
|
||||
|
||||
import baritone.api.utils.ISchematic;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@@ -58,7 +60,16 @@ public interface IBuilderProcess extends IBaritoneProcess {
|
||||
|
||||
void pause();
|
||||
|
||||
boolean isPaused();
|
||||
|
||||
void resume();
|
||||
|
||||
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();
|
||||
}
|
||||
|
@@ -17,20 +17,23 @@
|
||||
|
||||
package baritone.api.process;
|
||||
|
||||
import baritone.api.utils.BlockOptionalMeta;
|
||||
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 9/23/2018
|
||||
*/
|
||||
public interface IMineProcess extends IBaritoneProcess {
|
||||
|
||||
/**
|
||||
* Begin to search for and mine the specified blocks until
|
||||
* 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
|
||||
*/
|
||||
void mineByName(int quantity, String... blocks);
|
||||
@@ -41,9 +44,18 @@ public interface IMineProcess extends IBaritoneProcess {
|
||||
* are mined. This is based on the first target block to mine.
|
||||
*
|
||||
* @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.
|
||||
@@ -54,6 +66,38 @@ public interface IMineProcess extends IBaritoneProcess {
|
||||
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(
|
||||
Arrays.stream(blocks)
|
||||
.map(BlockOptionalMeta::new)
|
||||
.toArray(BlockOptionalMeta[]::new)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin to search for and mine the specified blocks.
|
||||
*
|
||||
|
47
src/api/java/baritone/api/schematic/AbstractSchematic.java
Normal file
47
src/api/java/baritone/api/schematic/AbstractSchematic.java
Normal file
@@ -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.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;
|
||||
}
|
||||
}
|
78
src/api/java/baritone/api/schematic/CompositeSchematic.java
Normal file
78
src/api/java/baritone/api/schematic/CompositeSchematic.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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,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.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;
|
||||
}
|
||||
}
|
54
src/api/java/baritone/api/schematic/FillSchematic.java
Normal file
54
src/api/java/baritone/api/schematic/FillSchematic.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
44
src/api/java/baritone/api/schematic/MaskSchematic.java
Normal file
44
src/api/java/baritone/api/schematic/MaskSchematic.java
Normal file
@@ -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.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 partOfMask(x, y, z, currentState) && schematic.inSchematic(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];
|
||||
}
|
||||
}
|
32
src/api/java/baritone/api/schematic/ShellSchematic.java
Normal file
32
src/api/java/baritone/api/schematic/ShellSchematic.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
32
src/api/java/baritone/api/schematic/WallsSchematic.java
Normal file
32
src/api/java/baritone/api/schematic/WallsSchematic.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
90
src/api/java/baritone/api/selection/ISelection.java
Normal file
90
src/api/java/baritone/api/selection/ISelection.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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);
|
||||
}
|
115
src/api/java/baritone/api/selection/ISelectionManager.java
Normal file
115
src/api/java/baritone/api/selection/ISelectionManager.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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);
|
||||
}
|
300
src/api/java/baritone/api/utils/BlockOptionalMeta.java
Normal file
300
src/api/java/baritone/api/utils/BlockOptionalMeta.java
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
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 = isNull(meta);
|
||||
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 static java.util.Arrays.asList;
|
||||
|
||||
public class BlockOptionalMetaLookup {
|
||||
private final BlockOptionalMeta[] boms;
|
||||
|
||||
public BlockOptionalMetaLookup(BlockOptionalMeta... boms) {
|
||||
this.boms = boms;
|
||||
}
|
||||
|
||||
public BlockOptionalMetaLookup(Block... blocks) {
|
||||
this.boms = Arrays.stream(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 = Arrays.stream(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 asList(boms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"BlockOptionalMetaLookup{%s}",
|
||||
Arrays.toString(boms)
|
||||
);
|
||||
}
|
||||
}
|
@@ -22,7 +22,6 @@ import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BlockUtils {
|
||||
private static transient Map<String, Block> resourceCache = new HashMap<>();
|
||||
@@ -39,7 +38,11 @@ public class BlockUtils {
|
||||
|
||||
public static Block stringToBlockRequired(String name) {
|
||||
Block block = stringToBlockNullable(name);
|
||||
Objects.requireNonNull(block);
|
||||
|
||||
if (block == null) {
|
||||
throw new NullPointerException(String.format("Invalid block name %s", name));
|
||||
}
|
||||
|
||||
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,10 @@ import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/1/2018
|
||||
@@ -34,13 +38,17 @@ public interface Helper {
|
||||
*/
|
||||
Helper HELPER = new Helper() {};
|
||||
|
||||
ITextComponent MESSAGE_PREFIX = new TextComponentString(String.format(
|
||||
"%s[%sBaritone%s]%s",
|
||||
TextFormatting.DARK_PURPLE,
|
||||
TextFormatting.LIGHT_PURPLE,
|
||||
TextFormatting.DARK_PURPLE,
|
||||
TextFormatting.GRAY
|
||||
));
|
||||
static ITextComponent getPrefix() {
|
||||
ITextComponent baritone = new TextComponentString(BaritoneAPI.getSettings().shortBaritonePrefix.value ? "B" : "Baritone");
|
||||
baritone.getStyle().setColor(TextFormatting.LIGHT_PURPLE);
|
||||
ITextComponent prefix = new TextComponentString("");
|
||||
prefix.getStyle().setColor(TextFormatting.DARK_PURPLE);
|
||||
prefix.appendText("[");
|
||||
prefix.appendSibling(baritone);
|
||||
prefix.appendText("]");
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
@@ -59,14 +67,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(" "));
|
||||
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) {
|
||||
Arrays.stream(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
|
||||
*/
|
||||
default void logDirect(String message) {
|
||||
ITextComponent component = MESSAGE_PREFIX.createCopy();
|
||||
component.getStyle().setColor(TextFormatting.GRAY);
|
||||
component.appendSibling(new TextComponentString(" " + message));
|
||||
Minecraft.getMinecraft().addScheduledTask(() -> BaritoneAPI.getSettings().logger.value.accept(component));
|
||||
logDirect(message, TextFormatting.GRAY);
|
||||
}
|
||||
}
|
||||
|
@@ -47,9 +47,21 @@ public interface IPlayerContext {
|
||||
default BetterBlockPos playerFeet() {
|
||||
// TODO find a better way to deal with soul sand!!!!!
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -20,9 +20,11 @@ package baritone.api.utils;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic representation of a schematic. Provides the dimensions and
|
||||
* the desired statefor a given position relative to the origin.
|
||||
* Basic representation of a schematic. Provides the dimensions and the desired statefor a given position relative to
|
||||
* the origin.
|
||||
*
|
||||
* @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,
|
||||
* 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 y The y position of the block, relative to the origin
|
||||
* @param z The z 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 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
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
*
|
||||
* @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 z The z 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 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
|
||||
*/
|
||||
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
|
||||
|
@@ -121,6 +121,40 @@ public class SettingsUtil {
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of a setting and returns it as a string, with package names stripped.
|
||||
*
|
||||
* 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) {
|
||||
if (BaritoneAPI.getSettings().censorCoordinates.value) {
|
||||
return "<censored>";
|
||||
@@ -133,11 +167,8 @@ public class SettingsUtil {
|
||||
if (setting.getName().equals("logger")) {
|
||||
return "logger";
|
||||
}
|
||||
Parser io = Parser.getParser(setting.getType());
|
||||
if (io == null) {
|
||||
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting.getName());
|
||||
}
|
||||
return setting.getName() + " " + io.toString(new ParserContext(setting), setting.value);
|
||||
|
||||
return setting.getName() + " " + settingValueToString(setting);
|
||||
}
|
||||
|
||||
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),
|
||||
FLOAT(Float.class, Float::parseFloat),
|
||||
LONG(Long.class, Long::parseLong),
|
||||
STRING(String.class, String::new),
|
||||
ENUMFACING(EnumFacing.class, EnumFacing::byName),
|
||||
COLOR(
|
||||
Color.class,
|
||||
|
225
src/api/java/baritone/api/utils/command/BaritoneChatControl.java
Normal file
225
src/api/java/baritone/api/utils/command/BaritoneChatControl.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.accessor.IGuiScreen;
|
||||
import baritone.api.event.events.ChatEvent;
|
||||
import baritone.api.event.events.TabCompleteEvent;
|
||||
import baritone.api.event.listener.AbstractGameEventListener;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.command.argument.CommandArgument;
|
||||
import baritone.api.utils.command.exception.CommandNotFoundException;
|
||||
import baritone.api.utils.command.execution.CommandExecution;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||
import baritone.api.utils.command.manager.CommandManager;
|
||||
import com.mojang.realmsclient.util.Pair;
|
||||
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.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class BaritoneChatControl implements Helper, AbstractGameEventListener {
|
||||
public final IBaritone baritone;
|
||||
public final IPlayerContext ctx;
|
||||
public final Settings settings = BaritoneAPI.getSettings();
|
||||
public static String FORCE_COMMAND_PREFIX = String.format("<<%s>>", UUID.randomUUID().toString());
|
||||
|
||||
public BaritoneChatControl(IBaritone baritone) {
|
||||
this.baritone = baritone;
|
||||
this.ctx = baritone.getPlayerContext();
|
||||
baritone.getGameEventHandler().registerEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendChatMessage(ChatEvent event) {
|
||||
String msg = event.getMessage();
|
||||
String prefix = settings.prefix.value;
|
||||
boolean forceRun = msg.startsWith(FORCE_COMMAND_PREFIX);
|
||||
|
||||
if ((settings.prefixControl.value && msg.startsWith(prefix)) || forceRun) {
|
||||
event.cancel();
|
||||
|
||||
String commandStr = msg.substring(forceRun ? FORCE_COMMAND_PREFIX.length() : prefix.length());
|
||||
|
||||
if (!runCommand(commandStr) && !commandStr.trim().isEmpty()) {
|
||||
new CommandNotFoundException(CommandExecution.expand(commandStr).first()).handle(null, null);
|
||||
}
|
||||
} else if ((settings.chatControl.value || settings.chatControlAnyway.value) && runCommand(msg)) {
|
||||
event.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void logRanCommand(String command, String rest) {
|
||||
if (settings.echoCommands.value) {
|
||||
String msg = command + rest;
|
||||
String toDisplay = settings.censorRanCommands.value ? command + " ..." : msg;
|
||||
|
||||
ITextComponent component = new TextComponentString(String.format("> %s", toDisplay));
|
||||
component.getStyle()
|
||||
.setColor(TextFormatting.WHITE)
|
||||
.setHoverEvent(new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT,
|
||||
new TextComponentString("Click to rerun command")
|
||||
))
|
||||
.setClickEvent(new ClickEvent(
|
||||
ClickEvent.Action.RUN_COMMAND,
|
||||
FORCE_COMMAND_PREFIX + msg
|
||||
));
|
||||
|
||||
logDirect(component);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean runCommand(String msg) {
|
||||
if (msg.trim().equalsIgnoreCase("damn")) {
|
||||
logDirect("daniel");
|
||||
return false;
|
||||
} else if (msg.trim().equalsIgnoreCase("orderpizza")) {
|
||||
try {
|
||||
((IGuiScreen) mc.currentScreen).openLink(new URI("https://www.dominos.com/en/pages/order/"));
|
||||
} catch (NullPointerException | URISyntaxException ignored) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msg.isEmpty()) {
|
||||
msg = "help";
|
||||
}
|
||||
|
||||
Pair<String, List<CommandArgument>> pair = CommandExecution.expand(msg);
|
||||
String command = pair.first();
|
||||
String rest = msg.substring(pair.first().length());
|
||||
ArgConsumer argc = new ArgConsumer(pair.second());
|
||||
|
||||
if (!argc.has()) {
|
||||
Settings.Setting setting = settings.byLowerName.get(command.toLowerCase(Locale.US));
|
||||
|
||||
if (setting != null) {
|
||||
logRanCommand(command, rest);
|
||||
|
||||
if (setting.getValueClass() == Boolean.class) {
|
||||
CommandManager.execute(String.format("set toggle %s", setting.getName()));
|
||||
} else {
|
||||
CommandManager.execute(String.format("set %s", setting.getName()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (argc.hasExactlyOne()) {
|
||||
for (Settings.Setting setting : settings.allSettings) {
|
||||
if (setting.getName().equals("logger")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setting.getName().equalsIgnoreCase(pair.first())) {
|
||||
logRanCommand(command, rest);
|
||||
CommandManager.execute(String.format("set %s %s", setting.getName(), argc.getString()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CommandExecution execution = CommandExecution.from(pair);
|
||||
|
||||
if (isNull(execution)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
logRanCommand(command, rest);
|
||||
CommandManager.execute(execution);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreTabComplete(TabCompleteEvent.Pre event) {
|
||||
if (!settings.prefixControl.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
String prefix = event.prefix.get();
|
||||
String commandPrefix = settings.prefix.value;
|
||||
|
||||
if (!prefix.startsWith(commandPrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String msg = prefix.substring(commandPrefix.length());
|
||||
|
||||
List<CommandArgument> args = CommandArgument.from(msg, true);
|
||||
Stream<String> stream = tabComplete(msg);
|
||||
|
||||
if (args.size() == 1) {
|
||||
stream = stream.map(x -> commandPrefix + x);
|
||||
}
|
||||
|
||||
event.completions.set(stream.toArray(String[]::new));
|
||||
}
|
||||
|
||||
public Stream<String> tabComplete(String msg) {
|
||||
List<CommandArgument> args = CommandArgument.from(msg, true);
|
||||
ArgConsumer argc = new ArgConsumer(args);
|
||||
|
||||
if (argc.hasAtMost(2)) {
|
||||
if (argc.hasExactly(1)) {
|
||||
return new TabCompleteHelper()
|
||||
.addCommands()
|
||||
.addSettings()
|
||||
.filterPrefix(argc.getString())
|
||||
.stream();
|
||||
}
|
||||
|
||||
Settings.Setting setting = settings.byLowerName.get(argc.getString().toLowerCase(Locale.US));
|
||||
|
||||
if (nonNull(setting)) {
|
||||
if (setting.getValueClass() == Boolean.class) {
|
||||
TabCompleteHelper helper = new TabCompleteHelper();
|
||||
|
||||
if ((Boolean) setting.value) {
|
||||
helper.append(Stream.of("true", "false"));
|
||||
} else {
|
||||
helper.append(Stream.of("false", "true"));
|
||||
}
|
||||
|
||||
return helper.filterPrefix(argc.getString()).stream();
|
||||
} else {
|
||||
return Stream.of(SettingsUtil.settingValueToString(setting));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CommandManager.tabComplete(msg);
|
||||
}
|
||||
}
|
113
src/api/java/baritone/api/utils/command/Command.java
Normal file
113
src/api/java/baritone/api/utils/command/Command.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.event.listener.AbstractGameEventListener;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.command.execution.CommandExecution;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
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, AbstractGameEventListener {
|
||||
protected IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
|
||||
protected Settings settings = BaritoneAPI.getSettings();
|
||||
protected IPlayerContext ctx = baritone.getPlayerContext();
|
||||
protected Minecraft MC = mc;
|
||||
|
||||
/**
|
||||
* 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(List<String> names) {
|
||||
this.names = names.stream()
|
||||
.map(s -> s.toLowerCase(Locale.US))
|
||||
.collect(Collectors.toList());
|
||||
baritone.getGameEventHandler().registerEventListener(this);
|
||||
}
|
||||
|
||||
protected Command(String name) {
|
||||
this(Collections.singletonList(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes this command with the specified arguments.
|
||||
*
|
||||
* @param execution The command execution to execute this command with
|
||||
*/
|
||||
public void execute(CommandExecution execution) {
|
||||
executed(execution.label, execution.args, execution.settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab completes this command with the specified arguments. This won't throw any exceptions ever.
|
||||
*
|
||||
* @param execution The command execution to tab complete
|
||||
* @return The list of completions.
|
||||
*/
|
||||
public Stream<String> tabComplete(CommandExecution execution) {
|
||||
try {
|
||||
return tabCompleted(execution.label, execution.args, execution.settings);
|
||||
} catch (Throwable t) {
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this command is executed.
|
||||
*/
|
||||
protected abstract void executed(String label, ArgConsumer args, Settings settings);
|
||||
|
||||
/**
|
||||
* 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, Settings settings);
|
||||
|
||||
/**
|
||||
* @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,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.utils.command.argparser;
|
||||
|
||||
public abstract class ArgParser<T> implements IArgParser<T> {
|
||||
private final Class<T> klass;
|
||||
|
||||
protected ArgParser(Class<T> klass) {
|
||||
this.klass = klass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getKlass() {
|
||||
return klass;
|
||||
}
|
||||
|
||||
public static abstract class Stated<T, S> extends ArgParser<T> implements IArgParser.Stated<T, S> {
|
||||
private final Class<S> stateKlass;
|
||||
|
||||
protected Stated(Class<T> klass, Class<S> stateKlass) {
|
||||
super(klass);
|
||||
this.stateKlass = stateKlass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<S> getStateKlass() {
|
||||
return stateKlass;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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.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.registry.Registry;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class ArgParserManager {
|
||||
public static final Registry<ArgParser> REGISTRY = new Registry<>();
|
||||
|
||||
static {
|
||||
DefaultArgParsers.ALL.forEach(REGISTRY::register);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param klass The class to search for.
|
||||
* @return A parser that can parse arguments into this class, if found.
|
||||
*/
|
||||
public static <T> ArgParser.Stateless<T> getParserStateless(Class<T> klass) {
|
||||
//noinspection unchecked
|
||||
return REGISTRY.descendingStream()
|
||||
.filter(ArgParser.Stateless.class::isInstance)
|
||||
.map(ArgParser.Stateless.class::cast)
|
||||
.filter(parser -> parser.getKlass().isAssignableFrom(klass))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param klass The class to search for.
|
||||
* @return A parser that can parse arguments into this class, if found.
|
||||
*/
|
||||
public static <T, S> ArgParser.Stated<T, S> getParserStated(Class<T> klass, Class<S> stateKlass) {
|
||||
//noinspection unchecked
|
||||
return REGISTRY.descendingStream()
|
||||
.filter(ArgParser.Stated.class::isInstance)
|
||||
.map(ArgParser.Stated.class::cast)
|
||||
.filter(parser -> parser.getKlass().isAssignableFrom(klass))
|
||||
.filter(parser -> parser.getStateKlass().isAssignableFrom(stateKlass))
|
||||
.map(ArgParser.Stated.class::cast)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to parse the specified argument with a stateless {@link ArgParser} that outputs the specified class.
|
||||
*
|
||||
* @param klass The class to parse the argument into.
|
||||
* @param arg The argument to parse.
|
||||
* @return An instance of the specified class.
|
||||
* @throws CommandNoParserForTypeException If no parser exists for that type
|
||||
* @throws CommandInvalidTypeException If the parsing failed
|
||||
* @see ArgParser.Stateless
|
||||
*/
|
||||
public static <T> T parseStateless(Class<T> klass, CommandArgument arg) {
|
||||
ArgParser.Stateless<T> parser = getParserStateless(klass);
|
||||
|
||||
if (isNull(parser)) {
|
||||
throw new CommandNoParserForTypeException(klass);
|
||||
}
|
||||
|
||||
try {
|
||||
return parser.parseArg(arg);
|
||||
} catch (RuntimeException exc) {
|
||||
throw new CommandInvalidTypeException(arg, klass.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to parse the specified argument with a stated {@link ArgParser} that outputs the specified class.
|
||||
*
|
||||
* @param klass The class to parse the argument into.
|
||||
* @param arg The argument to parse.
|
||||
* @param state The state to pass to the {@link ArgParser.Stated}.
|
||||
* @return An instance of the specified class.
|
||||
* @throws CommandNoParserForTypeException If no parser exists for that type
|
||||
* @throws CommandInvalidTypeException If the parsing failed
|
||||
* @see ArgParser.Stated
|
||||
*/
|
||||
public static <T, S> T parseStated(Class<T> klass, Class<S> stateKlass, CommandArgument arg, S state) {
|
||||
ArgParser.Stated<T, S> parser = getParserStated(klass, stateKlass);
|
||||
|
||||
if (isNull(parser)) {
|
||||
throw new CommandNoParserForTypeException(klass);
|
||||
}
|
||||
|
||||
try {
|
||||
return parser.parseArg(arg, state);
|
||||
} catch (RuntimeException exc) {
|
||||
throw new CommandInvalidTypeException(arg, klass.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.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class DefaultArgParsers {
|
||||
public static class IntArgumentParser extends ArgParser<Integer> implements IArgParser.Stateless<Integer> {
|
||||
public static final IntArgumentParser INSTANCE = new IntArgumentParser();
|
||||
|
||||
public IntArgumentParser() {
|
||||
super(Integer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer parseArg(CommandArgument arg) throws RuntimeException {
|
||||
return Integer.parseInt(arg.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LongArgumentParser extends ArgParser<Long> implements IArgParser.Stateless<Long> {
|
||||
public static final LongArgumentParser INSTANCE = new LongArgumentParser();
|
||||
|
||||
public LongArgumentParser() {
|
||||
super(Long.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long parseArg(CommandArgument arg) throws RuntimeException {
|
||||
return Long.parseLong(arg.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FloatArgumentParser extends ArgParser<Float> implements IArgParser.Stateless<Float> {
|
||||
public static final FloatArgumentParser INSTANCE = new FloatArgumentParser();
|
||||
|
||||
public FloatArgumentParser() {
|
||||
super(Float.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float parseArg(CommandArgument arg) throws RuntimeException {
|
||||
String value = arg.value;
|
||||
|
||||
if (!value.matches("^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$")) {
|
||||
throw new RuntimeException("failed float format check");
|
||||
}
|
||||
|
||||
return Float.parseFloat(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DoubleArgumentParser extends ArgParser<Double> implements IArgParser.Stateless<Double> {
|
||||
public static final DoubleArgumentParser INSTANCE = new DoubleArgumentParser();
|
||||
|
||||
public DoubleArgumentParser() {
|
||||
super(Double.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double parseArg(CommandArgument arg) throws RuntimeException {
|
||||
String value = arg.value;
|
||||
|
||||
if (!value.matches("^([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$")) {
|
||||
throw new RuntimeException("failed double format check");
|
||||
}
|
||||
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class BooleanArgumentParser extends ArgParser<Boolean> implements IArgParser.Stateless<Boolean> {
|
||||
public static final BooleanArgumentParser INSTANCE = new BooleanArgumentParser();
|
||||
|
||||
public static final List<String> TRUTHY_VALUES = asList("1", "true", "yes", "t", "y", "on", "enable");
|
||||
public static final List<String> FALSY_VALUES = asList("0", "false", "no", "f", "n", "off", "disable");
|
||||
|
||||
public BooleanArgumentParser() {
|
||||
super(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 RuntimeException("invalid boolean");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final List<ArgParser<?>> ALL = asList(
|
||||
IntArgumentParser.INSTANCE,
|
||||
LongArgumentParser.INSTANCE,
|
||||
FloatArgumentParser.INSTANCE,
|
||||
DoubleArgumentParser.INSTANCE,
|
||||
BooleanArgumentParser.INSTANCE
|
||||
);
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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> getKlass();
|
||||
|
||||
/**
|
||||
* 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 RuntimeException;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> getStateKlass();
|
||||
|
||||
/**
|
||||
* @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 RuntimeException;
|
||||
}
|
||||
}
|
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.ArgParser;
|
||||
import baritone.api.utils.command.argparser.ArgParserManager;
|
||||
import baritone.api.utils.command.exception.CommandInvalidArgumentException;
|
||||
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||
import baritone.api.utils.command.exception.CommandNoParserForTypeException;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 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. Check out {@link ArgConsumer#from(String)}
|
||||
*/
|
||||
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) {
|
||||
return Arrays.stream(enumClass.getEnumConstants())
|
||||
.filter(e -> e.name().equalsIgnoreCase(value))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new CommandInvalidTypeException(this, enumClass.getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to use a <b>stateless</b> {@link ArgParser} 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 CommandNoParserForTypeException If no parser exists for that type
|
||||
* @throws CommandInvalidTypeException If the parsing failed
|
||||
* @see ArgParser.Stateless
|
||||
*/
|
||||
public <T> T getAs(Class<T> type) {
|
||||
return ArgParserManager.parseStateless(type, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to use a <b>stateless</b> {@link ArgParser} to parse this argument into the specified class
|
||||
*
|
||||
* @param type The class to parse this argument into
|
||||
* @return If the parser succeeded
|
||||
* @see ArgParser.Stateless
|
||||
*/
|
||||
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 ArgParser} 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 CommandNoParserForTypeException If no parser exists for that type
|
||||
* @throws CommandInvalidTypeException If the parsing failed
|
||||
* @see ArgParser.Stated
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public <T, S> T getAs(Class<T> type, Class<S> stateType, S state) {
|
||||
return ArgParserManager.parseStated(type, stateType, this, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to use a <b>stated</b> {@link ArgParser} to parse this argument into the specified class
|
||||
*
|
||||
* @param type The class to parse this argument into
|
||||
* @return If the parser succeeded
|
||||
* @see ArgParser.Stated
|
||||
*/
|
||||
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,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.helpers.arguments.ArgConsumer;
|
||||
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 class BlockById implements IDatatypeFor<Block> {
|
||||
public final Block block;
|
||||
|
||||
public BlockById() {
|
||||
block = null;
|
||||
}
|
||||
|
||||
public BlockById(ArgConsumer consumer) {
|
||||
ResourceLocation id = new ResourceLocation(consumer.getString());
|
||||
|
||||
if ((block = Block.REGISTRY.getObject(id)) == Blocks.AIR) {
|
||||
throw new IllegalArgumentException("no block found by that id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block get() {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return new TabCompleteHelper()
|
||||
.append(
|
||||
Block.REGISTRY.getKeys()
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
)
|
||||
.filterPrefixNamespaced(consumer.getString())
|
||||
.sortAlphabetically()
|
||||
.stream();
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.helpers.arguments.ArgConsumer;
|
||||
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;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class EntityClassById implements IDatatypeFor<Class<? extends Entity>> {
|
||||
public final Class<? extends Entity> entity;
|
||||
|
||||
public EntityClassById() {
|
||||
entity = null;
|
||||
}
|
||||
|
||||
public EntityClassById(ArgConsumer consumer) {
|
||||
ResourceLocation id = new ResourceLocation(consumer.getString());
|
||||
|
||||
if (isNull(entity = EntityList.REGISTRY.getObject(id))) {
|
||||
throw new IllegalArgumentException("no entity found by that id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Entity> get() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return new TabCompleteHelper()
|
||||
.append(
|
||||
EntityList.getEntityNameList()
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
)
|
||||
.filterPrefixNamespaced(consumer.getString())
|
||||
.sortAlphabetically()
|
||||
.stream();
|
||||
}
|
||||
}
|
@@ -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.utils.command.datatypes;
|
||||
|
||||
import baritone.api.utils.BlockOptionalMeta;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ForBlockOptionalMeta implements IDatatypeFor<BlockOptionalMeta> {
|
||||
public final BlockOptionalMeta selector;
|
||||
|
||||
public ForBlockOptionalMeta() {
|
||||
selector = null;
|
||||
}
|
||||
|
||||
public ForBlockOptionalMeta(ArgConsumer consumer) {
|
||||
selector = new BlockOptionalMeta(consumer.getString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockOptionalMeta get() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return consumer.tabCompleteDatatype(BlockById.class);
|
||||
}
|
||||
}
|
@@ -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.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ForEnumFacing implements IDatatypeFor<EnumFacing> {
|
||||
private final EnumFacing facing;
|
||||
|
||||
public ForEnumFacing() {
|
||||
facing = null;
|
||||
}
|
||||
|
||||
public ForEnumFacing(ArgConsumer consumer) {
|
||||
facing = EnumFacing.valueOf(consumer.getString().toUpperCase(Locale.US));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumFacing get() {
|
||||
return facing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return new TabCompleteHelper()
|
||||
.append(
|
||||
Arrays.stream(EnumFacing.values())
|
||||
.map(EnumFacing::getName)
|
||||
.map(String::toLowerCase)
|
||||
)
|
||||
.filterPrefix(consumer.getString())
|
||||
.stream();
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.BaritoneAPI;
|
||||
import baritone.api.cache.IWaypoint;
|
||||
import baritone.api.cache.IWaypointCollection;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ForWaypoints implements IDatatypeFor<IWaypoint[]> {
|
||||
private final IWaypoint[] waypoints;
|
||||
|
||||
public ForWaypoints() {
|
||||
waypoints = null;
|
||||
}
|
||||
|
||||
public ForWaypoints(String arg) {
|
||||
IWaypoint.Tag tag = IWaypoint.Tag.getByName(arg);
|
||||
waypoints = tag == null ? getWaypointsByName(arg) : getWaypointsByTag(tag);
|
||||
}
|
||||
|
||||
public ForWaypoints(ArgConsumer consumer) {
|
||||
this(consumer.getString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWaypoint[] get() {
|
||||
return waypoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return new TabCompleteHelper()
|
||||
.append(getWaypointNames())
|
||||
.sortAlphabetically()
|
||||
.prepend(IWaypoint.Tag.getAllNames())
|
||||
.filterPrefix(consumer.getString())
|
||||
.stream();
|
||||
}
|
||||
|
||||
public static IWaypointCollection waypoints() {
|
||||
return BaritoneAPI.getProvider()
|
||||
.getPrimaryBaritone()
|
||||
.getWorldProvider()
|
||||
.getCurrentWorld()
|
||||
.getWaypoints();
|
||||
}
|
||||
|
||||
public static IWaypoint[] getWaypoints() {
|
||||
return waypoints().getAllWaypoints().stream()
|
||||
.sorted(Comparator.comparingLong(IWaypoint::getCreationTimestamp).reversed())
|
||||
.toArray(IWaypoint[]::new);
|
||||
}
|
||||
|
||||
public static String[] getWaypointNames() {
|
||||
return Arrays.stream(getWaypoints())
|
||||
.map(IWaypoint::getName)
|
||||
.filter(name -> !name.equals(""))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public static IWaypoint[] getWaypointsByTag(IWaypoint.Tag tag) {
|
||||
return waypoints().getByTag(tag).stream()
|
||||
.sorted(Comparator.comparingLong(IWaypoint::getCreationTimestamp).reversed())
|
||||
.toArray(IWaypoint[]::new);
|
||||
}
|
||||
|
||||
public static IWaypoint[] getWaypointsByName(String name) {
|
||||
return Arrays.stream(getWaypoints())
|
||||
.filter(waypoint -> waypoint.getName().equalsIgnoreCase(name))
|
||||
.toArray(IWaypoint[]::new);
|
||||
}
|
||||
}
|
@@ -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.utils.command.argparser.ArgParser;
|
||||
import baritone.api.utils.command.exception.CommandInvalidArgumentException;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Since interfaces cannot enforce the presence of a constructor, it's on you to make sure there is a constructor that
|
||||
* accepts a single {@link ArgConsumer} argument. The constructor will perform all needed validation, and {@link
|
||||
* ArgConsumer#getDatatype(Class)} will handle RuntimeExceptions and translate them into {@link
|
||||
* CommandInvalidArgumentException}s. There must always be a constructor with no arguments so that {@link ArgConsumer}
|
||||
* can create an instance for tab completion.
|
||||
*/
|
||||
public interface IDatatype {
|
||||
/**
|
||||
* One benefit over datatypes over {@link ArgParser}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.
|
||||
* <p>
|
||||
* See {@link RelativeFile} for a very advanced example of tab completion. You wouldn't want this pasted into every
|
||||
* command that uses files - right? Right?
|
||||
*
|
||||
* @param consumer 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(Class)
|
||||
*/
|
||||
Stream<String> tabComplete(ArgConsumer consumer);
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface IDatatypeFor<T> extends IDatatype {
|
||||
T get();
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface IDatatypePost<T, O> extends IDatatype {
|
||||
T apply(O original);
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.BaritoneAPI;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class PlayerByUsername implements IDatatypeFor<EntityPlayer> {
|
||||
private final List<EntityPlayer> players =
|
||||
BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().world().playerEntities;
|
||||
public final EntityPlayer player;
|
||||
|
||||
public PlayerByUsername() {
|
||||
player = null;
|
||||
}
|
||||
|
||||
public PlayerByUsername(ArgConsumer consumer) {
|
||||
String username = consumer.getString();
|
||||
|
||||
player = players
|
||||
.stream()
|
||||
.filter(s -> s.getName().equalsIgnoreCase(username))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (isNull(player)) {
|
||||
throw new IllegalArgumentException("no player found by that username");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPlayer get() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return new TabCompleteHelper()
|
||||
.append(
|
||||
players
|
||||
.stream()
|
||||
.map(EntityPlayer::getName)
|
||||
)
|
||||
.filterPrefix(consumer.getString())
|
||||
.sortAlphabetically()
|
||||
.stream();
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class RelativeBlockPos implements IDatatypePost<BetterBlockPos, BetterBlockPos> {
|
||||
final RelativeCoordinate x;
|
||||
final RelativeCoordinate y;
|
||||
final RelativeCoordinate z;
|
||||
|
||||
public RelativeBlockPos() {
|
||||
x = null;
|
||||
y = null;
|
||||
z = null;
|
||||
}
|
||||
|
||||
public RelativeBlockPos(ArgConsumer consumer) {
|
||||
x = consumer.getDatatype(RelativeCoordinate.class);
|
||||
y = consumer.getDatatype(RelativeCoordinate.class);
|
||||
z = consumer.getDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BetterBlockPos apply(BetterBlockPos origin) {
|
||||
return new BetterBlockPos(
|
||||
x.apply((double) origin.x),
|
||||
y.apply((double) origin.y),
|
||||
z.apply((double) origin.z)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
if (consumer.has() && !consumer.has(4)) {
|
||||
while (consumer.has(2)) {
|
||||
if (isNull(consumer.peekDatatypeOrNull(RelativeCoordinate.class))) {
|
||||
break;
|
||||
}
|
||||
|
||||
consumer.get();
|
||||
}
|
||||
|
||||
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.helpers.arguments.ArgConsumer;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class RelativeCoordinate implements IDatatypePost<Double, Double> {
|
||||
public static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$");
|
||||
|
||||
final boolean isRelative;
|
||||
final double offset;
|
||||
|
||||
public RelativeCoordinate() {
|
||||
isRelative = true;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
public RelativeCoordinate(ArgConsumer consumer) {
|
||||
Matcher matcher = PATTERN.matcher(consumer.getString());
|
||||
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("pattern doesn't match");
|
||||
}
|
||||
|
||||
isRelative = !matcher.group(1).isEmpty();
|
||||
offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double apply(Double origin) {
|
||||
if (isRelative) {
|
||||
return origin + offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public int applyFloor(double origin) {
|
||||
return MathHelper.floor(apply(origin));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
if (!consumer.has(2) && consumer.getString().matches("^(~|$)")) {
|
||||
return Stream.of("~");
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static baritone.api.utils.Helper.HELPER;
|
||||
|
||||
public class RelativeFile implements IDatatypePost<File, File> {
|
||||
private final Path path;
|
||||
|
||||
public RelativeFile() {
|
||||
path = null;
|
||||
}
|
||||
|
||||
public RelativeFile(ArgConsumer consumer) {
|
||||
try {
|
||||
path = FileSystems.getDefault().getPath(consumer.getString());
|
||||
} catch (InvalidPathException e) {
|
||||
throw new IllegalArgumentException("invalid path");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seriously
|
||||
*
|
||||
* @param file File
|
||||
* @return Canonical file of file
|
||||
* @author LoganDark and his hate of checked exceptions
|
||||
*/
|
||||
private static File SHUT_THE_FUCK_UP_IOEXCEPTION_NOBODY_LIKES_YOU(File file) {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Fuck you", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<String> tabComplete(ArgConsumer consumer, File base0) {
|
||||
// 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
|
||||
File base = SHUT_THE_FUCK_UP_IOEXCEPTION_NOBODY_LIKES_YOU(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 Arrays.stream(Objects.requireNonNull(SHUT_THE_FUCK_UP_IOEXCEPTION_NOBODY_LIKES_YOU(
|
||||
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(" "));
|
||||
}
|
||||
|
||||
@Override
|
||||
public File apply(File original) {
|
||||
return SHUT_THE_FUCK_UP_IOEXCEPTION_NOBODY_LIKES_YOU(original.toPath().resolve(path).toFile());
|
||||
}
|
||||
|
||||
public static File gameDir() {
|
||||
File gameDir = HELPER.mc.gameDir.getAbsoluteFile();
|
||||
|
||||
if (gameDir.getName().equals(".")) {
|
||||
return gameDir.getParentFile();
|
||||
}
|
||||
|
||||
return gameDir;
|
||||
}
|
||||
}
|
@@ -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.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.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class RelativeGoal implements IDatatypePost<Goal, BetterBlockPos> {
|
||||
final RelativeCoordinate[] coords;
|
||||
|
||||
public RelativeGoal() {
|
||||
coords = new RelativeCoordinate[0];
|
||||
}
|
||||
|
||||
public RelativeGoal(ArgConsumer consumer) {
|
||||
List<RelativeCoordinate> coordsList = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (nonNull(consumer.peekDatatypeOrNull(RelativeCoordinate.class))) {
|
||||
coordsList.add(consumer.getDatatype(RelativeCoordinate.class));
|
||||
}
|
||||
}
|
||||
|
||||
coords = coordsList.toArray(new RelativeCoordinate[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Goal apply(BetterBlockPos origin) {
|
||||
switch (coords.length) {
|
||||
case 0:
|
||||
return new GoalBlock(origin);
|
||||
case 1:
|
||||
return new GoalYLevel(
|
||||
coords[0].applyFloor(origin.y)
|
||||
);
|
||||
case 2:
|
||||
return new GoalXZ(
|
||||
coords[0].applyFloor(origin.x),
|
||||
coords[1].applyFloor(origin.z)
|
||||
);
|
||||
case 3:
|
||||
return new GoalBlock(
|
||||
coords[0].applyFloor(origin.x),
|
||||
coords[1].applyFloor(origin.y),
|
||||
coords[2].applyFloor(origin.z)
|
||||
);
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected coords size: " + coords.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class RelativeGoalBlock implements IDatatypePost<GoalBlock, BetterBlockPos> {
|
||||
final RelativeCoordinate[] coords;
|
||||
|
||||
public RelativeGoalBlock() {
|
||||
coords = new RelativeCoordinate[0];
|
||||
}
|
||||
|
||||
public RelativeGoalBlock(ArgConsumer consumer) {
|
||||
coords = new RelativeCoordinate[]{
|
||||
consumer.getDatatype(RelativeCoordinate.class),
|
||||
consumer.getDatatype(RelativeCoordinate.class),
|
||||
consumer.getDatatype(RelativeCoordinate.class)
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoalBlock apply(BetterBlockPos origin) {
|
||||
return new GoalBlock(
|
||||
coords[0].applyFloor(origin.x),
|
||||
coords[1].applyFloor(origin.y),
|
||||
coords[2].applyFloor(origin.z)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
if (consumer.hasAtMost(3)) {
|
||||
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
@@ -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.pathing.goals.GoalXZ;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class RelativeGoalXZ implements IDatatypePost<GoalXZ, BetterBlockPos> {
|
||||
final RelativeCoordinate[] coords;
|
||||
|
||||
public RelativeGoalXZ() {
|
||||
coords = new RelativeCoordinate[0];
|
||||
}
|
||||
|
||||
public RelativeGoalXZ(ArgConsumer consumer) {
|
||||
coords = new RelativeCoordinate[]{
|
||||
consumer.getDatatype(RelativeCoordinate.class),
|
||||
consumer.getDatatype(RelativeCoordinate.class)
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoalXZ apply(BetterBlockPos origin) {
|
||||
return new GoalXZ(
|
||||
coords[0].applyFloor(origin.x),
|
||||
coords[1].applyFloor(origin.z)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
if (consumer.hasAtMost(2)) {
|
||||
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
|
||||
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.helpers.arguments.ArgConsumer;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class RelativeGoalYLevel implements IDatatypePost<GoalYLevel, BetterBlockPos> {
|
||||
final RelativeCoordinate coord;
|
||||
|
||||
public RelativeGoalYLevel() {
|
||||
coord = null;
|
||||
}
|
||||
|
||||
public RelativeGoalYLevel(ArgConsumer consumer) {
|
||||
coord = consumer.getDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoalYLevel apply(BetterBlockPos origin) {
|
||||
return new GoalYLevel(coord.applyFloor(origin.y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||
if (consumer.hasAtMost(1)) {
|
||||
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
@@ -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.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 abstract class CommandErrorMessageException extends CommandException {
|
||||
protected CommandErrorMessageException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Command command, List<CommandArgument> args) {
|
||||
HELPER.logDirect(getMessage(), TextFormatting.RED);
|
||||
}
|
||||
}
|
@@ -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.exception;
|
||||
|
||||
import baritone.api.utils.command.Command;
|
||||
import baritone.api.utils.command.argument.CommandArgument;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class CommandException extends RuntimeException {
|
||||
protected CommandException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public abstract void handle(Command command, List<CommandArgument> args);
|
||||
}
|
@@ -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,24 @@
|
||||
/*
|
||||
* 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,38 @@
|
||||
/*
|
||||
* 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,27 @@
|
||||
/*
|
||||
* 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 CommandErrorMessageException {
|
||||
public final Class<?> klass;
|
||||
|
||||
public CommandNoParserForTypeException(Class<?> klass) {
|
||||
super(String.format("Could not find a handler for type %s", klass.getSimpleName()));
|
||||
this.klass = klass;
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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,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.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,24 @@
|
||||
/*
|
||||
* 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,83 @@
|
||||
/*
|
||||
* 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 java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class CommandUnhandledException extends CommandErrorMessageException {
|
||||
public static String getStackTrace(Throwable throwable) {
|
||||
StringWriter sw = new StringWriter();
|
||||
throwable.printStackTrace(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public static String getBaritoneStackTrace(String stackTrace) {
|
||||
List<String> lines = Arrays.stream(stackTrace.split("\n"))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int lastBaritoneLine = 0;
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (lines.get(i).startsWith("\tat baritone.") && lines.get(i).contains("BaritoneChatControl")) {
|
||||
lastBaritoneLine = i;
|
||||
}
|
||||
}
|
||||
|
||||
return String.join("\n", lines.subList(0, lastBaritoneLine + 1));
|
||||
}
|
||||
|
||||
public static String getBaritoneStackTrace(Throwable throwable) {
|
||||
return getBaritoneStackTrace(getStackTrace(throwable));
|
||||
}
|
||||
|
||||
public static String getFriendlierStackTrace(String stackTrace) {
|
||||
List<String> lines = asList(stackTrace.split("\n"));
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
String line = lines.get(i);
|
||||
if (line.startsWith("\tat ")) {
|
||||
if (line.startsWith("\tat baritone.")) {
|
||||
line = line.replaceFirst("^\tat [a-z.]+?([A-Z])", "\tat $1");
|
||||
}
|
||||
|
||||
// line = line.replaceFirst("\\(([^)]+)\\)$", "\n\t . $1");
|
||||
line = line.replaceFirst("\\([^:]+:(\\d+)\\)$", ":$1");
|
||||
line = line.replaceFirst("\\(Unknown Source\\)$", "");
|
||||
lines.set(i, line);
|
||||
}
|
||||
}
|
||||
|
||||
return String.join("\n", lines);
|
||||
}
|
||||
|
||||
public static String getFriendlierStackTrace(Throwable throwable) {
|
||||
return getFriendlierStackTrace(getBaritoneStackTrace(throwable));
|
||||
}
|
||||
|
||||
public CommandUnhandledException(Throwable cause) {
|
||||
super(String.format(
|
||||
"An unhandled exception has occurred:\n\n%s",
|
||||
getFriendlierStackTrace(cause)
|
||||
));
|
||||
}
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.BaritoneAPI;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.utils.command.Command;
|
||||
import baritone.api.utils.command.argument.CommandArgument;
|
||||
import baritone.api.utils.command.exception.CommandException;
|
||||
import baritone.api.utils.command.exception.CommandUnhandledException;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.manager.CommandManager;
|
||||
import com.mojang.realmsclient.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class CommandExecution {
|
||||
/**
|
||||
* The command itself
|
||||
*/
|
||||
private final Command command;
|
||||
|
||||
/**
|
||||
* The name this command was called with
|
||||
*/
|
||||
public final String label;
|
||||
|
||||
/**
|
||||
* The arg consumer
|
||||
*/
|
||||
public final ArgConsumer args;
|
||||
|
||||
/**
|
||||
* The Baritone settings
|
||||
*/
|
||||
public final Settings settings = BaritoneAPI.getSettings();
|
||||
|
||||
public CommandExecution(Command command, String label, ArgConsumer args) {
|
||||
this.command = command;
|
||||
this.label = label;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public static String getLabel(String string) {
|
||||
return string.split("\\s", 2)[0];
|
||||
}
|
||||
|
||||
public static Pair<String, List<CommandArgument>> expand(String string, boolean preserveEmptyLast) {
|
||||
String label = getLabel(string);
|
||||
List<CommandArgument> args = CommandArgument.from(string.substring(label.length()), preserveEmptyLast);
|
||||
return Pair.of(label, args);
|
||||
}
|
||||
|
||||
public static Pair<String, List<CommandArgument>> expand(String string) {
|
||||
return expand(string, false);
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
try {
|
||||
command.execute(this);
|
||||
} catch (CommandException e) {
|
||||
e.handle(command, args.args);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
|
||||
new CommandUnhandledException(t).handle(command, args.args);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<String> tabComplete() {
|
||||
return command.tabComplete(this);
|
||||
}
|
||||
|
||||
public static CommandExecution from(String label, ArgConsumer args) {
|
||||
Command command = CommandManager.getCommand(label);
|
||||
|
||||
if (isNull(command)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CommandExecution(
|
||||
command,
|
||||
label,
|
||||
args
|
||||
);
|
||||
}
|
||||
|
||||
public static CommandExecution from(Pair<String, List<CommandArgument>> pair) {
|
||||
return from(pair.first(), new ArgConsumer(pair.second()));
|
||||
}
|
||||
|
||||
public static CommandExecution from(String string) {
|
||||
return from(expand(string));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* 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.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.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
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 = 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 = nonNull(commandPrefix) && validPage(page - 1);
|
||||
boolean hasNextPage = nonNull(commandPrefix) && 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) {
|
||||
int page = 1;
|
||||
|
||||
consumer.requireMax(1);
|
||||
|
||||
if (consumer.has()) {
|
||||
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 (nonNull(pre)) {
|
||||
pre.run();
|
||||
}
|
||||
|
||||
pagi.display(transform, commandPrefix);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Runnable pre, Function<T, ITextComponent> transform, String commandPrefix) {
|
||||
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) {
|
||||
paginate(consumer, asList(elems), pre, transform, commandPrefix);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Function<T, ITextComponent> transform, String commandPrefix) {
|
||||
paginate(consumer, pagi, null, transform, commandPrefix);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Function<T, ITextComponent> transform, String commandPrefix) {
|
||||
paginate(consumer, new Paginator<>(elems), null, transform, commandPrefix);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, T[] elems, Function<T, ITextComponent> transform, String commandPrefix) {
|
||||
paginate(consumer, asList(elems), null, transform, commandPrefix);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Runnable pre, Function<T, ITextComponent> transform) {
|
||||
paginate(consumer, pagi, pre, transform, null);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Runnable pre, Function<T, ITextComponent> transform) {
|
||||
paginate(consumer, new Paginator<>(elems), pre, transform, null);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, T[] elems, Runnable pre, Function<T, ITextComponent> transform) {
|
||||
paginate(consumer, asList(elems), pre, transform, null);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, Paginator<T> pagi, Function<T, ITextComponent> transform) {
|
||||
paginate(consumer, pagi, null, transform, null);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, List<T> elems, Function<T, ITextComponent> transform) {
|
||||
paginate(consumer, new Paginator<>(elems), null, transform, null);
|
||||
}
|
||||
|
||||
public static <T> void paginate(ArgConsumer consumer, T[] elems, Function<T, ITextComponent> transform) {
|
||||
paginate(consumer, asList(elems), null, transform, null);
|
||||
}
|
||||
}
|
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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.execution.CommandExecution;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.manager.CommandManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.Arrays;
|
||||
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 CommandManager#tabComplete(CommandExecution)} or {@link ArgConsumer#tabCompleteDatatype(Class)})</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 = Arrays.stream(base);
|
||||
}
|
||||
|
||||
public TabCompleteHelper(List<String> base) {
|
||||
stream = base.stream();
|
||||
}
|
||||
|
||||
public TabCompleteHelper() {
|
||||
this(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @see #prepend(Stream)
|
||||
* @see #prepend(String...)
|
||||
* @see #prepend(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)
|
||||
* @see #prepend(Stream)
|
||||
* @see #prepend(String...)
|
||||
* @see #prepend(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...)
|
||||
* @see #prepend(Stream)
|
||||
* @see #prepend(String...)
|
||||
* @see #prepend(Class)
|
||||
*/
|
||||
public TabCompleteHelper append(Class<? extends Enum<?>> num) {
|
||||
return append(
|
||||
Arrays.stream(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 #append(Stream)
|
||||
* @see #append(String...)
|
||||
* @see #append(Class)
|
||||
* @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 #append(Stream)
|
||||
* @see #append(String...)
|
||||
* @see #append(Class)
|
||||
* @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 #append(Stream)
|
||||
* @see #append(String...)
|
||||
* @see #append(Class)
|
||||
* @see #prepend(Stream)
|
||||
* @see #prepend(String...)
|
||||
*/
|
||||
public TabCompleteHelper prepend(Class<? extends Enum<?>> num) {
|
||||
return prepend(
|
||||
Arrays.stream(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 {@link CommandManager#REGISTRY} to this {@link TabCompleteHelper}
|
||||
*
|
||||
* @return This {@link TabCompleteHelper}
|
||||
*/
|
||||
public TabCompleteHelper addCommands() {
|
||||
return append(
|
||||
CommandManager.REGISTRY.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,88 @@
|
||||
/*
|
||||
* 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.utils.command.Command;
|
||||
import baritone.api.utils.command.argument.CommandArgument;
|
||||
import baritone.api.utils.command.execution.CommandExecution;
|
||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||
import baritone.api.utils.command.registry.Registry;
|
||||
import com.mojang.realmsclient.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class CommandManager {
|
||||
public static final Registry<Command> REGISTRY = new Registry<>();
|
||||
|
||||
/**
|
||||
* @param name The command name to search for.
|
||||
* @return The command, if found.
|
||||
*/
|
||||
public static Command getCommand(String name) {
|
||||
for (Command command : REGISTRY.entries) {
|
||||
if (command.names.contains(name.toLowerCase(Locale.US))) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void execute(CommandExecution execution) {
|
||||
execution.execute();
|
||||
}
|
||||
|
||||
public static boolean execute(String string) {
|
||||
CommandExecution execution = CommandExecution.from(string);
|
||||
|
||||
if (nonNull(execution)) {
|
||||
execution.execute();
|
||||
}
|
||||
|
||||
return nonNull(execution);
|
||||
}
|
||||
|
||||
public static Stream<String> tabComplete(CommandExecution execution) {
|
||||
return execution.tabComplete();
|
||||
}
|
||||
|
||||
public static Stream<String> tabComplete(Pair<String, List<CommandArgument>> pair) {
|
||||
CommandExecution execution = CommandExecution.from(pair);
|
||||
return isNull(execution) ? Stream.empty() : tabComplete(execution);
|
||||
}
|
||||
|
||||
public static Stream<String> tabComplete(String prefix) {
|
||||
Pair<String, List<CommandArgument>> pair = CommandExecution.expand(prefix, true);
|
||||
String label = pair.first();
|
||||
List<CommandArgument> args = pair.second();
|
||||
|
||||
if (args.isEmpty()) {
|
||||
return new TabCompleteHelper()
|
||||
.addCommands()
|
||||
.filterPrefix(label)
|
||||
.stream();
|
||||
} else {
|
||||
return tabComplete(pair);
|
||||
}
|
||||
}
|
||||
}
|
140
src/api/java/baritone/api/utils/command/registry/Registry.java
Normal file
140
src/api/java/baritone/api/utils/command/registry/Registry.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "UnusedReturnValue"})
|
||||
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);
|
||||
}
|
||||
}
|
90
src/launch/java/baritone/launch/mixins/MixinBitArray.java
Normal file
90
src/launch/java/baritone/launch/mixins/MixinBitArray.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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,62 @@
|
||||
/*
|
||||
* 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,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.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();
|
||||
}
|
||||
}
|
||||
}
|
44
src/launch/java/baritone/launch/mixins/MixinGuiChat.java
Normal file
44
src/launch/java/baritone/launch/mixins/MixinGuiChat.java
Normal file
@@ -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.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();
|
||||
}
|
||||
}
|
||||
}
|
32
src/launch/java/baritone/launch/mixins/MixinGuiScreen.java
Normal file
32
src/launch/java/baritone/launch/mixins/MixinGuiScreen.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
67
src/launch/java/baritone/launch/mixins/MixinItemStack.java
Normal file
67
src/launch/java/baritone/launch/mixins/MixinItemStack.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@@ -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 com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
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(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;
|
||||
}
|
||||
}
|
132
src/launch/java/baritone/launch/mixins/MixinTabCompleter.java
Normal file
132
src/launch/java/baritone/launch/mixins/MixinTabCompleter.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.Minecraft;
|
||||
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;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
@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 (isNull(baritone)) {
|
||||
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": [
|
||||
"MixinAnvilChunkLoader",
|
||||
"MixinBitArray",
|
||||
"MixinBlockStateContainer",
|
||||
"MixinChatTabCompleter",
|
||||
"MixinChunkProviderClient",
|
||||
"MixinChunkProviderServer",
|
||||
"MixinChunkRenderContainer",
|
||||
@@ -16,12 +19,17 @@
|
||||
"MixinEntityLivingBase",
|
||||
"MixinEntityPlayerSP",
|
||||
"MixinEntityRenderer",
|
||||
"MixinGuiChat",
|
||||
"MixinGuiScreen",
|
||||
"MixinItemStack",
|
||||
"MixinMinecraft",
|
||||
"MixinNetHandlerPlayClient",
|
||||
"MixinNetworkManager",
|
||||
"MixinPlayerControllerMP",
|
||||
"MixinRenderChunk",
|
||||
"MixinRenderList",
|
||||
"MixinStateImplementation",
|
||||
"MixinTabCompleter",
|
||||
"MixinVboRenderList",
|
||||
"MixinWorldClient"
|
||||
]
|
||||
|
@@ -21,14 +21,17 @@ import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.utils.ExampleBaritoneControl;
|
||||
import baritone.api.utils.command.BaritoneChatControl;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.command.manager.CommandManager;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
import baritone.event.GameEventHandler;
|
||||
import baritone.process.*;
|
||||
import baritone.selection.SelectionManager;
|
||||
import baritone.utils.*;
|
||||
import baritone.utils.command.defaults.DefaultCommands;
|
||||
import baritone.utils.player.PrimaryPlayerContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
@@ -83,6 +86,7 @@ public class Baritone implements IBaritone {
|
||||
private FarmProcess farmProcess;
|
||||
|
||||
private PathingControlManager pathingControlManager;
|
||||
private SelectionManager selectionManager;
|
||||
|
||||
private IPlayerContext playerContext;
|
||||
private WorldProvider worldProvider;
|
||||
@@ -109,7 +113,6 @@ public class Baritone implements IBaritone {
|
||||
memoryBehavior = new MemoryBehavior(this);
|
||||
inventoryBehavior = new InventoryBehavior(this);
|
||||
inputOverrideHandler = new InputOverrideHandler(this);
|
||||
new ExampleBaritoneControl(this);
|
||||
}
|
||||
|
||||
this.pathingControlManager = new PathingControlManager(this);
|
||||
@@ -125,6 +128,7 @@ public class Baritone implements IBaritone {
|
||||
}
|
||||
|
||||
this.worldProvider = new WorldProvider();
|
||||
this.selectionManager = new SelectionManager();
|
||||
|
||||
if (BaritoneAutoTest.ENABLE_AUTO_TEST) {
|
||||
this.gameEventHandler.registerEventListener(BaritoneAutoTest.INSTANCE);
|
||||
@@ -203,6 +207,11 @@ public class Baritone implements IBaritone {
|
||||
return this.pathingBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectionManager getSelectionManager() {
|
||||
return selectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldProvider getWorldProvider() {
|
||||
return this.worldProvider;
|
||||
|
@@ -20,7 +20,10 @@ package baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.IBaritoneProvider;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.utils.command.BaritoneChatControl;
|
||||
import baritone.api.utils.command.manager.CommandManager;
|
||||
import baritone.cache.WorldScanner;
|
||||
import baritone.utils.command.defaults.DefaultCommands;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -34,6 +37,11 @@ public final class BaritoneProvider implements IBaritoneProvider {
|
||||
private final Baritone primary = new Baritone();
|
||||
private final List<IBaritone> all = Collections.singletonList(primary);
|
||||
|
||||
{
|
||||
DefaultCommands.COMMANDS.forEach(CommandManager.REGISTRY::register);
|
||||
new BaritoneChatControl(primary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaritone getPrimaryBaritone() {
|
||||
return primary;
|
||||
|
@@ -28,6 +28,7 @@ import net.minecraft.inventory.ClickType;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.OptionalInt;
|
||||
@@ -132,7 +133,7 @@ public final class InventoryBehavior extends Behavior {
|
||||
}
|
||||
|
||||
public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) {
|
||||
IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z);
|
||||
IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z, baritone.bsi.get0(x, y, z));
|
||||
if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof ItemBlock && maybe.equals(((ItemBlock) stack.getItem()).getBlock().getStateForPlacement(ctx.world(), ctx.playerFeet(), EnumFacing.UP, (float) ctx.player().posX, (float) ctx.player().posY, (float) ctx.player().posZ, stack.getItem().getMetadata(stack.getMetadata()), ctx.player())))) {
|
||||
return true; // gotem
|
||||
}
|
||||
|
@@ -160,7 +160,7 @@ public final class MemoryBehavior extends Behavior {
|
||||
@Override
|
||||
public void onBlockInteract(BlockInteractEvent event) {
|
||||
if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(ctx, event.getPos()) instanceof BlockBed) {
|
||||
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos()));
|
||||
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, BetterBlockPos.from(event.getPos())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,11 @@ package baritone.behavior;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.behavior.IPathingBehavior;
|
||||
import baritone.api.event.events.*;
|
||||
import baritone.api.event.events.PathEvent;
|
||||
import baritone.api.event.events.PlayerUpdateEvent;
|
||||
import baritone.api.event.events.RenderEvent;
|
||||
import baritone.api.event.events.SprintStateEvent;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.api.pathing.calc.IPath;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalXZ;
|
||||
@@ -55,6 +59,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
private boolean safeToCancel;
|
||||
private boolean pauseRequestedLastTick;
|
||||
private boolean unpausedLastTick;
|
||||
private boolean pausedThisTick;
|
||||
private boolean cancelRequested;
|
||||
private boolean calcFailedLastTick;
|
||||
|
||||
@@ -108,6 +113,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
}
|
||||
|
||||
private void tickPath() {
|
||||
pausedThisTick = false;
|
||||
if (pauseRequestedLastTick && safeToCancel) {
|
||||
pauseRequestedLastTick = false;
|
||||
if (unpausedLastTick) {
|
||||
@@ -115,6 +121,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
|
||||
}
|
||||
unpausedLastTick = false;
|
||||
pausedThisTick = true;
|
||||
return;
|
||||
}
|
||||
unpausedLastTick = true;
|
||||
@@ -130,8 +137,8 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
BetterBlockPos calcFrom = inProgress.getStart();
|
||||
Optional<IPath> currentBest = inProgress.bestPathSoFar();
|
||||
if ((current == null || !current.getPath().getDest().equals(calcFrom)) // if current ends in inProgress's start, then we're ok
|
||||
&& !calcFrom.equals(ctx.playerFeet()) && !calcFrom.equals(expectedSegmentStart) // if current starts in our playerFeet or pathStart, then we're ok
|
||||
&& (!currentBest.isPresent() || (!currentBest.get().positions().contains(ctx.playerFeet()) && !currentBest.get().positions().contains(expectedSegmentStart))) // if
|
||||
&& !calcFrom.equals(ctx.playerFeet()) && !calcFrom.equals(expectedSegmentStart) // if current starts in our playerFeet or pathStart, then we're ok
|
||||
&& (!currentBest.isPresent() || (!currentBest.get().positions().contains(ctx.playerFeet()) && !currentBest.get().positions().contains(expectedSegmentStart))) // if
|
||||
) {
|
||||
// when it was *just* started, currentBest will be empty so we need to also check calcFrom since that's always present
|
||||
inProgress.cancel(); // cancellation doesn't dispatch any events
|
||||
@@ -279,6 +286,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
return goal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPathing() {
|
||||
return hasPath() && !pausedThisTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathExecutor getCurrent() {
|
||||
return current;
|
||||
|
@@ -20,6 +20,7 @@ package baritone.cache;
|
||||
import baritone.api.cache.IWaypoint;
|
||||
import baritone.api.cache.IWaypointCollection;
|
||||
import baritone.api.cache.Waypoint;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.io.*;
|
||||
@@ -86,7 +87,7 @@ public class WaypointCollection implements IWaypointCollection {
|
||||
int x = in.readInt();
|
||||
int y = in.readInt();
|
||||
int z = in.readInt();
|
||||
this.waypoints.get(tag).add(new Waypoint(name, tag, new BlockPos(x, y, z), creationTimestamp));
|
||||
this.waypoints.get(tag).add(new Waypoint(name, tag, new BetterBlockPos(x, y, z), creationTimestamp));
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
98
src/main/java/baritone/cache/WorldScanner.java
vendored
98
src/main/java/baritone/cache/WorldScanner.java
vendored
@@ -17,20 +17,29 @@
|
||||
|
||||
package baritone.cache;
|
||||
|
||||
import baritone.api.cache.ICachedWorld;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import net.minecraft.block.Block;
|
||||
import baritone.utils.accessor.IBlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.multiplayer.ChunkProviderClient;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.chunk.BlockStateContainer;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public enum WorldScanner implements IWorldScanner {
|
||||
|
||||
INSTANCE;
|
||||
@@ -38,14 +47,13 @@ public enum WorldScanner implements IWorldScanner {
|
||||
private static final int[] DEFAULT_COORDINATE_ITERATION_ORDER = IntStream.range(0, 16).toArray();
|
||||
|
||||
@Override
|
||||
public List<BlockPos> scanChunkRadius(IPlayerContext ctx, List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius) {
|
||||
if (blocks.contains(null)) {
|
||||
throw new IllegalStateException("Invalid block name should have been caught earlier: " + blocks.toString());
|
||||
}
|
||||
public List<BlockPos> scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius) {
|
||||
ArrayList<BlockPos> res = new ArrayList<>();
|
||||
if (blocks.isEmpty()) {
|
||||
|
||||
if (filter.blocks().isEmpty()) {
|
||||
return res;
|
||||
}
|
||||
|
||||
ChunkProviderClient chunkProvider = (ChunkProviderClient) ctx.world().getChunkProvider();
|
||||
|
||||
int maxSearchRadiusSq = maxSearchRadius * maxSearchRadius;
|
||||
@@ -75,14 +83,14 @@ public enum WorldScanner implements IWorldScanner {
|
||||
continue;
|
||||
}
|
||||
allUnloaded = false;
|
||||
if (scanChunkInto(chunkX << 4, chunkZ << 4, chunk, blocks, res, max, yLevelThreshold, playerY, coordinateIterationOrder)) {
|
||||
if (scanChunkInto(chunkX << 4, chunkZ << 4, chunk, filter, res, max, yLevelThreshold, playerY, coordinateIterationOrder)) {
|
||||
foundWithinY = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((allUnloaded && foundChunks)
|
||||
|| (res.size() >= max
|
||||
&& (searchRadiusSq > maxSearchRadiusSq || (searchRadiusSq > 1 && foundWithinY)))
|
||||
|| (res.size() >= max
|
||||
&& (searchRadiusSq > maxSearchRadiusSq || (searchRadiusSq > 1 && foundWithinY)))
|
||||
) {
|
||||
return res;
|
||||
}
|
||||
@@ -91,8 +99,8 @@ public enum WorldScanner implements IWorldScanner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold) {
|
||||
if (blocks.isEmpty()) {
|
||||
public List<BlockPos> scanChunk(IPlayerContext ctx, BlockOptionalMetaLookup filter, ChunkPos pos, int max, int yLevelThreshold) {
|
||||
if (filter.blocks().isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -105,11 +113,11 @@ public enum WorldScanner implements IWorldScanner {
|
||||
}
|
||||
|
||||
ArrayList<BlockPos> res = new ArrayList<>();
|
||||
scanChunkInto(pos.x << 4, pos.z << 4, chunk, blocks, res, max, yLevelThreshold, playerY, DEFAULT_COORDINATE_ITERATION_ORDER);
|
||||
scanChunkInto(pos.x << 4, pos.z << 4, chunk, filter, res, max, yLevelThreshold, playerY, DEFAULT_COORDINATE_ITERATION_ORDER);
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean scanChunkInto(int chunkX, int chunkZ, Chunk chunk, List<Block> search, Collection<BlockPos> result, int max, int yLevelThreshold, int playerY, int[] coordinateIterationOrder) {
|
||||
private boolean scanChunkInto(int chunkX, int chunkZ, Chunk chunk, BlockOptionalMetaLookup filter, Collection<BlockPos> result, int max, int yLevelThreshold, int playerY, int[] coordinateIterationOrder) {
|
||||
ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
|
||||
boolean foundWithinY = false;
|
||||
for (int yIndex = 0; yIndex < 16; yIndex++) {
|
||||
@@ -119,32 +127,52 @@ public enum WorldScanner implements IWorldScanner {
|
||||
continue;
|
||||
}
|
||||
int yReal = y0 << 4;
|
||||
BlockStateContainer bsc = extendedblockstorage.getData();
|
||||
// the mapping of BlockStateContainer.getIndex from xyz to index is y << 8 | z << 4 | x;
|
||||
// for better cache locality, iterate in that order
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
IBlockState state = bsc.get(x, y, z);
|
||||
if (search.contains(state.getBlock())) {
|
||||
int yy = yReal | y;
|
||||
if (result.size() >= max) {
|
||||
if (Math.abs(yy - playerY) < yLevelThreshold) {
|
||||
foundWithinY = true;
|
||||
} else {
|
||||
if (foundWithinY) {
|
||||
// have found within Y in this chunk, so don't need to consider outside Y
|
||||
// TODO continue iteration to one more sorted Y coordinate block
|
||||
return true;
|
||||
}
|
||||
}
|
||||
IBlockStateContainer bsc = (IBlockStateContainer) extendedblockstorage.getData();
|
||||
// storageArray uses an optimized algorithm that's faster than getAt
|
||||
// creating this array and then using getAtPalette is faster than even getFast(int index)
|
||||
int[] storage = bsc.storageArray();
|
||||
final int imax = 1 << 12;
|
||||
for (int i = 0; i < imax; i++) {
|
||||
IBlockState state = bsc.getAtPalette(storage[i]);
|
||||
if (filter.has(state)) {
|
||||
int y = yReal | ((i >> 8) & 15);
|
||||
if (result.size() >= max) {
|
||||
if (Math.abs(y - playerY) < yLevelThreshold) {
|
||||
foundWithinY = true;
|
||||
} else {
|
||||
if (foundWithinY) {
|
||||
// have found within Y in this chunk, so don't need to consider outside Y
|
||||
// TODO continue iteration to one more sorted Y coordinate block
|
||||
return true;
|
||||
}
|
||||
result.add(new BlockPos(chunkX | x, yy, chunkZ | z));
|
||||
}
|
||||
}
|
||||
result.add(new BlockPos(chunkX | (i & 15), y, chunkZ | ((i >> 4) & 15)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundWithinY;
|
||||
}
|
||||
|
||||
public int repack(IPlayerContext ctx) {
|
||||
IChunkProvider chunkProvider = ctx.world().getChunkProvider();
|
||||
ICachedWorld cachedWorld = ctx.worldData().getCachedWorld();
|
||||
|
||||
BetterBlockPos playerPos = ctx.playerFeet();
|
||||
int playerChunkX = playerPos.getX() >> 4;
|
||||
int playerChunkZ = playerPos.getZ() >> 4;
|
||||
int queued = 0;
|
||||
for (int x = playerChunkX - 40; x <= playerChunkX + 40; x++) {
|
||||
for (int z = playerChunkZ - 40; z <= playerChunkZ + 40; z++) {
|
||||
Chunk chunk = chunkProvider.getLoadedChunk(x, z);
|
||||
|
||||
if (nonNull(chunk) && !chunk.isEmpty()) {
|
||||
queued++;
|
||||
cachedWorld.queueForPacking(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queued;
|
||||
}
|
||||
}
|
||||
|
@@ -69,6 +69,16 @@ public final class GameEventHandler implements IEventBus, Helper {
|
||||
listeners.forEach(l -> l.onSendChatMessage(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreTabComplete(TabCompleteEvent.Pre event) {
|
||||
listeners.forEach(l -> l.onPreTabComplete(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTabComplete(TabCompleteEvent.Post event) {
|
||||
listeners.forEach(l -> l.onPostTabComplete(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onChunkEvent(ChunkEvent event) {
|
||||
EventState state = event.getState();
|
||||
|
@@ -177,7 +177,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
return block.isPassable(null, null);
|
||||
}
|
||||
|
||||
static boolean isReplacable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
|
||||
static boolean isReplaceable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
|
||||
// for MovementTraverse and MovementAscend
|
||||
// block double plant defaults to true when the block doesn't match, so don't need to check that case
|
||||
// all other overrides just return true or false
|
||||
@@ -207,6 +207,11 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
return state.getMaterial().isReplaceable();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
static boolean isReplacable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
|
||||
return isReplaceable(x, y, z, state, bsi);
|
||||
}
|
||||
|
||||
static boolean isDoorPassable(IPlayerContext ctx, BlockPos doorPos, BlockPos playerPos) {
|
||||
if (playerPos.equals(doorPos)) {
|
||||
return false;
|
||||
|
@@ -73,7 +73,7 @@ public class MovementAscend extends Movement {
|
||||
if (additionalPlacementCost >= COST_INF) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (!MovementHelper.isReplacable(destX, y, destZ, toPlace, context.bsi)) {
|
||||
if (!MovementHelper.isReplaceable(destX, y, destZ, toPlace, context.bsi)) {
|
||||
return COST_INF;
|
||||
}
|
||||
boolean foundPlaceOption = false;
|
||||
|
@@ -152,7 +152,7 @@ public class MovementParkour extends Movement {
|
||||
return;
|
||||
}
|
||||
IBlockState toReplace = context.get(destX, y - 1, destZ);
|
||||
if (!MovementHelper.isReplacable(destX, y - 1, destZ, toReplace, context.bsi)) {
|
||||
if (!MovementHelper.isReplaceable(destX, y - 1, destZ, toReplace, context.bsi)) {
|
||||
return;
|
||||
}
|
||||
if (!checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) {
|
||||
|
@@ -111,7 +111,7 @@ public class MovementTraverse extends Movement {
|
||||
if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (MovementHelper.isReplacable(destX, y - 1, destZ, destOn, context.bsi)) {
|
||||
if (MovementHelper.isReplaceable(destX, y - 1, destZ, destOn, context.bsi)) {
|
||||
boolean throughWater = MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock());
|
||||
if (MovementHelper.isWater(destOn.getBlock()) && throughWater) {
|
||||
// this happens when assume walk on water is true and this is a traverse in water, which isn't allowed
|
||||
|
@@ -33,7 +33,7 @@ import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.schematic.AirSchematic;
|
||||
import baritone.utils.schematic.FillSchematic;
|
||||
import baritone.utils.schematic.MapArtSchematic;
|
||||
import baritone.utils.schematic.Schematic;
|
||||
import baritone.utils.schematic.schematica.SchematicaHelper;
|
||||
@@ -58,7 +58,6 @@ import java.util.*;
|
||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
|
||||
public final class BuilderProcess extends BaritoneProcessHelper implements IBuilderProcess {
|
||||
|
||||
private HashSet<BetterBlockPos> incorrectPositions;
|
||||
private LongOpenHashSet observedCompleted; // positions that are completed even if they're out of render distance and we can't make sure right now
|
||||
private String name;
|
||||
@@ -68,6 +67,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
private int ticks;
|
||||
private boolean paused;
|
||||
private int layer;
|
||||
private List<IBlockState> approxPlaceable;
|
||||
|
||||
public BuilderProcess(Baritone baritone) {
|
||||
super(baritone);
|
||||
@@ -104,6 +104,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
paused = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean build(String name, File schematic, Vec3i origin) {
|
||||
NBTTagCompound tag;
|
||||
@@ -113,6 +118,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
//noinspection ConstantConditions
|
||||
if (tag == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -139,7 +145,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
int widthX = Math.abs(corner1.getX() - corner2.getX()) + 1;
|
||||
int heightY = Math.abs(corner1.getY() - corner2.getY()) + 1;
|
||||
int lengthZ = Math.abs(corner1.getZ() - corner2.getZ()) + 1;
|
||||
build("clear area", new AirSchematic(widthX, heightY, lengthZ), origin);
|
||||
build("clear area", new FillSchematic(widthX, heightY, lengthZ, Blocks.AIR.getDefaultState()), origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBlockState> getApproxPlaceable() {
|
||||
return new ArrayList<>(approxPlaceable);
|
||||
}
|
||||
|
||||
private static ISchematic parse(NBTTagCompound schematic) {
|
||||
@@ -151,14 +162,14 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
return schematic != null;
|
||||
}
|
||||
|
||||
public IBlockState placeAt(int x, int y, int z) {
|
||||
public IBlockState placeAt(int x, int y, int z, IBlockState current) {
|
||||
if (!isActive()) {
|
||||
return null;
|
||||
}
|
||||
if (!schematic.inSchematic(x - origin.getX(), y - origin.getY(), z - origin.getZ())) {
|
||||
if (!schematic.inSchematic(x - origin.getX(), y - origin.getY(), z - origin.getZ(), current)) {
|
||||
return null;
|
||||
}
|
||||
IBlockState state = schematic.desiredState(x - origin.getX(), y - origin.getY(), z - origin.getZ());
|
||||
IBlockState state = schematic.desiredState(x - origin.getX(), y - origin.getY(), z - origin.getZ(), current, this.approxPlaceable);
|
||||
if (state.getBlock() == Blocks.AIR) {
|
||||
return null;
|
||||
}
|
||||
@@ -177,7 +188,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
if (dy == -1 && x == pathStart.x && z == pathStart.z) {
|
||||
continue; // dont mine what we're supported by, but not directly standing on
|
||||
}
|
||||
IBlockState desired = bcc.getSchematic(x, y, z);
|
||||
IBlockState desired = bcc.getSchematic(x, y, z, bcc.bsi.get0(x, y, z));
|
||||
if (desired == null) {
|
||||
continue; // irrelevant
|
||||
}
|
||||
@@ -195,7 +206,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public class Placement {
|
||||
public static class Placement {
|
||||
private final int hotbarSelection;
|
||||
private final BlockPos placeAgainst;
|
||||
private final EnumFacing side;
|
||||
@@ -209,7 +220,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Placement> searchForPlacables(BuilderCalculationContext bcc, List<IBlockState> desirableOnHotbar) {
|
||||
private Optional<Placement> searchForPlaceables(BuilderCalculationContext bcc, List<IBlockState> desirableOnHotbar) {
|
||||
BetterBlockPos center = ctx.playerFeet();
|
||||
for (int dx = -5; dx <= 5; dx++) {
|
||||
for (int dy = -5; dy <= 1; dy++) {
|
||||
@@ -217,12 +228,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
int x = center.x + dx;
|
||||
int y = center.y + dy;
|
||||
int z = center.z + dz;
|
||||
IBlockState desired = bcc.getSchematic(x, y, z);
|
||||
IBlockState desired = bcc.getSchematic(x, y, z, bcc.bsi.get0(x, y, z));
|
||||
if (desired == null) {
|
||||
continue; // irrelevant
|
||||
}
|
||||
IBlockState curr = bcc.bsi.get0(x, y, z);
|
||||
if (MovementHelper.isReplacable(x, y, z, curr, bcc.bsi) && !valid(curr, desired)) {
|
||||
if (MovementHelper.isReplaceable(x, y, z, curr, bcc.bsi) && !valid(curr, desired)) {
|
||||
if (dy == 1 && bcc.bsi.get0(x, y + 1, z).getBlock() == Blocks.AIR) {
|
||||
continue;
|
||||
}
|
||||
@@ -242,7 +253,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
for (EnumFacing against : EnumFacing.values()) {
|
||||
BetterBlockPos placeAgainstPos = new BetterBlockPos(x, y, z).offset(against);
|
||||
IBlockState placeAgainstState = bsi.get0(placeAgainstPos);
|
||||
if (MovementHelper.isReplacable(placeAgainstPos.x, placeAgainstPos.y, placeAgainstPos.z, placeAgainstState, bsi)) {
|
||||
if (MovementHelper.isReplaceable(placeAgainstPos.x, placeAgainstPos.y, placeAgainstPos.z, placeAgainstState, bsi)) {
|
||||
continue;
|
||||
}
|
||||
if (!ctx.world().mayPlace(toPlace.getBlock(), new BetterBlockPos(x, y, z), false, against, null)) {
|
||||
@@ -316,6 +327,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
approxPlaceable = approxPlaceable(36);
|
||||
if (baritone.getInputOverrideHandler().isInputForcedDown(Input.CLICK_LEFT)) {
|
||||
ticks = 5;
|
||||
} else {
|
||||
@@ -343,13 +355,13 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
}
|
||||
schematic = new ISchematic() {
|
||||
@Override
|
||||
public IBlockState desiredState(int x, int y, int z) {
|
||||
return realSchematic.desiredState(x, y, z);
|
||||
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
||||
return realSchematic.desiredState(x, y, z, current, BuilderProcess.this.approxPlaceable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inSchematic(int x, int y, int z) {
|
||||
return ISchematic.super.inSchematic(x, y, z) && y >= minYInclusive && y <= maxYInclusive;
|
||||
public boolean inSchematic(int x, int y, int z, IBlockState currentState) {
|
||||
return ISchematic.super.inSchematic(x, y, z, currentState) && y >= minYInclusive && y <= maxYInclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -411,7 +423,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
List<IBlockState> desirableOnHotbar = new ArrayList<>();
|
||||
Optional<Placement> toPlace = searchForPlacables(bcc, desirableOnHotbar);
|
||||
Optional<Placement> toPlace = searchForPlaceables(bcc, desirableOnHotbar);
|
||||
if (toPlace.isPresent() && isSafeToCancel && ctx.player().onGround && ticks <= 0) {
|
||||
Rotation rot = toPlace.get().rot;
|
||||
baritone.getLookBehavior().updateTarget(rot, true);
|
||||
@@ -423,14 +435,13 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
List<IBlockState> approxPlacable = placable(36);
|
||||
if (Baritone.settings().allowInventory.value) {
|
||||
ArrayList<Integer> usefulSlots = new ArrayList<>();
|
||||
List<IBlockState> noValidHotbarOption = new ArrayList<>();
|
||||
outer:
|
||||
for (IBlockState desired : desirableOnHotbar) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (valid(approxPlacable.get(i), desired)) {
|
||||
if (valid(approxPlaceable.get(i), desired)) {
|
||||
usefulSlots.add(i);
|
||||
continue outer;
|
||||
}
|
||||
@@ -441,7 +452,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
outer:
|
||||
for (int i = 9; i < 36; i++) {
|
||||
for (IBlockState desired : noValidHotbarOption) {
|
||||
if (valid(approxPlacable.get(i), desired)) {
|
||||
if (valid(approxPlaceable.get(i), desired)) {
|
||||
baritone.getInventoryBehavior().attemptToPutOnHotbar(i, usefulSlots::contains);
|
||||
break outer;
|
||||
}
|
||||
@@ -449,9 +460,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
}
|
||||
}
|
||||
|
||||
Goal goal = assemble(bcc, approxPlacable.subList(0, 9));
|
||||
Goal goal = assemble(bcc, approxPlaceable.subList(0, 9));
|
||||
if (goal == null) {
|
||||
goal = assemble(bcc, approxPlacable); // we're far away, so assume that we have our whole inventory to recalculate placable properly
|
||||
goal = assemble(bcc, approxPlaceable); // we're far away, so assume that we have our whole inventory to recalculate placeable properly
|
||||
if (goal == null) {
|
||||
logDirect("Unable to do it. Pausing. resume to resume, cancel to cancel");
|
||||
paused = true;
|
||||
@@ -493,7 +504,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
int x = center.x + dx;
|
||||
int y = center.y + dy;
|
||||
int z = center.z + dz;
|
||||
IBlockState desired = bcc.getSchematic(x, y, z);
|
||||
IBlockState desired = bcc.getSchematic(x, y, z, bcc.bsi.get0(x, y, z));
|
||||
if (desired != null) {
|
||||
// we care about this position
|
||||
BetterBlockPos pos = new BetterBlockPos(x, y, z);
|
||||
@@ -515,15 +526,16 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
for (int y = 0; y < schematic.heightY(); y++) {
|
||||
for (int z = 0; z < schematic.lengthZ(); z++) {
|
||||
for (int x = 0; x < schematic.widthX(); x++) {
|
||||
if (!schematic.inSchematic(x, y, z)) {
|
||||
continue;
|
||||
}
|
||||
int blockX = x + origin.getX();
|
||||
int blockY = y + origin.getY();
|
||||
int blockZ = z + origin.getZ();
|
||||
IBlockState current = bcc.bsi.get0(blockX, blockY, blockZ);
|
||||
if (!schematic.inSchematic(x, y, z, current)) {
|
||||
continue;
|
||||
}
|
||||
if (bcc.bsi.worldContainsLoadedChunk(blockX, blockZ)) { // check if its in render distance, not if its in cache
|
||||
// we can directly observe this block, it is in render distance
|
||||
if (valid(bcc.bsi.get0(blockX, blockY, blockZ), schematic.desiredState(x, y, z))) {
|
||||
if (valid(bcc.bsi.get0(blockX, blockY, blockZ), schematic.desiredState(x, y, z, current, this.approxPlaceable))) {
|
||||
observedCompleted.add(BetterBlockPos.longHash(blockX, blockY, blockZ));
|
||||
} else {
|
||||
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
|
||||
@@ -548,15 +560,15 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
}
|
||||
}
|
||||
|
||||
private Goal assemble(BuilderCalculationContext bcc, List<IBlockState> approxPlacable) {
|
||||
List<BetterBlockPos> placable = new ArrayList<>();
|
||||
private Goal assemble(BuilderCalculationContext bcc, List<IBlockState> approxPlaceable) {
|
||||
List<BetterBlockPos> placeable = new ArrayList<>();
|
||||
List<BetterBlockPos> breakable = new ArrayList<>();
|
||||
List<BetterBlockPos> sourceLiquids = new ArrayList<>();
|
||||
incorrectPositions.forEach(pos -> {
|
||||
IBlockState state = bcc.bsi.get0(pos);
|
||||
if (state.getBlock() instanceof BlockAir) {
|
||||
if (approxPlacable.contains(bcc.getSchematic(pos.x, pos.y, pos.z))) {
|
||||
placable.add(pos);
|
||||
if (approxPlaceable.contains(bcc.getSchematic(pos.x, pos.y, pos.z, state))) {
|
||||
placeable.add(pos);
|
||||
}
|
||||
} else {
|
||||
if (state.getBlock() instanceof BlockLiquid) {
|
||||
@@ -574,8 +586,8 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
List<Goal> toBreak = new ArrayList<>();
|
||||
breakable.forEach(pos -> toBreak.add(breakGoal(pos, bcc)));
|
||||
List<Goal> toPlace = new ArrayList<>();
|
||||
placable.forEach(pos -> {
|
||||
if (!placable.contains(pos.down()) && !placable.contains(pos.down(2))) {
|
||||
placeable.forEach(pos -> {
|
||||
if (!placeable.contains(pos.down()) && !placeable.contains(pos.down(2))) {
|
||||
toPlace.add(placementGoal(pos, bcc));
|
||||
}
|
||||
});
|
||||
@@ -638,8 +650,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
return new GoalPlace(pos);
|
||||
}
|
||||
boolean allowSameLevel = ctx.world().getBlockState(pos.up()).getBlock() != Blocks.AIR;
|
||||
IBlockState current = ctx.world().getBlockState(pos);
|
||||
for (EnumFacing facing : Movement.HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP) {
|
||||
if (MovementHelper.canPlaceAgainst(ctx, pos.offset(facing)) && ctx.world().mayPlace(bcc.getSchematic(pos.getX(), pos.getY(), pos.getZ()).getBlock(), pos, false, facing, null)) {
|
||||
//noinspection ConstantConditions
|
||||
if (MovementHelper.canPlaceAgainst(ctx, pos.offset(facing)) && ctx.world().mayPlace(bcc.getSchematic(pos.getX(), pos.getY(), pos.getZ(), current).getBlock(), pos, false, facing, null)) {
|
||||
return new GoalAdjacent(pos, pos.offset(facing), allowSameLevel);
|
||||
}
|
||||
}
|
||||
@@ -720,7 +734,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
return paused ? "Builder Paused" : "Building " + name;
|
||||
}
|
||||
|
||||
private List<IBlockState> placable(int size) {
|
||||
private List<IBlockState> approxPlaceable(int size) {
|
||||
List<IBlockState> result = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
ItemStack stack = ctx.player().inventory.mainInventory.get(i);
|
||||
@@ -744,7 +758,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
}
|
||||
|
||||
public class BuilderCalculationContext extends CalculationContext {
|
||||
private final List<IBlockState> placable;
|
||||
private final List<IBlockState> placeable;
|
||||
private final ISchematic schematic;
|
||||
private final int originX;
|
||||
private final int originY;
|
||||
@@ -752,7 +766,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
|
||||
public BuilderCalculationContext() {
|
||||
super(BuilderProcess.this.baritone, true); // wew lad
|
||||
this.placable = placable(9);
|
||||
this.placeable = approxPlaceable(9);
|
||||
this.schematic = BuilderProcess.this.schematic;
|
||||
this.originX = origin.getX();
|
||||
this.originY = origin.getY();
|
||||
@@ -762,9 +776,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
this.backtrackCostFavoringCoefficient = 1;
|
||||
}
|
||||
|
||||
private IBlockState getSchematic(int x, int y, int z) {
|
||||
if (schematic.inSchematic(x - originX, y - originY, z - originZ)) {
|
||||
return schematic.desiredState(x - originX, y - originY, z - originZ);
|
||||
private IBlockState getSchematic(int x, int y, int z, IBlockState current) {
|
||||
if (schematic.inSchematic(x - originX, y - originY, z - originZ, current)) {
|
||||
return schematic.desiredState(x - originX, y - originY, z - originZ, current, BuilderProcess.this.approxPlaceable);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -775,7 +789,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
if (isPossiblyProtected(x, y, z) || !worldBorder.canPlaceAt(x, z)) { // make calculation fail properly if we can't build
|
||||
return COST_INF;
|
||||
}
|
||||
IBlockState sch = getSchematic(x, y, z);
|
||||
IBlockState sch = getSchematic(x, y, z, bsi.get0(x, y, z));
|
||||
if (sch != null) {
|
||||
// TODO this can return true even when allowPlace is off.... is that an issue?
|
||||
if (sch.getBlock() == Blocks.AIR) {
|
||||
@@ -783,7 +797,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
// this won't be a schematic block, this will be a throwaway
|
||||
return placeBlockCost * 2; // we're going to have to break it eventually
|
||||
}
|
||||
if (placable.contains(sch)) {
|
||||
if (placeable.contains(sch)) {
|
||||
return 0; // thats right we gonna make it FREE to place a block where it should go in a structure
|
||||
// no place block penalty at all 😎
|
||||
// i'm such an idiot that i just tried to copy and paste the epic gamer moment emoji too
|
||||
@@ -809,7 +823,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
if (!allowBreak || isPossiblyProtected(x, y, z)) {
|
||||
return COST_INF;
|
||||
}
|
||||
IBlockState sch = getSchematic(x, y, z);
|
||||
IBlockState sch = getSchematic(x, y, z, bsi.get0(x, y, z));
|
||||
if (sch != null) {
|
||||
if (sch.getBlock() == Blocks.AIR) {
|
||||
// it should be air
|
||||
|
@@ -87,7 +87,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
|
||||
.filter(this::followable)
|
||||
.filter(this.filter)
|
||||
.distinct()
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -22,6 +22,7 @@ import baritone.api.pathing.goals.*;
|
||||
import baritone.api.process.IGetToBlockProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.RotationUtils;
|
||||
import baritone.api.utils.input.Input;
|
||||
@@ -171,7 +172,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG
|
||||
}
|
||||
|
||||
private synchronized void rescan(List<BlockPos> known, CalculationContext context) {
|
||||
List<BlockPos> positions = MineProcess.searchWorld(context, Collections.singletonList(gettingTo), 64, known, blacklist);
|
||||
List<BlockPos> positions = MineProcess.searchWorld(context, new BlockOptionalMetaLookup(gettingTo), 64, known, blacklist);
|
||||
positions.removeIf(blacklist::contains);
|
||||
knownLocations = positions;
|
||||
}
|
||||
|
@@ -22,10 +22,7 @@ import baritone.api.pathing.goals.*;
|
||||
import baritone.api.process.IMineProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.BlockUtils;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.RotationUtils;
|
||||
import baritone.api.utils.*;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.cache.CachedChunk;
|
||||
import baritone.cache.WorldScanner;
|
||||
@@ -40,7 +37,6 @@ import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
@@ -56,10 +52,9 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
* @author leijurv
|
||||
*/
|
||||
public final class MineProcess extends BaritoneProcessHelper implements IMineProcess {
|
||||
|
||||
private static final int ORE_LOCATIONS_COUNT = 64;
|
||||
|
||||
private List<Block> mining;
|
||||
private BlockOptionalMetaLookup filter;
|
||||
private List<BlockPos> knownOreLocations;
|
||||
private List<BlockPos> blacklist; // inaccessible
|
||||
private BlockPos branchPoint;
|
||||
@@ -73,28 +68,29 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return mining != null;
|
||||
return filter != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
if (desiredQuantity > 0) {
|
||||
Item item = mining.get(0).getItemDropped(mining.get(0).getDefaultState(), new Random(), 0);
|
||||
int curr = ctx.player().inventory.mainInventory.stream().filter(stack -> item.equals(stack.getItem())).mapToInt(ItemStack::getCount).sum();
|
||||
System.out.println("Currently have " + curr + " " + item);
|
||||
int curr = ctx.player().inventory.mainInventory.stream()
|
||||
.filter(stack -> filter.has(stack))
|
||||
.mapToInt(ItemStack::getCount).sum();
|
||||
System.out.println("Currently have " + curr + " valid items");
|
||||
if (curr >= desiredQuantity) {
|
||||
logDirect("Have " + curr + " " + item.getItemStackDisplayName(new ItemStack(item, 1)));
|
||||
logDirect("Have " + curr + " valid items");
|
||||
cancel();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (calcFailed) {
|
||||
if (!knownOreLocations.isEmpty() && Baritone.settings().blacklistClosestOnFailure.value) {
|
||||
logDirect("Unable to find any path to " + mining + ", blacklisting presumably unreachable closest instance...");
|
||||
logDirect("Unable to find any path to " + filter + ", blacklisting presumably unreachable closest instance...");
|
||||
knownOreLocations.stream().min(Comparator.comparingDouble(ctx.player()::getDistanceSq)).ifPresent(blacklist::add);
|
||||
knownOreLocations.removeIf(blacklist::contains);
|
||||
} else {
|
||||
logDirect("Unable to find any path to " + mining + ", canceling Mine");
|
||||
logDirect("Unable to find any path to " + filter + ", canceling mine");
|
||||
cancel();
|
||||
return null;
|
||||
}
|
||||
@@ -146,19 +142,19 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
mine(0, (Block[]) null);
|
||||
mine(0, (BlockOptionalMetaLookup) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName0() {
|
||||
return "Mine " + mining;
|
||||
return "Mine " + filter;
|
||||
}
|
||||
|
||||
private PathingCommand updateGoal() {
|
||||
boolean legit = Baritone.settings().legitMine.value;
|
||||
List<BlockPos> locs = knownOreLocations;
|
||||
if (!locs.isEmpty()) {
|
||||
List<BlockPos> locs2 = prune(new CalculationContext(baritone), new ArrayList<>(locs), mining, ORE_LOCATIONS_COUNT, blacklist);
|
||||
List<BlockPos> locs2 = prune(new CalculationContext(baritone), new ArrayList<>(locs), filter, ORE_LOCATIONS_COUNT, blacklist);
|
||||
// can't reassign locs, gotta make a new var locs2, because we use it in a lambda right here, and variables you use in a lambda must be effectively final
|
||||
Goal goal = new GoalComposite(locs2.stream().map(loc -> coalesce(loc, locs2)).toArray(Goal[]::new));
|
||||
knownOreLocations = locs2;
|
||||
@@ -194,16 +190,16 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
}
|
||||
|
||||
private void rescan(List<BlockPos> already, CalculationContext context) {
|
||||
if (mining == null) {
|
||||
if (filter == null) {
|
||||
return;
|
||||
}
|
||||
if (Baritone.settings().legitMine.value) {
|
||||
return;
|
||||
}
|
||||
List<BlockPos> locs = searchWorld(context, mining, ORE_LOCATIONS_COUNT, already, blacklist);
|
||||
locs.addAll(droppedItemsScan(mining, ctx.world()));
|
||||
List<BlockPos> locs = searchWorld(context, filter, ORE_LOCATIONS_COUNT, already, blacklist);
|
||||
locs.addAll(droppedItemsScan(filter, ctx.world()));
|
||||
if (locs.isEmpty()) {
|
||||
logDirect("No locations for " + mining + " known, cancelling");
|
||||
logDirect("No locations for " + filter + " known, cancelling");
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
@@ -215,11 +211,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
if (locs.contains(pos)) {
|
||||
return true;
|
||||
}
|
||||
Block block = BlockStateInterface.getBlock(ctx, pos);
|
||||
if (Baritone.settings().internalMiningAirException.value && block instanceof BlockAir) {
|
||||
IBlockState state = BlockStateInterface.get(ctx, pos);
|
||||
if (Baritone.settings().internalMiningAirException.value && state.getBlock() instanceof BlockAir) {
|
||||
return true;
|
||||
}
|
||||
return mining.contains(block);
|
||||
return filter.has(state);
|
||||
}
|
||||
|
||||
private Goal coalesce(BlockPos loc, List<BlockPos> locs) {
|
||||
@@ -284,22 +280,15 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
}
|
||||
}
|
||||
|
||||
public static List<BlockPos> droppedItemsScan(List<Block> mining, World world) {
|
||||
public static List<BlockPos> droppedItemsScan(BlockOptionalMetaLookup filter, World world) {
|
||||
if (!Baritone.settings().mineScanDroppedItems.value) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Set<Item> searchingFor = new HashSet<>();
|
||||
for (Block block : mining) {
|
||||
Item drop = block.getItemDropped(block.getDefaultState(), new Random(), 0);
|
||||
Item ore = Item.getItemFromBlock(block);
|
||||
searchingFor.add(drop);
|
||||
searchingFor.add(ore);
|
||||
}
|
||||
List<BlockPos> ret = new ArrayList<>();
|
||||
for (Entity entity : world.loadedEntityList) {
|
||||
if (entity instanceof EntityItem) {
|
||||
EntityItem ei = (EntityItem) entity;
|
||||
if (searchingFor.contains(ei.getItem().getItem())) {
|
||||
if (filter.has(ei.getItem())) {
|
||||
ret.add(new BlockPos(entity));
|
||||
}
|
||||
}
|
||||
@@ -307,30 +296,46 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static List<BlockPos> searchWorld(CalculationContext ctx, List<Block> mining, int max, List<BlockPos> alreadyKnown, List<BlockPos> blacklist) {
|
||||
public static List<BlockPos> searchWorld(CalculationContext ctx, BlockOptionalMetaLookup filter, int max, List<BlockPos> alreadyKnown, List<BlockPos> blacklist) {
|
||||
List<BlockPos> locs = new ArrayList<>();
|
||||
List<Block> uninteresting = new ArrayList<>();
|
||||
for (Block m : mining) {
|
||||
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(m)) {
|
||||
List<Block> untracked = new ArrayList<>();
|
||||
for (BlockOptionalMeta bom : filter.blocks()) {
|
||||
Block block = bom.getBlock();
|
||||
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(block)) {
|
||||
BetterBlockPos pf = ctx.baritone.getPlayerContext().playerFeet();
|
||||
|
||||
// maxRegionDistanceSq 2 means adjacent directly or adjacent diagonally; nothing further than that
|
||||
locs.addAll(ctx.worldData.getCachedWorld().getLocationsOf(BlockUtils.blockToString(m), Baritone.settings().maxCachedWorldScanCount.value, ctx.getBaritone().getPlayerContext().playerFeet().getX(), ctx.getBaritone().getPlayerContext().playerFeet().getZ(), 2));
|
||||
locs.addAll(ctx.worldData.getCachedWorld().getLocationsOf(
|
||||
BlockUtils.blockToString(block),
|
||||
Baritone.settings().maxCachedWorldScanCount.value,
|
||||
pf.x,
|
||||
pf.z,
|
||||
2
|
||||
));
|
||||
} else {
|
||||
uninteresting.add(m);
|
||||
untracked.add(block);
|
||||
}
|
||||
}
|
||||
locs = prune(ctx, locs, mining, max, blacklist);
|
||||
if (locs.isEmpty() || (Baritone.settings().extendCacheOnThreshold.value && locs.size() < max)) {
|
||||
uninteresting = mining;
|
||||
}
|
||||
if (!uninteresting.isEmpty()) {
|
||||
locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(ctx.getBaritone().getPlayerContext(), uninteresting, max, 10, 32)); // maxSearchRadius is NOT sq
|
||||
|
||||
locs = prune(ctx, locs, filter, max, blacklist);
|
||||
|
||||
if (!untracked.isEmpty() || (Baritone.settings().extendCacheOnThreshold.value && locs.size() < max)) {
|
||||
locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(
|
||||
ctx.getBaritone().getPlayerContext(),
|
||||
filter,
|
||||
max,
|
||||
10,
|
||||
32
|
||||
)); // maxSearchRadius is NOT sq
|
||||
}
|
||||
|
||||
locs.addAll(alreadyKnown);
|
||||
return prune(ctx, locs, mining, max, blacklist);
|
||||
|
||||
return prune(ctx, locs, filter, max, blacklist);
|
||||
}
|
||||
|
||||
private void addNearby() {
|
||||
knownOreLocations.addAll(droppedItemsScan(mining, ctx.world()));
|
||||
knownOreLocations.addAll(droppedItemsScan(filter, ctx.world()));
|
||||
BlockPos playerFeet = ctx.playerFeet();
|
||||
BlockStateInterface bsi = new BlockStateInterface(ctx);
|
||||
int searchDist = 10;
|
||||
@@ -340,7 +345,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
for (int z = playerFeet.getZ() - searchDist; z <= playerFeet.getZ() + searchDist; z++) {
|
||||
// crucial to only add blocks we can see because otherwise this
|
||||
// is an x-ray and it'll get caught
|
||||
if (mining.contains(bsi.get0(x, y, z).getBlock())) {
|
||||
if (filter.has(bsi.get0(x, y, z))) {
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
if ((Baritone.settings().legitMineIncludeDiagonals.value && knownOreLocations.stream().anyMatch(ore -> ore.distanceSq(pos) <= 2 /* sq means this is pytha dist <= sqrt(2) */)) || RotationUtils.reachable(ctx.player(), pos, fakedBlockReachDistance).isPresent()) {
|
||||
knownOreLocations.add(pos);
|
||||
@@ -349,14 +354,14 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
}
|
||||
}
|
||||
}
|
||||
knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, mining, ORE_LOCATIONS_COUNT, blacklist);
|
||||
knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist);
|
||||
}
|
||||
|
||||
private static List<BlockPos> prune(CalculationContext ctx, List<BlockPos> locs2, List<Block> mining, int max, List<BlockPos> blacklist) {
|
||||
List<BlockPos> dropped = droppedItemsScan(mining, ctx.world);
|
||||
private static List<BlockPos> prune(CalculationContext ctx, List<BlockPos> locs2, BlockOptionalMetaLookup filter, int max, List<BlockPos> blacklist) {
|
||||
List<BlockPos> dropped = droppedItemsScan(filter, ctx.world);
|
||||
dropped.removeIf(drop -> {
|
||||
for (BlockPos pos : locs2) {
|
||||
if (pos.distanceSq(drop) <= 9 && mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx, pos)) { // TODO maybe drop also has to be supported? no lava below?
|
||||
if (pos.distanceSq(drop) <= 9 && filter.has(ctx.get(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx, pos)) { // TODO maybe drop also has to be supported? no lava below?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -367,7 +372,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
.distinct()
|
||||
|
||||
// remove any that are within loaded chunks that aren't actually what we want
|
||||
.filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos))
|
||||
.filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || filter.has(ctx.get(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos))
|
||||
|
||||
// remove any that are implausible to mine (encased in bedrock, or touching lava)
|
||||
.filter(pos -> MineProcess.plausibleToBreak(ctx, pos))
|
||||
@@ -394,22 +399,22 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
|
||||
@Override
|
||||
public void mineByName(int quantity, String... blocks) {
|
||||
mine(quantity, blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(BlockUtils::stringToBlockRequired).toArray(Block[]::new));
|
||||
mine(quantity, new BlockOptionalMetaLookup(blocks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mine(int quantity, Block... blocks) {
|
||||
this.mining = blocks == null || blocks.length == 0 ? null : Arrays.asList(blocks);
|
||||
if (mining != null && !Baritone.settings().allowBreak.value) {
|
||||
public void mine(int quantity, BlockOptionalMetaLookup filter) {
|
||||
this.filter = filter;
|
||||
if (filter != null && !Baritone.settings().allowBreak.value) {
|
||||
logDirect("Unable to mine when allowBreak is false!");
|
||||
mining = null;
|
||||
filter = null;
|
||||
}
|
||||
this.desiredQuantity = quantity;
|
||||
this.knownOreLocations = new ArrayList<>();
|
||||
this.blacklist = new ArrayList<>();
|
||||
this.branchPoint = null;
|
||||
this.branchPointRunaway = null;
|
||||
if (mining != null) {
|
||||
if (filter != null) {
|
||||
rescan(new ArrayList<>(), new CalculationContext(baritone));
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user