diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 71a2d996b..1b39c3cab 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -741,6 +741,12 @@ public final class Settings { */ public final Setting blockFreeLook = new Setting<>(false); + /** + * When true, the player will remain with its existing look direction as often as possible. + * Although, in some cases this can get it stuck, hence this setting to disable that behavior. + */ + public final Setting remainWithExistingLookDirection = new Setting<>(true); + /** * Will cause some minor behavioral differences to ensure that Baritone works on anticheats. *

diff --git a/src/api/java/baritone/api/behavior/ILookBehavior.java b/src/api/java/baritone/api/behavior/ILookBehavior.java index 218e8b59a..d78e7f8b3 100644 --- a/src/api/java/baritone/api/behavior/ILookBehavior.java +++ b/src/api/java/baritone/api/behavior/ILookBehavior.java @@ -17,6 +17,8 @@ package baritone.api.behavior; +import baritone.api.Settings; +import baritone.api.behavior.look.IAimProcessor; import baritone.api.utils.Rotation; /** @@ -27,10 +29,22 @@ public interface ILookBehavior extends IBehavior { /** * Updates the current {@link ILookBehavior} target to target the specified rotations on the next tick. If any sort - * of block interaction is required, {@code blockInteract} should be {@code true}. + * of block interaction is required, {@code blockInteract} should be {@code true}. It is not guaranteed that the + * rotations set by the caller will be the exact rotations expressed by the client (This is due to settings like + * {@link Settings#randomLooking}). If the rotations produced by this behavior are required, then the + * {@link #getAimProcessor() aim processor} should be used. * * @param rotation The target rotations * @param blockInteract Whether the target rotations are needed for a block interaction */ void updateTarget(Rotation rotation, boolean blockInteract); + + /** + * The aim processor instance for this {@link ILookBehavior}, which is responsible for applying additional, + * deterministic transformations to the target rotation set by {@link #updateTarget}. + * + * @return The aim processor + * @see IAimProcessor#fork + */ + IAimProcessor getAimProcessor(); } diff --git a/src/api/java/baritone/api/behavior/look/IAimProcessor.java b/src/api/java/baritone/api/behavior/look/IAimProcessor.java new file mode 100644 index 000000000..c7c60f413 --- /dev/null +++ b/src/api/java/baritone/api/behavior/look/IAimProcessor.java @@ -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 . + */ + +package baritone.api.behavior.look; + +import baritone.api.utils.Rotation; + +/** + * @author Brady + */ +public interface IAimProcessor { + + /** + * Returns the actual rotation that will be used when the desired rotation is requested. The returned rotation + * always reflects what would happen in the upcoming tick. In other words, it is a pure function, and no internal + * state changes. If simulation of the rotation states beyond the next tick is required, then a + * {@link IAimProcessor#fork fork} should be created. + * + * @param desired The desired rotation to set + * @return The actual rotation + */ + Rotation peekRotation(Rotation desired); + + /** + * Returns a copy of this {@link IAimProcessor} which has its own internal state and is manually tickable. + * + * @return The forked processor + * @see ITickableAimProcessor + */ + ITickableAimProcessor fork(); +} diff --git a/src/api/java/baritone/api/behavior/look/ITickableAimProcessor.java b/src/api/java/baritone/api/behavior/look/ITickableAimProcessor.java new file mode 100644 index 000000000..e0a07ae57 --- /dev/null +++ b/src/api/java/baritone/api/behavior/look/ITickableAimProcessor.java @@ -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 . + */ + +package baritone.api.behavior.look; + +import baritone.api.utils.Rotation; + +/** + * @author Brady + */ +public interface ITickableAimProcessor extends IAimProcessor { + + /** + * Advances the internal state of this aim processor by a single tick. + */ + void tick(); + + /** + * Calls {@link #tick()} the specified number of times. + * + * @param ticks The number of calls + */ + void advance(int ticks); + + /** + * Returns the actual rotation as provided by {@link #peekRotation(Rotation)}, and then automatically advances the + * internal state by one {@link #tick() tick}. + * + * @param rotation The desired rotation to set + * @return The actual rotation + */ + Rotation nextRotation(Rotation rotation); +} diff --git a/src/api/java/baritone/api/command/datatypes/BlockById.java b/src/api/java/baritone/api/command/datatypes/BlockById.java index 3702725e3..0efb738ca 100644 --- a/src/api/java/baritone/api/command/datatypes/BlockById.java +++ b/src/api/java/baritone/api/command/datatypes/BlockById.java @@ -23,11 +23,17 @@ import net.minecraft.block.Block; import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation; +import java.util.regex.Pattern; import java.util.stream.Stream; public enum BlockById implements IDatatypeFor { INSTANCE; + /** + * Matches (domain:)?name? where domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ respectively. + */ + private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?[a-z0-9/_.-]*"); + @Override public Block get(IDatatypeContext ctx) throws CommandException { ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString()); @@ -40,13 +46,19 @@ public enum BlockById implements IDatatypeFor { @Override public Stream tabComplete(IDatatypeContext ctx) throws CommandException { + String arg = ctx.getConsumer().getString(); + + if (!PATTERN.matcher(arg).matches()) { + return Stream.empty(); + } + return new TabCompleteHelper() .append( Block.REGISTRY.getKeys() .stream() .map(Object::toString) ) - .filterPrefixNamespaced(ctx.getConsumer().getString()) + .filterPrefixNamespaced(arg) .sortAlphabetically() .stream(); } diff --git a/src/api/java/baritone/api/command/datatypes/ForBlockOptionalMeta.java b/src/api/java/baritone/api/command/datatypes/ForBlockOptionalMeta.java index 978450a23..079ec03fd 100644 --- a/src/api/java/baritone/api/command/datatypes/ForBlockOptionalMeta.java +++ b/src/api/java/baritone/api/command/datatypes/ForBlockOptionalMeta.java @@ -18,20 +18,136 @@ package baritone.api.command.datatypes; import baritone.api.command.exception.CommandException; +import baritone.api.command.helpers.TabCompleteHelper; import baritone.api.utils.BlockOptionalMeta; +import net.minecraft.block.Block; +import net.minecraft.block.properties.IProperty; +import net.minecraft.util.ResourceLocation; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; public enum ForBlockOptionalMeta implements IDatatypeFor { INSTANCE; + /** + * Matches (domain:)?name([(property=value)*])? but the input can be truncated at any position. + * domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ because that's what mc 1.13+ accepts. + * property and value use the same format as domain. + */ + // Good luck reading this. + private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?(?:[a-z0-9/_.-]+(?:\\[(?:(?:[a-z0-9_.-]+=[a-z0-9_.-]+,)*(?:[a-z0-9_.-]+(?:=(?:[a-z0-9_.-]+(?:\\])?)?)?)?|\\])?)?)?"); + @Override public BlockOptionalMeta get(IDatatypeContext ctx) throws CommandException { return new BlockOptionalMeta(ctx.getConsumer().getString()); } @Override - public Stream tabComplete(IDatatypeContext ctx) { - return ctx.getConsumer().tabCompleteDatatype(BlockById.INSTANCE); + public Stream tabComplete(IDatatypeContext ctx) throws CommandException { + String arg = ctx.getConsumer().peekString(); + + if (!PATTERN.matcher(arg).matches()) { + // Invalid format; we can't complete this. + ctx.getConsumer().getString(); + return Stream.empty(); + } + + if (arg.endsWith("]")) { + // We are already done. + ctx.getConsumer().getString(); + return Stream.empty(); + } + + if (!arg.contains("[")) { + // no properties so we are completing the block id + return ctx.getConsumer().tabCompleteDatatype(BlockById.INSTANCE); + } + + ctx.getConsumer().getString(); + + // destructuring assignment? Please? + String blockId, properties; + { + String[] parts = splitLast(arg, '['); + blockId = parts[0]; + properties = parts[1]; + } + + Block block = Block.REGISTRY.getObject(new ResourceLocation(blockId)); + if (block == null) { + // This block doesn't exist so there's no properties to complete. + return Stream.empty(); + } + + String leadingProperties, lastProperty; + { + String[] parts = splitLast(properties, ','); + leadingProperties = parts[0]; + lastProperty = parts[1]; + } + + if (!lastProperty.contains("=")) { + // The last property-value pair doesn't have a value yet so we are completing its name + Set usedProps = Stream.of(leadingProperties.split(",")) + .map(pair -> pair.split("=")[0]) + .collect(Collectors.toSet()); + + String prefix = arg.substring(0, arg.length() - lastProperty.length()); + return new TabCompleteHelper() + .append( + block.getBlockState() + .getProperties() + .stream() + .map(IProperty::getName) + ) + .filter(prop -> !usedProps.contains(prop)) + .filterPrefix(lastProperty) + .sortAlphabetically() + .map(prop -> prefix + prop) + .stream(); + } + + String lastName, lastValue; + { + String[] parts = splitLast(lastProperty, '='); + lastName = parts[0]; + lastValue = parts[1]; + } + + // We are completing the value of a property + String prefix = arg.substring(0, arg.length() - lastValue.length()); + + IProperty property = block.getBlockState().getProperty(lastName); + if (property == null) { + // The property does not exist so there's no values to complete + return Stream.empty(); + } + + return new TabCompleteHelper() + .append(getValues(property)) + .filterPrefix(lastValue) + .sortAlphabetically() + .map(val -> prefix + val) + .stream(); + } + + /** + * Always returns exactly two strings. + * If the separator is not found the FIRST returned string is empty. + */ + private static String[] splitLast(String string, char chr) { + int idx = string.lastIndexOf(chr); + if (idx == -1) { + return new String[]{"", string}; + } + return new String[]{string.substring(0, idx), string.substring(idx + 1)}; + } + + // this shouldn't need to be a separate method? + private static > Stream getValues(IProperty property) { + return property.getAllowedValues().stream().map(property::getName); } } diff --git a/src/api/java/baritone/api/pathing/goals/GoalAxis.java b/src/api/java/baritone/api/pathing/goals/GoalAxis.java index ad8fb892e..6e2f84e7a 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalAxis.java +++ b/src/api/java/baritone/api/pathing/goals/GoalAxis.java @@ -47,6 +47,11 @@ public class GoalAxis implements Goal { return o.getClass() == GoalAxis.class; } + @Override + public int hashCode() { + return 201385781; + } + @Override public String toString() { return "GoalAxis"; diff --git a/src/api/java/baritone/api/pathing/goals/GoalBlock.java b/src/api/java/baritone/api/pathing/goals/GoalBlock.java index d76fdc7af..24faa9b34 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalBlock.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -81,6 +82,11 @@ public class GoalBlock implements Goal, IGoalRenderPos { && z == goal.z; } + @Override + public int hashCode() { + return (int) BetterBlockPos.longHash(x, y, z) * 905165533; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/pathing/goals/GoalComposite.java b/src/api/java/baritone/api/pathing/goals/GoalComposite.java index d64f8e33e..8e13a86e4 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalComposite.java +++ b/src/api/java/baritone/api/pathing/goals/GoalComposite.java @@ -80,6 +80,11 @@ public class GoalComposite implements Goal { return Arrays.equals(goals, goal.goals); } + @Override + public int hashCode() { + return Arrays.hashCode(goals); + } + @Override public String toString() { return "GoalComposite" + Arrays.toString(goals); diff --git a/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java b/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java index b5caafa48..b8934a480 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -75,6 +76,11 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos { && z == goal.z; } + @Override + public int hashCode() { + return (int) BetterBlockPos.longHash(x, y, z) * -49639096; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/pathing/goals/GoalInverted.java b/src/api/java/baritone/api/pathing/goals/GoalInverted.java index e559088ef..4a3f75315 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalInverted.java +++ b/src/api/java/baritone/api/pathing/goals/GoalInverted.java @@ -65,6 +65,11 @@ public class GoalInverted implements Goal { return Objects.equals(origin, goal.origin); } + @Override + public int hashCode() { + return origin.hashCode() * 495796690; + } + @Override public String toString() { return String.format("GoalInverted{%s}", origin.toString()); diff --git a/src/api/java/baritone/api/pathing/goals/GoalNear.java b/src/api/java/baritone/api/pathing/goals/GoalNear.java index 166138ff4..e211c0194 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalNear.java +++ b/src/api/java/baritone/api/pathing/goals/GoalNear.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import it.unimi.dsi.fastutil.doubles.DoubleIterator; @@ -102,6 +103,11 @@ public class GoalNear implements Goal, IGoalRenderPos { && rangeSq == goal.rangeSq; } + @Override + public int hashCode() { + return (int) BetterBlockPos.longHash(x, y, z) + rangeSq; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java index 166ad5a98..1e65d30f7 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java +++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java @@ -140,6 +140,14 @@ public class GoalRunAway implements Goal { && Objects.equals(maintainY, goal.maintainY); } + @Override + public int hashCode() { + int hash = Arrays.hashCode(from); + hash = hash * 1196803141 + distanceSq; + hash = hash * -2053788840 + maintainY; + return hash; + } + @Override public String toString() { if (maintainY != null) { diff --git a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java index b8e4b43b2..b6bf16b33 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java +++ b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; @@ -86,6 +87,14 @@ public class GoalStrictDirection implements Goal { && dz == goal.dz; } + @Override + public int hashCode() { + int hash = (int) BetterBlockPos.longHash(x, y, z); + hash = hash * 630627507 + dx; + hash = hash * -283028380 + dz; + return hash; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java index d6fff33a2..475d6e972 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java +++ b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -87,6 +88,11 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos { && z == goal.z; } + @Override + public int hashCode() { + return (int) BetterBlockPos.longHash(x, y, z) * 516508351; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/pathing/goals/GoalXZ.java b/src/api/java/baritone/api/pathing/goals/GoalXZ.java index 2c551d395..1c7535b38 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalXZ.java +++ b/src/api/java/baritone/api/pathing/goals/GoalXZ.java @@ -77,6 +77,14 @@ public class GoalXZ implements Goal { return x == goal.x && z == goal.z; } + @Override + public int hashCode() { + int hash = 1791873246; + hash = hash * 222601791 + x; + hash = hash * -1331679453 + z; + return hash; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/pathing/goals/GoalYLevel.java b/src/api/java/baritone/api/pathing/goals/GoalYLevel.java index 37745e8de..442906ad1 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalYLevel.java +++ b/src/api/java/baritone/api/pathing/goals/GoalYLevel.java @@ -71,6 +71,11 @@ public class GoalYLevel implements Goal, ActionCosts { return level == goal.level; } + @Override + public int hashCode() { + return level * 1271009915; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java b/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java index e591c7873..bcce96651 100644 --- a/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java +++ b/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java @@ -33,7 +33,7 @@ public final class BinaryOperatorMask extends AbstractMask { private final BooleanBinaryOperator operator; public BinaryOperatorMask(Mask a, Mask b, BooleanBinaryOperator operator) { - super(a.widthX(), a.heightY(), a.lengthZ()); + super(Math.max(a.widthX(), b.widthX()), Math.max(a.heightY(), b.heightY()), Math.max(a.lengthZ(), b.lengthZ())); this.a = a; this.b = b; this.operator = operator; @@ -42,11 +42,15 @@ public final class BinaryOperatorMask extends AbstractMask { @Override public boolean partOfMask(int x, int y, int z, IBlockState currentState) { return this.operator.applyAsBoolean( - this.a.partOfMask(x, y, z, currentState), - this.b.partOfMask(x, y, z, currentState) + partOfMask(a, x, y, z, currentState), + partOfMask(b, x, y, z, currentState) ); } + private static boolean partOfMask(Mask mask, int x, int y, int z, IBlockState currentState) { + return x < mask.widthX() && y < mask.heightY() && z < mask.lengthZ() && mask.partOfMask(x, y, z, currentState); + } + public static final class Static extends AbstractMask implements StaticMask { private final StaticMask a; @@ -54,7 +58,7 @@ public final class BinaryOperatorMask extends AbstractMask { private final BooleanBinaryOperator operator; public Static(StaticMask a, StaticMask b, BooleanBinaryOperator operator) { - super(a.widthX(), a.heightY(), a.lengthZ()); + super(Math.max(a.widthX(), b.widthX()), Math.max(a.heightY(), b.heightY()), Math.max(a.lengthZ(), b.lengthZ())); this.a = a; this.b = b; this.operator = operator; @@ -63,9 +67,13 @@ public final class BinaryOperatorMask extends AbstractMask { @Override public boolean partOfMask(int x, int y, int z) { return this.operator.applyAsBoolean( - this.a.partOfMask(x, y, z), - this.b.partOfMask(x, y, z) + partOfMask(a, x, y, z), + partOfMask(b, x, y, z) ); } + + private static boolean partOfMask(StaticMask mask, int x, int y, int z) { + return x < mask.widthX() && y < mask.heightY() && z < mask.lengthZ() && mask.partOfMask(x, y, z); + } } } diff --git a/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java b/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java index 71b0d43c9..790a9a05d 100644 --- a/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java +++ b/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java @@ -35,8 +35,8 @@ public final class CylinderMask extends AbstractMask implements StaticMask { public CylinderMask(int widthX, int heightY, int lengthZ, boolean filled, EnumFacing.Axis alignment) { super(widthX, heightY, lengthZ); - this.centerA = this.getA(widthX, heightY) / 2.0; - this.centerB = this.getB(heightY, lengthZ) / 2.0; + this.centerA = this.getA(widthX, heightY, alignment) / 2.0; + this.centerB = this.getB(heightY, lengthZ, alignment) / 2.0; this.radiusSqA = (this.centerA - 1) * (this.centerA - 1); this.radiusSqB = (this.centerB - 1) * (this.centerB - 1); this.filled = filled; @@ -45,8 +45,8 @@ public final class CylinderMask extends AbstractMask implements StaticMask { @Override public boolean partOfMask(int x, int y, int z) { - double da = Math.abs((this.getA(x, y) + 0.5) - this.centerA); - double db = Math.abs((this.getB(y, z) + 0.5) - this.centerB); + double da = Math.abs((this.getA(x, y, this.alignment) + 0.5) - this.centerA); + double db = Math.abs((this.getB(y, z, this.alignment) + 0.5) - this.centerB); if (this.outside(da, db)) { return false; } @@ -59,11 +59,11 @@ public final class CylinderMask extends AbstractMask implements StaticMask { return da * da / this.radiusSqA + db * db / this.radiusSqB > 1; } - private int getA(int x, int y) { - return this.alignment == EnumFacing.Axis.X ? y : x; + private static int getA(int x, int y, EnumFacing.Axis alignment) { + return alignment == EnumFacing.Axis.X ? y : x; } - private int getB(int y, int z) { - return this.alignment == EnumFacing.Axis.Z ? y : z; + private static int getB(int y, int z, EnumFacing.Axis alignment) { + return alignment == EnumFacing.Axis.Z ? y : z; } } diff --git a/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java index 6d236e90e..6479854bc 100644 --- a/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java +++ b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java @@ -17,6 +17,7 @@ package baritone.api.utils; +import baritone.api.utils.accessor.IItemStack; import com.google.common.collect.ImmutableSet; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -29,8 +30,9 @@ import java.util.Set; import java.util.stream.Stream; public class BlockOptionalMetaLookup { - private final Set blockSet; - private final Set blockStateSet; + private final ImmutableSet blockSet; + private final ImmutableSet blockStateSet; + private final ImmutableSet stackHashes; private final BlockOptionalMeta[] boms; public BlockOptionalMetaLookup(BlockOptionalMeta... boms) { @@ -45,6 +47,7 @@ public class BlockOptionalMetaLookup { } this.blockSet = ImmutableSet.copyOf(blocks); this.blockStateSet = ImmutableSet.copyOf(blockStates); + this.stackHashes = ImmutableSet.copyOf(stacks); } public BlockOptionalMetaLookup(Block... blocks) { @@ -75,13 +78,9 @@ public class BlockOptionalMetaLookup { } public boolean has(ItemStack stack) { - for (BlockOptionalMeta bom : boms) { - if (bom.matches(stack)) { - return true; - } - } - - return false; + int hash = ((IItemStack) (Object) stack).getBaritoneHash(); + return stackHashes.contains(hash) + || stackHashes.contains(hash - stack.getItemDamage()); } public List blocks() { diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java index 4ebb22dd5..296d93999 100644 --- a/src/api/java/baritone/api/utils/RotationUtils.java +++ b/src/api/java/baritone/api/utils/RotationUtils.java @@ -168,7 +168,7 @@ public final class RotationUtils { } public static Optional reachable(IPlayerContext ctx, BlockPos pos, double blockReachDistance, boolean wouldSneak) { - if (ctx.isLookingAt(pos)) { + if (BaritoneAPI.getSettings().remainWithExistingLookDirection.value && ctx.isLookingAt(pos)) { /* * why add 0.0001? * to indicate that we actually have a desired pitch @@ -224,7 +224,8 @@ public final class RotationUtils { public static Optional reachableOffset(IPlayerContext ctx, BlockPos pos, Vec3d offsetPos, double blockReachDistance, boolean wouldSneak) { Vec3d eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(ctx.player()) : ctx.player().getPositionEyes(1.0F); Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, ctx.playerRotations()); - RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rotation, blockReachDistance, wouldSneak); + Rotation actualRotation = BaritoneAPI.getProvider().getBaritoneForPlayer(ctx.player()).getLookBehavior().getAimProcessor().peekRotation(rotation); + RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), actualRotation, blockReachDistance, wouldSneak); //System.out.println(result); if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) { if (result.getBlockPos().equals(pos)) { diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index 05e1992c9..5723cc422 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -102,9 +102,9 @@ public class Baritone implements IBaritone { this.playerContext = new BaritonePlayerContext(this, mc); { + this.lookBehavior = this.registerBehavior(LookBehavior::new); this.pathingBehavior = this.registerBehavior(PathingBehavior::new); this.elytraBehavior = this.registerBehavior(ElytraBehavior::new); - this.lookBehavior = this.registerBehavior(LookBehavior::new); this.inventoryBehavior = this.registerBehavior(InventoryBehavior::new); this.inputOverrideHandler = this.registerBehavior(InputOverrideHandler::new); this.registerBehavior(WaypointBehavior::new); diff --git a/src/main/java/baritone/behavior/LookBehavior.java b/src/main/java/baritone/behavior/LookBehavior.java index 1bf8e7146..9dd379771 100644 --- a/src/main/java/baritone/behavior/LookBehavior.java +++ b/src/main/java/baritone/behavior/LookBehavior.java @@ -20,13 +20,12 @@ package baritone.behavior; import baritone.Baritone; import baritone.api.Settings; import baritone.api.behavior.ILookBehavior; -import baritone.api.event.events.PacketEvent; -import baritone.api.event.events.PlayerUpdateEvent; -import baritone.api.event.events.RotationMoveEvent; -import baritone.api.event.events.WorldEvent; -import baritone.api.utils.Helper; +import baritone.api.behavior.look.IAimProcessor; +import baritone.api.behavior.look.ITickableAimProcessor; +import baritone.api.event.events.*; import baritone.api.utils.IPlayerContext; import baritone.api.utils.Rotation; +import baritone.behavior.look.ForkableRandom; import net.minecraft.network.play.client.CPacketPlayer; import java.util.Optional; @@ -44,14 +43,17 @@ public final class LookBehavior extends Behavior implements ILookBehavior { private Rotation serverRotation; /** - * The last player rotation. Used when free looking + * The last player rotation. Used to restore the player's angle when using free look. * * @see Settings#freeLook */ private Rotation prevRotation; + private final AimProcessor processor; + public LookBehavior(Baritone baritone) { super(baritone); + this.processor = new AimProcessor(baritone.getPlayerContext()); } @Override @@ -59,6 +61,18 @@ public final class LookBehavior extends Behavior implements ILookBehavior { this.target = new Target(rotation, Target.Mode.resolve(ctx, blockInteract)); } + @Override + public IAimProcessor getAimProcessor() { + return this.processor; + } + + @Override + public void onTick(TickEvent event) { + if (event.getType() == TickEvent.Type.IN) { + this.processor.tick(); + } + } + @Override public void onPlayerUpdate(PlayerUpdateEvent event) { if (this.target == null) { @@ -67,34 +81,16 @@ public final class LookBehavior extends Behavior implements ILookBehavior { switch (event.getState()) { case PRE: { if (this.target.mode == Target.Mode.NONE) { + // Just return for PRE, we still want to set target to null on POST return; } if (this.target.mode == Target.Mode.SERVER) { this.prevRotation = new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch); } - final float oldYaw = ctx.playerRotations().getYaw(); - final float oldPitch = ctx.playerRotations().getPitch(); - - float desiredYaw = this.target.rotation.getYaw(); - float desiredPitch = this.target.rotation.getPitch(); - - // In other words, the target doesn't care about the pitch, so it used playerRotations().getPitch() - // and it's safe to adjust it to a normal level - if (desiredPitch == oldPitch) { - desiredPitch = nudgeToLevel(desiredPitch); - } - - desiredYaw += (Math.random() - 0.5) * Baritone.settings().randomLooking.value; - desiredPitch += (Math.random() - 0.5) * Baritone.settings().randomLooking.value; - - ctx.player().rotationYaw = calculateMouseMove(oldYaw, desiredYaw); - ctx.player().rotationPitch = calculateMouseMove(oldPitch, desiredPitch); - - if (this.target.mode == Target.Mode.CLIENT) { - // The target can be invalidated now since it won't be needed for RotationMoveEvent - this.target = null; - } + final Rotation actual = this.processor.peekRotation(this.target.rotation); + ctx.player().rotationYaw = actual.getYaw(); + ctx.player().rotationPitch = actual.getPitch(); break; } case POST: { @@ -133,7 +129,8 @@ public final class LookBehavior extends Behavior implements ILookBehavior { public void pig() { if (this.target != null) { - ctx.player().rotationYaw = this.target.rotation.getYaw(); + final Rotation actual = this.processor.peekRotation(this.target.rotation); + ctx.player().rotationYaw = actual.getYaw(); } } @@ -148,37 +145,133 @@ public final class LookBehavior extends Behavior implements ILookBehavior { @Override public void onPlayerRotationMove(RotationMoveEvent event) { if (this.target != null) { - event.setYaw(this.target.rotation.getYaw()); - event.setPitch(this.target.rotation.getPitch()); + final Rotation actual = this.processor.peekRotation(this.target.rotation); + event.setYaw(actual.getYaw()); + event.setPitch(actual.getPitch()); } } - /** - * Nudges the player's pitch to a regular level. (Between {@code -20} and {@code 10}, increments are by {@code 1}) - */ - private static float nudgeToLevel(float pitch) { - if (pitch < -20) { - return pitch + 1; - } else if (pitch > 10) { - return pitch - 1; + private static final class AimProcessor extends AbstractAimProcessor { + + public AimProcessor(final IPlayerContext ctx) { + super(ctx); + } + + @Override + protected Rotation getPrevRotation() { + // Implementation will use LookBehavior.serverRotation + return ctx.playerRotations(); } - return pitch; } - private float calculateMouseMove(float current, float target) { - final float delta = target - current; - final int deltaPx = angleToMouse(delta); - return current + mouseToAngle(deltaPx); - } + private static abstract class AbstractAimProcessor implements ITickableAimProcessor { - private int angleToMouse(float angleDelta) { - final float minAngleChange = mouseToAngle(1); - return Math.round(angleDelta / minAngleChange); - } + protected final IPlayerContext ctx; + private final ForkableRandom rand; + private double randomYawOffset; + private double randomPitchOffset; - private float mouseToAngle(int mouseDelta) { - final float f = ctx.minecraft().gameSettings.mouseSensitivity * 0.6f + 0.2f; - return mouseDelta * f * f * f * 8.0f * 0.15f; + public AbstractAimProcessor(IPlayerContext ctx) { + this.ctx = ctx; + this.rand = new ForkableRandom(); + } + + private AbstractAimProcessor(final AbstractAimProcessor source) { + this.ctx = source.ctx; + this.rand = source.rand.fork(); + this.randomYawOffset = source.randomYawOffset; + this.randomPitchOffset = source.randomPitchOffset; + } + + @Override + public final Rotation peekRotation(final Rotation rotation) { + final Rotation prev = this.getPrevRotation(); + + float desiredYaw = rotation.getYaw(); + float desiredPitch = rotation.getPitch(); + + // In other words, the target doesn't care about the pitch, so it used playerRotations().getPitch() + // and it's safe to adjust it to a normal level + if (desiredPitch == prev.getPitch()) { + desiredPitch = nudgeToLevel(desiredPitch); + } + + desiredYaw += this.randomYawOffset; + desiredPitch += this.randomPitchOffset; + + return new Rotation( + this.calculateMouseMove(prev.getYaw(), desiredYaw), + this.calculateMouseMove(prev.getPitch(), desiredPitch) + ); + } + + @Override + public final void tick() { + this.randomYawOffset = (this.rand.nextDouble() - 0.5) * Baritone.settings().randomLooking.value; + this.randomPitchOffset = (this.rand.nextDouble() - 0.5) * Baritone.settings().randomLooking.value; + } + + @Override + public final void advance(int ticks) { + for (int i = 0; i < ticks; i++) { + this.tick(); + } + } + + @Override + public Rotation nextRotation(final Rotation rotation) { + final Rotation actual = this.peekRotation(rotation); + this.tick(); + return actual; + } + + @Override + public final ITickableAimProcessor fork() { + return new AbstractAimProcessor(this) { + + private Rotation prev = AbstractAimProcessor.this.getPrevRotation(); + + @Override + public Rotation nextRotation(final Rotation rotation) { + return (this.prev = super.nextRotation(rotation)); + } + + @Override + protected Rotation getPrevRotation() { + return this.prev; + } + }; + } + + protected abstract Rotation getPrevRotation(); + + /** + * Nudges the player's pitch to a regular level. (Between {@code -20} and {@code 10}, increments are by {@code 1}) + */ + private float nudgeToLevel(float pitch) { + if (pitch < -20) { + return pitch + 1; + } else if (pitch > 10) { + return pitch - 1; + } + return pitch; + } + + private float calculateMouseMove(float current, float target) { + final float delta = target - current; + final int deltaPx = angleToMouse(delta); + return current + mouseToAngle(deltaPx); + } + + private int angleToMouse(float angleDelta) { + final float minAngleChange = mouseToAngle(1); + return Math.round(angleDelta / minAngleChange); + } + + private float mouseToAngle(int mouseDelta) { + final float f = ctx.minecraft().gameSettings.mouseSensitivity * 0.6f + 0.2f; + return mouseDelta * f * f * f * 8.0f * 0.15f; + } } private static class Target { diff --git a/src/main/java/baritone/behavior/look/ForkableRandom.java b/src/main/java/baritone/behavior/look/ForkableRandom.java new file mode 100644 index 000000000..5f5f942d2 --- /dev/null +++ b/src/main/java/baritone/behavior/look/ForkableRandom.java @@ -0,0 +1,85 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.behavior.look; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.LongSupplier; + +/** + * Implementation of Xoroshiro256++ + *

+ * Extended to produce random double-precision floating point numbers, and allow copies to be spawned via {@link #fork}, + * which share the same internal state as the source object. + * + * @author Brady + */ +public final class ForkableRandom { + + private static final double DOUBLE_UNIT = 0x1.0p-53; + + private final long[] s; + + public ForkableRandom() { + this(System.nanoTime() ^ System.currentTimeMillis()); + } + + public ForkableRandom(long seedIn) { + final AtomicLong seed = new AtomicLong(seedIn); + final LongSupplier splitmix64 = () -> { + long z = seed.addAndGet(0x9e3779b97f4a7c15L); + z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; + z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL; + return z ^ (z >>> 31); + }; + this.s = new long[] { + splitmix64.getAsLong(), + splitmix64.getAsLong(), + splitmix64.getAsLong(), + splitmix64.getAsLong() + }; + } + + private ForkableRandom(long[] s) { + this.s = s; + } + + public double nextDouble() { + return (this.next() >>> 11) * DOUBLE_UNIT; + } + + public long next() { + final long result = rotl(this.s[0] + this.s[3], 23) + this.s[0]; + final long t = this.s[1] << 17; + this.s[2] ^= this.s[0]; + this.s[3] ^= this.s[1]; + this.s[1] ^= this.s[2]; + this.s[0] ^= this.s[3]; + this.s[2] ^= t; + this.s[3] = rotl(this.s[3], 45); + return result; + } + + public ForkableRandom fork() { + return new ForkableRandom(Arrays.copyOf(this.s, 4)); + } + + private static long rotl(long x, int k) { + return (x << k) | (x >>> (64 - k)); + } +} diff --git a/src/main/java/baritone/command/argument/ArgConsumer.java b/src/main/java/baritone/command/argument/ArgConsumer.java index 4a80681dd..42ac1e5a0 100644 --- a/src/main/java/baritone/command/argument/ArgConsumer.java +++ b/src/main/java/baritone/command/argument/ArgConsumer.java @@ -373,6 +373,8 @@ public class ArgConsumer implements IArgConsumer { public Stream tabCompleteDatatype(T datatype) { try { return datatype.tabComplete(this.context); + } catch (CommandException ignored) { + // NOP } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/baritone/command/defaults/GotoCommand.java b/src/main/java/baritone/command/defaults/GotoCommand.java index 333d7fa57..c64d7fa00 100644 --- a/src/main/java/baritone/command/defaults/GotoCommand.java +++ b/src/main/java/baritone/command/defaults/GotoCommand.java @@ -20,7 +20,6 @@ package baritone.command.defaults; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; -import baritone.api.command.datatypes.BlockById; import baritone.api.command.datatypes.ForBlockOptionalMeta; import baritone.api.command.datatypes.RelativeCoordinate; import baritone.api.command.datatypes.RelativeGoal; @@ -61,7 +60,8 @@ public class GotoCommand extends Command { public Stream tabComplete(String label, IArgConsumer args) throws CommandException { // since it's either a goal or a block, I don't think we can tab complete properly? // so just tab complete for the block variant - return args.tabCompleteDatatype(BlockById.INSTANCE); + args.requireMax(1); + return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE); } @Override diff --git a/src/main/java/baritone/command/defaults/MineCommand.java b/src/main/java/baritone/command/defaults/MineCommand.java index 1ab5c3321..0f0f9bcb1 100644 --- a/src/main/java/baritone/command/defaults/MineCommand.java +++ b/src/main/java/baritone/command/defaults/MineCommand.java @@ -21,7 +21,6 @@ import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; -import baritone.api.command.datatypes.BlockById; import baritone.api.command.datatypes.ForBlockOptionalMeta; import baritone.api.command.exception.CommandException; import baritone.api.utils.BlockOptionalMeta; @@ -52,8 +51,12 @@ public class MineCommand extends Command { } @Override - public Stream tabComplete(String label, IArgConsumer args) { - return args.tabCompleteDatatype(BlockById.INSTANCE); + public Stream tabComplete(String label, IArgConsumer args) throws CommandException { + args.getAsOrDefault(Integer.class, 0); + while (args.has(2)) { + args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE); + } + return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE); } @Override diff --git a/src/main/java/baritone/command/defaults/SetCommand.java b/src/main/java/baritone/command/defaults/SetCommand.java index dd6f1204b..4325cd625 100644 --- a/src/main/java/baritone/command/defaults/SetCommand.java +++ b/src/main/java/baritone/command/defaults/SetCommand.java @@ -22,12 +22,14 @@ import baritone.api.IBaritone; import baritone.api.Settings; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; +import baritone.api.command.datatypes.RelativeFile; import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.command.exception.CommandInvalidTypeException; import baritone.api.command.helpers.Paginator; import baritone.api.command.helpers.TabCompleteHelper; import baritone.api.utils.SettingsUtil; +import net.minecraft.client.Minecraft; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; @@ -221,6 +223,9 @@ public class SetCommand extends Command { .addToggleableSettings() .filterPrefix(args.getString()) .stream(); + } else if (Arrays.asList("ld", "load").contains(arg.toLowerCase(Locale.US))) { + // settings always use the directory of the main Minecraft instance + return RelativeFile.tabComplete(args, Minecraft.getMinecraft().gameDir.toPath().resolve("baritone").toFile()); } Settings.Setting setting = Baritone.settings().byLowerName.get(arg.toLowerCase(Locale.US)); if (setting != null) { diff --git a/src/main/java/baritone/command/manager/CommandManager.java b/src/main/java/baritone/command/manager/CommandManager.java index e7d24eb33..35cad4541 100644 --- a/src/main/java/baritone/command/manager/CommandManager.java +++ b/src/main/java/baritone/command/manager/CommandManager.java @@ -21,6 +21,7 @@ import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.command.ICommand; import baritone.api.command.argument.ICommandArgument; +import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandUnhandledException; import baritone.api.command.exception.ICommandException; import baritone.api.command.helpers.TabCompleteHelper; @@ -151,9 +152,12 @@ public class CommandManager implements ICommandManager { private Stream tabComplete() { try { return this.command.tabComplete(this.label, this.args); + } catch (CommandException ignored) { + // NOP } catch (Throwable t) { - return Stream.empty(); + t.printStackTrace(); } + return Stream.empty(); } } } diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index b14b2d69c..881bb6f15 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -684,7 +684,8 @@ public interface MovementHelper extends ActionCosts, Helper { double faceY = (placeAt.getY() + against1.getY() + 0.5D) * 0.5D; double faceZ = (placeAt.getZ() + against1.getZ() + 1.0D) * 0.5D; Rotation place = RotationUtils.calcRotationFromVec3d(wouldSneak ? RayTraceUtils.inferSneakingEyePosition(ctx.player()) : ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations()); - RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), place, ctx.playerController().getBlockReachDistance(), wouldSneak); + Rotation actual = baritone.getLookBehavior().getAimProcessor().peekRotation(place); + RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), actual, ctx.playerController().getBlockReachDistance(), wouldSneak); if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(placeAt)) { state.setTarget(new MovementState.MovementTarget(place, true)); found = true; diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index ac12471a3..60066971e 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -351,9 +351,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil double placeY = placeAgainstPos.y + aabb.minY * placementMultiplier.y + aabb.maxY * (1 - placementMultiplier.y); double placeZ = placeAgainstPos.z + aabb.minZ * placementMultiplier.z + aabb.maxZ * (1 - placementMultiplier.z); Rotation rot = RotationUtils.calcRotationFromVec3d(RayTraceUtils.inferSneakingEyePosition(ctx.player()), new Vec3d(placeX, placeY, placeZ), ctx.playerRotations()); - RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot, ctx.playerController().getBlockReachDistance(), true); + Rotation actualRot = baritone.getLookBehavior().getAimProcessor().peekRotation(rot); + RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), actualRot, ctx.playerController().getBlockReachDistance(), true); if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK && result.getBlockPos().equals(placeAgainstPos) && result.sideHit == against.getOpposite()) { - OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, rot); + OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, actualRot); if (hotbar.isPresent()) { return Optional.of(new Placement(hotbar.getAsInt(), placeAgainstPos, against.getOpposite(), rot)); } @@ -775,6 +776,14 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil && Objects.equals(fallback, goal.fallback); } + @Override + public int hashCode() { + int hash = -1701079641; + hash = hash * 1196141026 + primary.hashCode(); + hash = hash * -80327868 + fallback.hashCode(); + return hash; + } + @Override public String toString() { return "JankyComposite Primary: " + primary + " Fallback: " + fallback; @@ -806,6 +815,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil SettingsUtil.maybeCensor(z) ); } + + @Override + public int hashCode() { + return super.hashCode() * 1636324008; + } } private Goal placementGoal(BlockPos pos, BuilderCalculationContext bcc) { @@ -883,6 +897,15 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil && Objects.equals(no, goal.no); } + @Override + public int hashCode() { + int hash = 806368046; + hash = hash * 1412661222 + super.hashCode(); + hash = hash * 1730799370 + (int) BetterBlockPos.longHash(no.getX(), no.getY(), no.getZ()); + hash = hash * 260592149 + (allowSameLevel ? -1314802005 : 1565710265); + return hash; + } + @Override public String toString() { return String.format( @@ -906,6 +929,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return this.y * 100 + super.heuristic(x, y, z); } + @Override + public int hashCode() { + return super.hashCode() * 1910811835; + } + @Override public String toString() { return String.format( diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 777b48197..8cd1a6cae 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -325,6 +325,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return super.equals(o); } + @Override + public int hashCode() { + return super.hashCode() * 393857768; + } + @Override public String toString() { return String.format(