inventoryMoveOnlyIfStationary = new Setting<>(false);
+
/**
* Disable baritone's auto-tool at runtime, but still assume that another mod will provide auto tool functionality
*
@@ -107,6 +124,13 @@ public final class Settings {
*/
public final Setting walkOnWaterOnePenalty = new Setting<>(3D);
+ /**
+ * Don't allow breaking blocks next to liquids.
+ *
+ * Enable if you have mods adding custom fluid physics.
+ */
+ public final Setting strictLiquidCheck = new Setting<>(false);
+
/**
* Allow Baritone to fall arbitrary distances and place a water bucket beneath it.
* Reliability: questionable.
@@ -116,6 +140,8 @@ public final class Settings {
/**
* Allow Baritone to assume it can walk on still water just like any other block.
* This functionality is assumed to be provided by a separate library that might have imported Baritone.
+ *
+ * Note: This will prevent some usage of the frostwalker enchantment, like pillaring up from water.
*/
public final Setting assumeWalkOnWater = new Setting<>(false);
@@ -276,6 +302,12 @@ public final class Settings {
*/
public final Setting buildIgnoreDirection = new Setting<>(false);
+ /**
+ * A list of names of block properties the builder will ignore.
+ */
+ public final Setting> buildIgnoreProperties = new Setting<>(new ArrayList<>(Arrays.asList(
+ )));
+
/**
* If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block.
*
@@ -595,6 +627,13 @@ public final class Settings {
*/
public final Setting pruneRegionsFromRAM = new Setting<>(true);
+ /**
+ * The chunk packer queue can never grow to larger than this, if it does, the oldest chunks are discarded
+ *
+ * The newest chunks are kept, so that if you're moving in a straight line quickly then stop, your immediate render distance is still included
+ */
+ public final Setting chunkPackerQueueMaxSize = new Setting<>(2000);
+
/**
* Fill in blocks behind you
*/
@@ -696,6 +735,37 @@ public final class Settings {
*/
public final Setting freeLook = new Setting<>(true);
+ /**
+ * Break and place blocks without having to force the client-sided rotations. Requires {@link #freeLook}.
+ */
+ public final Setting blockFreeLook = new Setting<>(false);
+
+ /**
+ * Automatically elytra fly without having to force the client-sided rotations.
+ */
+ public final Setting elytraFreeLook = new Setting<>(true);
+
+ /**
+ * Forces the client-sided yaw rotation to an average of the last {@link #smoothLookTicks} of server-sided rotations.
+ */
+ public final Setting smoothLook = new Setting<>(false);
+
+ /**
+ * Same as {@link #smoothLook} but for elytra flying.
+ */
+ public final Setting elytraSmoothLook = new Setting<>(false);
+
+ /**
+ * The number of ticks to average across for {@link #smoothLook};
+ */
+ public final Setting smoothLookTicks = new Setting<>(5);
+
+ /**
+ * 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.
*
@@ -758,6 +828,11 @@ public final class Settings {
*/
public final Setting shortBaritonePrefix = new Setting<>(false);
+ /**
+ * Use a modern message tag instead of a prefix when logging to chat
+ */
+ public final Setting useMessageTag = new Setting<>(false);
+
/**
* Echo commands to chat when they are run
*/
@@ -831,6 +906,11 @@ public final class Settings {
*/
public final Setting minYLevelWhileMining = new Setting<>(0);
+ /**
+ * Sets the maximum y level to mine ores at.
+ */
+ public final Setting maxYLevelWhileMining = new Setting<>(2031);
+
/**
* This will only allow baritone to mine exposed ores, can be used to stop ore obfuscators on servers that use them.
*/
@@ -1127,13 +1207,18 @@ public final class Settings {
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
* {@link Setting#value};
*/
- public final Setting> logger = new Setting<>(msg -> Minecraft.getInstance().gui.getChat().addMessage(msg));
+ @JavaOnly
+ public final Setting> logger = new Setting<>((msg) -> {
+ final GuiMessageTag tag = useMessageTag.value ? Helper.MESSAGE_TAG : null;
+ Minecraft.getInstance().gui.getChat().addMessage(msg, null, tag);
+ });
/**
* The function that is called when Baritone will send a desktop notification. This function can be added to
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
* {@link Setting#value};
*/
+ @JavaOnly
public final Setting> notifier = new Setting<>(NotificationHelper::notify);
/**
@@ -1141,6 +1226,7 @@ public final class Settings {
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
* {@link Setting#value};
*/
+ @JavaOnly
public final Setting> toaster = new Setting<>(BaritoneToast::addOrUpdate);
/**
@@ -1273,6 +1359,120 @@ public final class Settings {
*/
public final Setting notificationOnMineFail = new Setting<>(true);
+ /**
+ * The number of ticks of elytra movement to simulate while firework boost is not active. Higher values are
+ * computationally more expensive.
+ */
+ public final Setting elytraSimulationTicks = new Setting<>(20);
+
+ /**
+ * The maximum allowed deviation in pitch from a direct line-of-sight to the flight target. Higher values are
+ * computationally more expensive.
+ */
+ public final Setting elytraPitchRange = new Setting<>(25);
+
+ /**
+ * The minimum speed that the player can drop to (in blocks/tick) before a firework is automatically deployed.
+ */
+ public final Setting elytraFireworkSpeed = new Setting<>(1.2);
+
+ /**
+ * The delay after the player's position is set-back by the server that a firework may be automatically deployed.
+ * Value is in ticks.
+ */
+ public final Setting elytraFireworkSetbackUseDelay = new Setting<>(15);
+
+ /**
+ * The minimum padding value that is added to the player's hitbox when considering which point to fly to on the
+ * path. High values can result in points not being considered which are otherwise safe to fly to. Low values can
+ * result in flight paths which are extremely tight, and there's the possibility of crashing due to getting too low
+ * to the ground.
+ */
+ public final Setting elytraMinimumAvoidance = new Setting<>(0.2);
+
+ /**
+ * If enabled, avoids using fireworks when descending along the flight path.
+ */
+ public final Setting elytraConserveFireworks = new Setting<>(false);
+
+ /**
+ * Renders the raytraces that are performed by the elytra fly calculation.
+ */
+ public final Setting elytraRenderRaytraces = new Setting<>(false);
+
+ /**
+ * Renders the raytraces that are used in the hitbox part of the elytra fly calculation.
+ * Requires {@link #elytraRenderRaytraces}.
+ */
+ public final Setting elytraRenderHitboxRaytraces = new Setting<>(false);
+
+ /**
+ * Renders the best elytra flight path that was simulated each tick.
+ */
+ public final Setting elytraRenderSimulation = new Setting<>(true);
+
+ /**
+ * Automatically path to and jump off of ledges to initiate elytra flight when grounded.
+ */
+ public final Setting elytraAutoJump = new Setting<>(false);
+
+ /**
+ * The seed used to generate chunks for long distance elytra path-finding in the nether.
+ * Defaults to 2b2t's nether seed.
+ */
+ public final Setting elytraNetherSeed = new Setting<>(146008555100680L);
+
+ /**
+ * Whether nether-pathfinder should generate terrain based on {@link #elytraNetherSeed}.
+ * If false all chunks that haven't been loaded are assumed to be air.
+ */
+ public final Setting elytraPredictTerrain = new Setting<>(false);
+
+ /**
+ * Automatically swap the current elytra with a new one when the durability gets too low
+ */
+ public final Setting elytraAutoSwap = new Setting<>(true);
+
+ /**
+ * The minimum durability an elytra can have before being swapped
+ */
+ public final Setting elytraMinimumDurability = new Setting<>(5);
+
+ /**
+ * The minimum fireworks before landing early for safety
+ */
+ public final Setting elytraMinFireworksBeforeLanding = new Setting<>(5);
+
+ /**
+ * Automatically land when elytra is almost out of durability, or almost out of fireworks
+ */
+ public final Setting elytraAllowEmergencyLand = new Setting<>(true);
+
+ /**
+ * Time between culling far away chunks from the nether pathfinder chunk cache
+ */
+ public final Setting elytraTimeBetweenCacheCullSecs = new Setting<>(TimeUnit.MINUTES.toSeconds(3));
+
+ /**
+ * Maximum distance chunks can be before being culled from the nether pathfinder chunk cache
+ */
+ public final Setting elytraCacheCullDistance = new Setting<>(5000);
+
+ /**
+ * Should elytra consider nether brick a valid landing block
+ */
+ public final Setting elytraAllowLandOnNetherFortress = new Setting<>(false);
+
+ /**
+ * Has the user read and understood the elytra terms and conditions
+ */
+ public final Setting elytraTermsAccepted = new Setting<>(false);
+
+ /**
+ * Verbose chat logging in elytra mode
+ */
+ public final Setting elytraChatSpam = new Setting<>(false);
+
/**
* A map of lowercase setting field names to their respective setting
*/
@@ -1290,6 +1490,7 @@ public final class Setting {
public T value;
public final T defaultValue;
private String name;
+ private boolean javaOnly;
@SuppressWarnings("unchecked")
private Setting(T value) {
@@ -1298,6 +1499,7 @@ private Setting(T value) {
}
this.value = value;
this.defaultValue = value;
+ this.javaOnly = false;
}
/**
@@ -1334,8 +1536,25 @@ public void reset() {
public final Type getType() {
return settingTypes.get(this);
}
+
+ /**
+ * This should always be the same as whether the setting can be parsed from or serialized to a string; in other
+ * words, the only way to modify it is by writing to {@link #value} programatically.
+ *
+ * @return {@code true} if the setting can not be set or read by the user
+ */
+ public boolean isJavaOnly() {
+ return javaOnly;
+ }
}
+ /**
+ * Marks a {@link Setting} field as being {@link Setting#isJavaOnly() Java-only}
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.FIELD)
+ private @interface JavaOnly {}
+
// here be dragons
Settings() {
@@ -1351,6 +1570,7 @@ public final Type getType() {
Setting> setting = (Setting>) field.get(this);
String name = field.getName();
setting.name = name;
+ setting.javaOnly = field.isAnnotationPresent(JavaOnly.class);
name = name.toLowerCase();
if (tmpByName.containsKey(name)) {
throw new IllegalStateException("Duplicate setting name");
diff --git a/src/api/java/baritone/api/behavior/IBehavior.java b/src/api/java/baritone/api/behavior/IBehavior.java
index 95fb22344..811563b93 100644
--- a/src/api/java/baritone/api/behavior/IBehavior.java
+++ b/src/api/java/baritone/api/behavior/IBehavior.java
@@ -27,5 +27,4 @@
* @see IGameEventListener
* @since 9/23/2018
*/
-public interface IBehavior extends AbstractGameEventListener {
-}
+public interface IBehavior extends AbstractGameEventListener {}
diff --git a/src/api/java/baritone/api/behavior/ILookBehavior.java b/src/api/java/baritone/api/behavior/ILookBehavior.java
index 058a5dd88..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;
/**
@@ -26,14 +28,23 @@
public interface ILookBehavior extends IBehavior {
/**
- * Updates the current {@link ILookBehavior} target to target
- * the specified rotations on the next tick. If force is {@code true},
- * then freeLook will be overriden and angles will be set regardless.
- * If any sort of block interaction is required, force should be {@code true},
- * otherwise, it should be {@code false};
+ * 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}. 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 force Whether or not to "force" the rotations
+ * @param rotation The target rotations
+ * @param blockInteract Whether the target rotations are needed for a block interaction
*/
- void updateTarget(Rotation rotation, boolean force);
+ 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/cache/ICachedWorld.java b/src/api/java/baritone/api/cache/ICachedWorld.java
index 120ca8da4..6e74fa55a 100644
--- a/src/api/java/baritone/api/cache/ICachedWorld.java
+++ b/src/api/java/baritone/api/cache/ICachedWorld.java
@@ -17,11 +17,10 @@
package baritone.api.cache;
+import java.util.ArrayList;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.chunk.LevelChunk;
-import java.util.ArrayList;
-
/**
* @author Brady
* @since 9/24/2018
diff --git a/src/api/java/baritone/api/cache/IWorldProvider.java b/src/api/java/baritone/api/cache/IWorldProvider.java
index 0e54ef469..b9ca149c7 100644
--- a/src/api/java/baritone/api/cache/IWorldProvider.java
+++ b/src/api/java/baritone/api/cache/IWorldProvider.java
@@ -17,6 +17,8 @@
package baritone.api.cache;
+import java.util.function.Consumer;
+
/**
* @author Brady
* @since 9/24/2018
@@ -29,4 +31,11 @@ public interface IWorldProvider {
* @return The current world data
*/
IWorldData getCurrentWorld();
+
+ default void ifWorldLoaded(Consumer callback) {
+ final IWorldData currentWorld = this.getCurrentWorld();
+ if (currentWorld != null) {
+ callback.accept(currentWorld);
+ }
+ }
}
diff --git a/src/api/java/baritone/api/cache/IWorldScanner.java b/src/api/java/baritone/api/cache/IWorldScanner.java
index d8cf2bd38..ea27dd161 100644
--- a/src/api/java/baritone/api/cache/IWorldScanner.java
+++ b/src/api/java/baritone/api/cache/IWorldScanner.java
@@ -19,12 +19,11 @@
import baritone.api.utils.BlockOptionalMetaLookup;
import baritone.api.utils.IPlayerContext;
+import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Block;
-import java.util.List;
-
/**
* @author Brady
* @since 10/6/2018
diff --git a/src/api/java/baritone/api/command/argument/IArgConsumer.java b/src/api/java/baritone/api/command/argument/IArgConsumer.java
index 833d67736..894e4a71b 100644
--- a/src/api/java/baritone/api/command/argument/IArgConsumer.java
+++ b/src/api/java/baritone/api/command/argument/IArgConsumer.java
@@ -27,11 +27,10 @@
import baritone.api.command.exception.CommandNotEnoughArgumentsException;
import baritone.api.command.exception.CommandTooManyArgumentsException;
import baritone.api.utils.Helper;
-import net.minecraft.core.Direction;
-
import java.util.Deque;
import java.util.LinkedList;
import java.util.stream.Stream;
+import net.minecraft.core.Direction;
/**
* The {@link IArgConsumer} is how {@link ICommand}s read the arguments passed to them. This class has many benefits:
diff --git a/src/api/java/baritone/api/command/datatypes/BlockById.java b/src/api/java/baritone/api/command/datatypes/BlockById.java
index 21562e188..f92c968a2 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.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
+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 Block get(IDatatypeContext ctx) throws CommandException {
@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(
BuiltInRegistries.BLOCK.keySet()
.stream()
.map(Object::toString)
)
- .filterPrefixNamespaced(ctx.getConsumer().getString())
+ .filterPrefixNamespaced(arg)
.sortAlphabetically()
.stream();
}
diff --git a/src/api/java/baritone/api/command/datatypes/ForAxis.java b/src/api/java/baritone/api/command/datatypes/ForAxis.java
new file mode 100644
index 000000000..369697dcb
--- /dev/null
+++ b/src/api/java/baritone/api/command/datatypes/ForAxis.java
@@ -0,0 +1,43 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.command.datatypes;
+
+import baritone.api.command.exception.CommandException;
+import baritone.api.command.helpers.TabCompleteHelper;
+import net.minecraft.core.Direction;
+
+import java.util.Locale;
+import java.util.stream.Stream;
+
+public enum ForAxis implements IDatatypeFor {
+ INSTANCE;
+
+ @Override
+ public Direction.Axis get(IDatatypeContext ctx) throws CommandException {
+ return Direction.Axis.valueOf(ctx.getConsumer().getString().toUpperCase(Locale.US));
+ }
+
+ @Override
+ public Stream tabComplete(IDatatypeContext ctx) throws CommandException {
+ return new TabCompleteHelper()
+ .append(Stream.of(Direction.Axis.values())
+ .map(Direction.Axis::getName).map(String::toLowerCase))
+ .filterPrefix(ctx.getConsumer().getString())
+ .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..5b949cd63 100644
--- a/src/api/java/baritone/api/command/datatypes/ForBlockOptionalMeta.java
+++ b/src/api/java/baritone/api/command/datatypes/ForBlockOptionalMeta.java
@@ -18,20 +18,137 @@
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.core.registries.BuiltInRegistries;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.properties.Property;
+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 = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(blockId)).orElse(null);
+ 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.getStateDefinition()
+ .getProperties()
+ .stream()
+ .map(Property::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());
+
+ Property> property = block.getStateDefinition().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(Property property) {
+ return property.getPossibleValues().stream().map(property::getName);
}
}
diff --git a/src/api/java/baritone/api/command/datatypes/ForDirection.java b/src/api/java/baritone/api/command/datatypes/ForDirection.java
index 5dd355b41..cbfbc2243 100644
--- a/src/api/java/baritone/api/command/datatypes/ForDirection.java
+++ b/src/api/java/baritone/api/command/datatypes/ForDirection.java
@@ -19,10 +19,9 @@
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
-import net.minecraft.core.Direction;
-
import java.util.Locale;
import java.util.stream.Stream;
+import net.minecraft.core.Direction;
public enum ForDirection implements IDatatypeFor {
INSTANCE;
diff --git a/src/api/java/baritone/api/command/datatypes/NearbyPlayer.java b/src/api/java/baritone/api/command/datatypes/NearbyPlayer.java
index d1016e99e..b0d72bed1 100644
--- a/src/api/java/baritone/api/command/datatypes/NearbyPlayer.java
+++ b/src/api/java/baritone/api/command/datatypes/NearbyPlayer.java
@@ -20,11 +20,10 @@
import baritone.api.IBaritone;
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
-import net.minecraft.network.chat.Component;
-import net.minecraft.world.entity.player.Player;
-
import java.util.List;
import java.util.stream.Stream;
+import net.minecraft.network.chat.Component;
+import net.minecraft.world.entity.player.Player;
/**
* An {@link IDatatype} used to resolve nearby players, those within
diff --git a/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java b/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java
index 7d77a96c7..3d0f2613f 100644
--- a/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java
+++ b/src/api/java/baritone/api/command/datatypes/RelativeCoordinate.java
@@ -26,7 +26,8 @@
public enum RelativeCoordinate implements IDatatypePost {
INSTANCE;
- private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)([k-k]?)|)$");
+ private static String ScalesAliasRegex = "[kKmM]";
+ private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(" + ScalesAliasRegex + "?)|)$");
@Override
public Double apply(IDatatypeContext ctx, Double origin) throws CommandException {
@@ -41,11 +42,15 @@ public Double apply(IDatatypeContext ctx, Double origin) throws CommandException
boolean isRelative = !matcher.group(1).isEmpty();
- double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2).replaceAll("k", ""));
+ double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2).replaceAll(ScalesAliasRegex, ""));
- if (matcher.group(2).contains("k")) {
+ if (matcher.group(2).toLowerCase().contains("k")) {
offset *= 1000;
}
+ if (matcher.group(2).toLowerCase().contains("m")) {
+ offset *= 1000000;
+ }
+
if (isRelative) {
return origin + offset;
diff --git a/src/api/java/baritone/api/command/datatypes/RelativeFile.java b/src/api/java/baritone/api/command/datatypes/RelativeFile.java
index 7d7e6899b..e85f12971 100644
--- a/src/api/java/baritone/api/command/datatypes/RelativeFile.java
+++ b/src/api/java/baritone/api/command/datatypes/RelativeFile.java
@@ -19,6 +19,8 @@
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
+import baritone.api.utils.Helper;
+import net.minecraft.client.Minecraft;
import java.io.File;
import java.io.IOException;
@@ -30,8 +32,6 @@
import java.util.Objects;
import java.util.stream.Stream;
-import static baritone.api.utils.Helper.HELPER;
-
public enum RelativeFile implements IDatatypePost {
INSTANCE;
@@ -93,8 +93,13 @@ public static Stream tabComplete(IArgConsumer consumer, File base0) thro
.filter(s -> !s.contains(" "));
}
+ @Deprecated
public static File gameDir() {
- File gameDir = HELPER.mc.gameDirectory.getAbsoluteFile();
+ return gameDir(Helper.mc);
+ }
+
+ public static File gameDir(Minecraft mc) {
+ File gameDir = mc.gameDirectory.getAbsoluteFile();
if (gameDir.getName().equals(".")) {
return gameDir.getParentFile();
}
diff --git a/src/api/java/baritone/api/command/datatypes/RelativeGoalBlock.java b/src/api/java/baritone/api/command/datatypes/RelativeGoalBlock.java
index 738ca019a..d97635eb2 100644
--- a/src/api/java/baritone/api/command/datatypes/RelativeGoalBlock.java
+++ b/src/api/java/baritone/api/command/datatypes/RelativeGoalBlock.java
@@ -21,9 +21,8 @@
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.utils.BetterBlockPos;
-import net.minecraft.util.Mth;
-
import java.util.stream.Stream;
+import net.minecraft.util.Mth;
public enum RelativeGoalBlock implements IDatatypePost {
INSTANCE;
diff --git a/src/api/java/baritone/api/command/datatypes/RelativeGoalXZ.java b/src/api/java/baritone/api/command/datatypes/RelativeGoalXZ.java
index c4dd045f3..8682bbbaf 100644
--- a/src/api/java/baritone/api/command/datatypes/RelativeGoalXZ.java
+++ b/src/api/java/baritone/api/command/datatypes/RelativeGoalXZ.java
@@ -21,9 +21,8 @@
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.GoalXZ;
import baritone.api.utils.BetterBlockPos;
-import net.minecraft.util.Mth;
-
import java.util.stream.Stream;
+import net.minecraft.util.Mth;
public enum RelativeGoalXZ implements IDatatypePost {
INSTANCE;
diff --git a/src/api/java/baritone/api/command/datatypes/RelativeGoalYLevel.java b/src/api/java/baritone/api/command/datatypes/RelativeGoalYLevel.java
index 9a13e4bbd..34c8c0018 100644
--- a/src/api/java/baritone/api/command/datatypes/RelativeGoalYLevel.java
+++ b/src/api/java/baritone/api/command/datatypes/RelativeGoalYLevel.java
@@ -21,9 +21,8 @@
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.GoalYLevel;
import baritone.api.utils.BetterBlockPos;
-import net.minecraft.util.Mth;
-
import java.util.stream.Stream;
+import net.minecraft.util.Mth;
public enum RelativeGoalYLevel implements IDatatypePost {
INSTANCE;
diff --git a/src/api/java/baritone/api/command/exception/CommandUnhandledException.java b/src/api/java/baritone/api/command/exception/CommandUnhandledException.java
index 51840a117..a1f826262 100644
--- a/src/api/java/baritone/api/command/exception/CommandUnhandledException.java
+++ b/src/api/java/baritone/api/command/exception/CommandUnhandledException.java
@@ -19,7 +19,6 @@
import baritone.api.command.ICommand;
import baritone.api.command.argument.ICommandArgument;
-import net.minecraft.ChatFormatting;
import java.util.List;
@@ -37,10 +36,6 @@ public CommandUnhandledException(Throwable cause) {
@Override
public void handle(ICommand command, List args) {
- HELPER.logDirect("An unhandled exception occurred. " +
- "The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
- ChatFormatting.RED);
-
- this.printStackTrace();
+ HELPER.logUnhandledException(this);
}
}
diff --git a/src/api/java/baritone/api/command/exception/ICommandException.java b/src/api/java/baritone/api/command/exception/ICommandException.java
index 389129761..0a1529d69 100644
--- a/src/api/java/baritone/api/command/exception/ICommandException.java
+++ b/src/api/java/baritone/api/command/exception/ICommandException.java
@@ -19,9 +19,8 @@
import baritone.api.command.ICommand;
import baritone.api.command.argument.ICommandArgument;
-import net.minecraft.ChatFormatting;
-
import java.util.List;
+import net.minecraft.ChatFormatting;
import static baritone.api.utils.Helper.HELPER;
diff --git a/src/api/java/baritone/api/command/helpers/Paginator.java b/src/api/java/baritone/api/command/helpers/Paginator.java
index e119a9a23..77628a796 100644
--- a/src/api/java/baritone/api/command/helpers/Paginator.java
+++ b/src/api/java/baritone/api/command/helpers/Paginator.java
@@ -21,16 +21,17 @@
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidTypeException;
import baritone.api.utils.Helper;
+
+import java.awt.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.network.chat.MutableComponent;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Function;
-
public class Paginator implements Helper {
public final List entries;
diff --git a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java
index 0722ce16d..4f822352a 100644
--- a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java
+++ b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java
@@ -23,14 +23,13 @@
import baritone.api.command.manager.ICommandManager;
import baritone.api.event.events.TabCompleteEvent;
import baritone.api.utils.SettingsUtil;
-import net.minecraft.resources.ResourceLocation;
-
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
+import net.minecraft.resources.ResourceLocation;
/**
* The {@link TabCompleteHelper} is a single-use object that helps you handle tab completion. It includes helper
@@ -253,7 +252,7 @@ public TabCompleteHelper addCommands(ICommandManager manager) {
public TabCompleteHelper addSettings() {
return append(
BaritoneAPI.getSettings().allSettings.stream()
- .filter(s -> !SettingsUtil.javaOnlySetting(s))
+ .filter(s -> !s.isJavaOnly())
.map(Settings.Setting::getName)
.sorted(String.CASE_INSENSITIVE_ORDER)
);
diff --git a/src/api/java/baritone/api/command/registry/Registry.java b/src/api/java/baritone/api/command/registry/Registry.java
index 067791690..b571484b7 100644
--- a/src/api/java/baritone/api/command/registry/Registry.java
+++ b/src/api/java/baritone/api/command/registry/Registry.java
@@ -84,7 +84,7 @@ public boolean register(V entry) {
* @param entry The entry to unregister.
*/
public void unregister(V entry) {
- if (registered(entry)) {
+ if (!registered(entry)) {
return;
}
_entries.remove(entry);
diff --git a/src/api/java/baritone/api/event/events/BlockChangeEvent.java b/src/api/java/baritone/api/event/events/BlockChangeEvent.java
new file mode 100644
index 000000000..4fc496eb5
--- /dev/null
+++ b/src/api/java/baritone/api/event/events/BlockChangeEvent.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.event.events;
+
+import baritone.api.utils.Pair;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.block.state.BlockState;
+
+import java.util.List;
+
+/**
+ * @author Brady
+ */
+public final class BlockChangeEvent {
+
+ private final ChunkPos chunk;
+ private final List> blocks;
+
+ public BlockChangeEvent(ChunkPos pos, List> blocks) {
+ this.chunk = pos;
+ this.blocks = blocks;
+ }
+
+ public ChunkPos getChunkPos() {
+ return this.chunk;
+ }
+
+ public List> getBlocks() {
+ return this.blocks;
+ }
+}
diff --git a/src/api/java/baritone/api/event/events/ChunkEvent.java b/src/api/java/baritone/api/event/events/ChunkEvent.java
index f27475bce..bb22a47b1 100644
--- a/src/api/java/baritone/api/event/events/ChunkEvent.java
+++ b/src/api/java/baritone/api/event/events/ChunkEvent.java
@@ -57,31 +57,38 @@ public ChunkEvent(EventState state, Type type, int x, int z) {
/**
* @return The state of the event
*/
- public final EventState getState() {
+ public EventState getState() {
return this.state;
}
/**
* @return The type of chunk event that occurred;
*/
- public final Type getType() {
+ public Type getType() {
return this.type;
}
/**
* @return The Chunk X position.
*/
- public final int getX() {
+ public int getX() {
return this.x;
}
/**
* @return The Chunk Z position.
*/
- public final int getZ() {
+ public int getZ() {
return this.z;
}
+ /**
+ * @return {@code true} if the event was fired after a chunk population
+ */
+ public boolean isPostPopulate() {
+ return this.state == EventState.POST && this.type.isPopulate();
+ }
+
public enum Type {
/**
@@ -106,6 +113,10 @@ public enum Type {
*
* And it's a partial chunk
*/
- POPULATE_PARTIAL
+ POPULATE_PARTIAL;
+
+ public final boolean isPopulate() {
+ return this == POPULATE_FULL || this == POPULATE_PARTIAL;
+ }
}
}
diff --git a/src/api/java/baritone/api/event/events/RotationMoveEvent.java b/src/api/java/baritone/api/event/events/RotationMoveEvent.java
index bae83c0fa..c5a9ea9f9 100644
--- a/src/api/java/baritone/api/event/events/RotationMoveEvent.java
+++ b/src/api/java/baritone/api/event/events/RotationMoveEvent.java
@@ -17,6 +17,7 @@
package baritone.api.event.events;
+import baritone.api.utils.Rotation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.Vec3;
@@ -32,14 +33,27 @@ public final class RotationMoveEvent {
*/
private final Type type;
+ private final Rotation original;
+
/**
* The yaw rotation
*/
private float yaw;
- public RotationMoveEvent(Type type, float yaw) {
+ /**
+ * The pitch rotation
+ */
+ private float pitch;
+
+ public RotationMoveEvent(Type type, float yaw, float pitch) {
this.type = type;
+ this.original = new Rotation(yaw, pitch);
this.yaw = yaw;
+ this.pitch = pitch;
+ }
+
+ public Rotation getOriginal() {
+ return this.original;
}
/**
@@ -47,21 +61,37 @@ public RotationMoveEvent(Type type, float yaw) {
*
* @param yaw Yaw rotation
*/
- public final void setYaw(float yaw) {
+ public void setYaw(float yaw) {
this.yaw = yaw;
}
/**
* @return The yaw rotation
*/
- public final float getYaw() {
+ public float getYaw() {
return this.yaw;
}
+ /**
+ * Set the pitch movement rotation
+ *
+ * @param pitch Pitch rotation
+ */
+ public void setPitch(float pitch) {
+ this.pitch = pitch;
+ }
+
+ /**
+ * @return The pitch rotation
+ */
+ public float getPitch() {
+ return pitch;
+ }
+
/**
* @return The type of the event
*/
- public final Type getType() {
+ public Type getType() {
return this.type;
}
diff --git a/src/api/java/baritone/api/event/events/TickEvent.java b/src/api/java/baritone/api/event/events/TickEvent.java
index 5c484ae49..405ad3c49 100644
--- a/src/api/java/baritone/api/event/events/TickEvent.java
+++ b/src/api/java/baritone/api/event/events/TickEvent.java
@@ -18,9 +18,18 @@
package baritone.api.event.events;
import baritone.api.event.events.type.EventState;
+import net.minecraft.client.Minecraft;
import java.util.function.BiFunction;
+/**
+ * Called on and after each game tick of the primary {@link Minecraft} instance and dispatched to all Baritone
+ * instances.
+ *
+ * When {@link #state} is {@link EventState#PRE}, the event is being called just prior to when the current in-game
+ * screen is ticked. When {@link #state} is {@link EventState#POST}, the event is being called at the very end
+ * of the {@link Minecraft#runTick()} method.
+ */
public final class TickEvent {
private static int overallTickCount;
diff --git a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java
index 5a94e5100..54aabe387 100644
--- a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java
+++ b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java
@@ -31,58 +31,50 @@
public interface AbstractGameEventListener extends IGameEventListener {
@Override
- default void onTick(TickEvent event) {
- }
+ default void onTick(TickEvent event) {}
@Override
- default void onPlayerUpdate(PlayerUpdateEvent event) {
- }
+ default void onPostTick(TickEvent event) {}
@Override
- default void onSendChatMessage(ChatEvent event) {
- }
+ default void onPlayerUpdate(PlayerUpdateEvent event) {}
@Override
- default void onPreTabComplete(TabCompleteEvent event) {
- }
+ default void onSendChatMessage(ChatEvent event) {}
@Override
- default void onChunkEvent(ChunkEvent event) {
- }
+ default void onPreTabComplete(TabCompleteEvent event) {}
@Override
- default void onRenderPass(RenderEvent event) {
- }
+ default void onChunkEvent(ChunkEvent event) {}
@Override
- default void onWorldEvent(WorldEvent event) {
- }
+ default void onBlockChange(BlockChangeEvent event) {}
@Override
- default void onSendPacket(PacketEvent event) {
- }
+ default void onRenderPass(RenderEvent event) {}
@Override
- default void onReceivePacket(PacketEvent event) {
- }
+ default void onWorldEvent(WorldEvent event) {}
@Override
- default void onPlayerRotationMove(RotationMoveEvent event) {
- }
+ default void onSendPacket(PacketEvent event) {}
@Override
- default void onPlayerSprintState(SprintStateEvent event) {
- }
+ default void onReceivePacket(PacketEvent event) {}
@Override
- default void onBlockInteract(BlockInteractEvent event) {
- }
+ default void onPlayerRotationMove(RotationMoveEvent event) {}
@Override
- default void onPlayerDeath() {
- }
+ default void onPlayerSprintState(SprintStateEvent event) {}
@Override
- default void onPathEvent(PathEvent event) {
- }
+ default void onBlockInteract(BlockInteractEvent event) {}
+
+ @Override
+ default void onPlayerDeath() {}
+
+ @Override
+ default void onPathEvent(PathEvent event) {}
}
diff --git a/src/api/java/baritone/api/event/listener/IGameEventListener.java b/src/api/java/baritone/api/event/listener/IGameEventListener.java
index a34ea4ef3..6939f8d66 100644
--- a/src/api/java/baritone/api/event/listener/IGameEventListener.java
+++ b/src/api/java/baritone/api/event/listener/IGameEventListener.java
@@ -40,6 +40,14 @@ public interface IGameEventListener {
*/
void onTick(TickEvent event);
+ /**
+ * Run once per game tick after the tick is completed
+ *
+ * @param event The event
+ * @see Minecraft#runTick()
+ */
+ void onPostTick(TickEvent event);
+
/**
* Run once per game tick from before and after the player rotation is sent to the server.
*
@@ -70,6 +78,13 @@ public interface IGameEventListener {
*/
void onChunkEvent(ChunkEvent event);
+ /**
+ * Runs after a single or multi block change packet is received and processed.
+ *
+ * @param event The event
+ */
+ void onBlockChange(BlockChangeEvent event);
+
/**
* Runs once per world render pass.
*
diff --git a/src/api/java/baritone/api/pathing/goals/GoalAxis.java b/src/api/java/baritone/api/pathing/goals/GoalAxis.java
index 7c9b26705..6e2f84e7a 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalAxis.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalAxis.java
@@ -42,6 +42,16 @@ public double heuristic(int x0, int y, int z0) {
return flatAxisDistance * BaritoneAPI.getSettings().costHeuristic.value + GoalYLevel.calculate(BaritoneAPI.getSettings().axisHeight.value, y);
}
+ @Override
+ public boolean equals(Object o) {
+ 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 7cb9da14a..4bebe07a3 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.core.BlockPos;
@@ -66,6 +67,26 @@ public double heuristic(int x, int y, int z) {
return calculate(xDiff, yDiff, zDiff);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalBlock goal = (GoalBlock) o;
+ return x == goal.x
+ && y == goal.y
+ && 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 47522492b..8e13a86e4 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalComposite.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalComposite.java
@@ -67,6 +67,24 @@ public double heuristic() {
return min;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalComposite goal = (GoalComposite) o;
+ 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 8d15e4bc9..1c04f7c6d 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.core.BlockPos;
@@ -60,6 +61,26 @@ public double heuristic(int x, int y, int z) {
return GoalBlock.calculate(xDiff, yDiff < 0 ? yDiff + 1 : yDiff, zDiff);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalGetToBlock goal = (GoalGetToBlock) o;
+ return x == goal.x
+ && y == goal.y
+ && 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 354e2ce39..4a3f75315 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalInverted.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalInverted.java
@@ -17,6 +17,8 @@
package baritone.api.pathing.goals;
+import java.util.Objects;
+
/**
* Invert any goal.
*
@@ -50,6 +52,24 @@ public double heuristic() {
return Double.NEGATIVE_INFINITY;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalInverted goal = (GoalInverted) o;
+ 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 6ee35ad7b..351c08021 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;
@@ -86,6 +87,27 @@ public BlockPos getGoalPos() {
return new BlockPos(x, y, z);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalNear goal = (GoalNear) o;
+ return x == goal.x
+ && y == goal.y
+ && z == goal.z
+ && 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 3906713f2..49b6f708d 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
@@ -23,6 +23,7 @@
import net.minecraft.core.BlockPos;
import java.util.Arrays;
+import java.util.Objects;
/**
* Useful for automated combat (retreating specifically)
@@ -124,6 +125,29 @@ public double heuristic() {// TODO less hacky solution
return maxInside;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalRunAway goal = (GoalRunAway) o;
+ return distanceSq == goal.distanceSq
+ && Arrays.equals(from, goal.from)
+ && 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 c4a8a6272..6facfbd79 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.core.BlockPos;
import net.minecraft.core.Direction;
@@ -69,6 +70,31 @@ public double heuristic() {
return Double.NEGATIVE_INFINITY;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalStrictDirection goal = (GoalStrictDirection) o;
+ return x == goal.x
+ && y == goal.y
+ && z == goal.z
+ && dx == goal.dx
+ && 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 1b7213471..c9325e3ad 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.core.BlockPos;
@@ -72,6 +73,26 @@ public BlockPos getGoalPos() {
return new BlockPos(x, y, z);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalTwoBlocks goal = (GoalTwoBlocks) o;
+ return x == goal.x
+ && y == goal.y
+ && 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 f70f6c4f7..b72711283 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalXZ.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalXZ.java
@@ -64,6 +64,27 @@ public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock
return calculate(xDiff, zDiff);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalXZ goal = (GoalXZ) o;
+ 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 603ef9bd1..442906ad1 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalYLevel.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalYLevel.java
@@ -58,6 +58,24 @@ public static double calculate(int goalY, int currentY) {
return 0;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GoalYLevel goal = (GoalYLevel) o;
+ 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/process/IBuilderProcess.java b/src/api/java/baritone/api/process/IBuilderProcess.java
index 34c4394aa..347303dff 100644
--- a/src/api/java/baritone/api/process/IBuilderProcess.java
+++ b/src/api/java/baritone/api/process/IBuilderProcess.java
@@ -25,7 +25,6 @@
import java.io.File;
import java.util.List;
-import java.util.Map;
/**
* @author Brady
@@ -42,14 +41,6 @@ public interface IBuilderProcess extends IBaritoneProcess {
*/
void build(String name, ISchematic schematic, Vec3i origin);
- Vec3i getSchemSize();
-
- void popStack();
-
- boolean clearState();
-
- boolean isFromAltoclefFinished();
-
/**
* Requests a build for the specified schematic, labeled as specified, with the specified origin.
*
@@ -60,6 +51,7 @@ public interface IBuilderProcess extends IBaritoneProcess {
*/
boolean build(String name, File schematic, Vec3i origin);
+ @Deprecated
default boolean build(String schematicFile, BlockPos origin) {
File file = new File(new File(Minecraft.getInstance().gameDirectory, "schematics"), schematicFile);
return build(schematicFile, file, origin);
@@ -73,13 +65,13 @@ default boolean build(String schematicFile, BlockPos origin) {
boolean isPaused();
- void resume();
+ void popStack();
- void clearArea(BlockPos corner1, BlockPos corner2);
+ boolean isFromAltoclefFinished();
- void reset();
+ void resume();
- Map getMissing();
+ 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
@@ -87,12 +79,4 @@ default boolean build(String schematicFile, BlockPos origin) {
* cause it to give up. This is updated every tick, but only while the builder process is active.
*/
List getApproxPlaceable();
-
- boolean isFromAltoclef();
-
- void build(String name, ISchematic schematic, Vec3i origin, boolean fromAltoclef);
-
- boolean build(String name, File schematic, Vec3i origin, boolean fromAltoclef);
-
- void noteInsert(BlockPos pos);
}
diff --git a/src/api/java/baritone/api/process/ICustomGoalProcess.java b/src/api/java/baritone/api/process/ICustomGoalProcess.java
index 5084aff2f..2bae55ce3 100644
--- a/src/api/java/baritone/api/process/ICustomGoalProcess.java
+++ b/src/api/java/baritone/api/process/ICustomGoalProcess.java
@@ -38,6 +38,11 @@ public interface ICustomGoalProcess extends IBaritoneProcess {
*/
Goal getGoal();
+ /**
+ * @return The most recent set goal, which doesn't invalidate upon {@link #onLostControl()}
+ */
+ Goal mostRecentGoal();
+
/**
* Sets the goal and begins the path execution.
*
diff --git a/src/api/java/baritone/api/process/IElytraProcess.java b/src/api/java/baritone/api/process/IElytraProcess.java
new file mode 100644
index 000000000..28328f901
--- /dev/null
+++ b/src/api/java/baritone/api/process/IElytraProcess.java
@@ -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 .
+ */
+
+package baritone.api.process;
+
+import baritone.api.pathing.goals.Goal;
+import net.minecraft.core.BlockPos;
+
+public interface IElytraProcess extends IBaritoneProcess {
+
+ void repackChunks();
+
+ /**
+ * @return Where it is currently flying to, null if not active
+ */
+ BlockPos currentDestination();
+
+ void pathTo(BlockPos destination);
+
+ void pathTo(Goal destination);
+
+ /**
+ * Resets the state of the process but will maintain the same destination and will try to keep flying
+ */
+ void resetState();
+
+ /**
+ * @return {@code true} if the native library loaded and elytra is actually usable
+ */
+ boolean isLoaded();
+
+ /*
+ * FOR INTERNAL USE ONLY. MAY BE REMOVED AT ANY TIME.
+ */
+ boolean isSafeToCancel();
+}
diff --git a/src/api/java/baritone/api/process/IFarmProcess.java b/src/api/java/baritone/api/process/IFarmProcess.java
index cf63b64d3..0c07567de 100644
--- a/src/api/java/baritone/api/process/IFarmProcess.java
+++ b/src/api/java/baritone/api/process/IFarmProcess.java
@@ -33,9 +33,7 @@ public interface IFarmProcess extends IBaritoneProcess {
/**
* Begin to search for nearby crops to farm.
*/
- default void farm() {
- farm(0, null);
- }
+ default void farm() {farm(0, null);}
/**
* Begin to search for crops to farm with in specified aria
@@ -43,7 +41,5 @@ default void farm() {
*
* @param range The distance to search for crops to farm
*/
- default void farm(int range) {
- farm(range, null);
- }
+ default void farm(int range) {farm(range, null);}
}
diff --git a/src/api/java/baritone/api/process/IFollowProcess.java b/src/api/java/baritone/api/process/IFollowProcess.java
index b9eedee30..6f7f0a239 100644
--- a/src/api/java/baritone/api/process/IFollowProcess.java
+++ b/src/api/java/baritone/api/process/IFollowProcess.java
@@ -17,10 +17,9 @@
package baritone.api.process;
-import net.minecraft.world.entity.Entity;
-
import java.util.List;
import java.util.function.Predicate;
+import net.minecraft.world.entity.Entity;
/**
* @author Brady
diff --git a/src/api/java/baritone/api/process/IMineProcess.java b/src/api/java/baritone/api/process/IMineProcess.java
index 1331e3dde..a63eb00a2 100644
--- a/src/api/java/baritone/api/process/IMineProcess.java
+++ b/src/api/java/baritone/api/process/IMineProcess.java
@@ -19,9 +19,8 @@
import baritone.api.utils.BlockOptionalMeta;
import baritone.api.utils.BlockOptionalMetaLookup;
-import net.minecraft.world.level.block.Block;
-
import java.util.stream.Stream;
+import net.minecraft.world.level.block.Block;
/**
* @author Brady
diff --git a/src/api/java/baritone/api/process/PathingCommandType.java b/src/api/java/baritone/api/process/PathingCommandType.java
index af25591af..cde38eaf2 100644
--- a/src/api/java/baritone/api/process/PathingCommandType.java
+++ b/src/api/java/baritone/api/process/PathingCommandType.java
@@ -56,5 +56,10 @@ public enum PathingCommandType {
/**
* Go and ask the next process what to do
*/
- DEFER
+ DEFER,
+
+ /**
+ * Sets the goal and calculates a path, but pauses instead of immediately starting the path.
+ */
+ SET_GOAL_AND_PAUSE
}
diff --git a/src/api/java/baritone/api/schematic/CompositeSchematic.java b/src/api/java/baritone/api/schematic/CompositeSchematic.java
index 62faa8bf2..0724ec018 100644
--- a/src/api/java/baritone/api/schematic/CompositeSchematic.java
+++ b/src/api/java/baritone/api/schematic/CompositeSchematic.java
@@ -17,10 +17,9 @@
package baritone.api.schematic;
-import net.minecraft.world.level.block.state.BlockState;
-
import java.util.ArrayList;
import java.util.List;
+import net.minecraft.world.level.block.state.BlockState;
public class CompositeSchematic extends AbstractSchematic {
diff --git a/src/api/java/baritone/api/schematic/FillSchematic.java b/src/api/java/baritone/api/schematic/FillSchematic.java
index d79374fc3..126501987 100644
--- a/src/api/java/baritone/api/schematic/FillSchematic.java
+++ b/src/api/java/baritone/api/schematic/FillSchematic.java
@@ -18,6 +18,7 @@
package baritone.api.schematic;
import baritone.api.utils.BlockOptionalMeta;
+import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import java.util.List;
diff --git a/src/api/java/baritone/api/schematic/ISchematic.java b/src/api/java/baritone/api/schematic/ISchematic.java
index 362d246f7..bc7c35a15 100644
--- a/src/api/java/baritone/api/schematic/ISchematic.java
+++ b/src/api/java/baritone/api/schematic/ISchematic.java
@@ -17,11 +17,10 @@
package baritone.api.schematic;
+import java.util.List;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
-import java.util.List;
-
/**
* Basic representation of a schematic. Provides the dimensions and the desired state for a given position relative to
* the origin.
@@ -76,8 +75,7 @@ default int size(Direction.Axis axis) {
/**
* Resets possible caches to avoid wrong behavior when moving the schematic around
*/
- default void reset() {
- }
+ default void reset() {}
/**
* @return The width (X axis length) of this schematic
diff --git a/src/api/java/baritone/api/schematic/MaskSchematic.java b/src/api/java/baritone/api/schematic/MaskSchematic.java
index 954d7973c..a5749ff57 100644
--- a/src/api/java/baritone/api/schematic/MaskSchematic.java
+++ b/src/api/java/baritone/api/schematic/MaskSchematic.java
@@ -17,6 +17,7 @@
package baritone.api.schematic;
+import baritone.api.schematic.mask.Mask;
import net.minecraft.world.level.block.state.BlockState;
import java.util.List;
@@ -41,4 +42,14 @@ public boolean inSchematic(int x, int y, int z, BlockState currentState) {
public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) {
return schematic.desiredState(x, y, z, current, approxPlaceable);
}
+
+ public static MaskSchematic create(ISchematic schematic, Mask function) {
+ return new MaskSchematic(schematic) {
+
+ @Override
+ protected boolean partOfMask(int x, int y, int z, BlockState currentState) {
+ return function.partOfMask(x, y, z, currentState);
+ }
+ };
+ }
}
diff --git a/src/api/java/baritone/api/schematic/SubstituteSchematic.java b/src/api/java/baritone/api/schematic/SubstituteSchematic.java
index 1e7d99db0..96baa38da 100644
--- a/src/api/java/baritone/api/schematic/SubstituteSchematic.java
+++ b/src/api/java/baritone/api/schematic/SubstituteSchematic.java
@@ -84,6 +84,7 @@ private BlockState withBlock(BlockState state, Block block) {
blockStateCache.computeIfAbsent(state, s -> new HashMap()).put(block, newState);
return newState;
}
+
private > BlockState copySingleProp(BlockState fromState, BlockState toState, Property prop) {
return toState.setValue(prop, fromState.getValue(prop));
}
diff --git a/src/api/java/baritone/api/schematic/mask/AbstractMask.java b/src/api/java/baritone/api/schematic/mask/AbstractMask.java
new file mode 100644
index 000000000..ce92af0ec
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/AbstractMask.java
@@ -0,0 +1,49 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.schematic.mask;
+
+/**
+ * @author Brady
+ */
+public abstract class AbstractMask implements Mask {
+
+ private final int widthX;
+ private final int heightY;
+ private final int lengthZ;
+
+ public AbstractMask(int widthX, int heightY, int lengthZ) {
+ this.widthX = widthX;
+ this.heightY = heightY;
+ this.lengthZ = lengthZ;
+ }
+
+ @Override
+ public int widthX() {
+ return this.widthX;
+ }
+
+ @Override
+ public int heightY() {
+ return this.heightY;
+ }
+
+ @Override
+ public int lengthZ() {
+ return this.lengthZ;
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/Mask.java b/src/api/java/baritone/api/schematic/mask/Mask.java
new file mode 100644
index 000000000..c8b1f15a1
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/Mask.java
@@ -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 .
+ */
+
+package baritone.api.schematic.mask;
+
+import baritone.api.schematic.mask.operator.BinaryOperatorMask;
+import baritone.api.schematic.mask.operator.NotMask;
+import baritone.api.utils.BooleanBinaryOperators;
+import net.minecraft.world.level.block.state.BlockState;
+
+/**
+ * @author Brady
+ */
+public interface Mask {
+
+ /**
+ * @param x The relative x position of the block
+ * @param y The relative y position of the block
+ * @param z The relative z position of the block
+ * @param currentState The current state of that block in the world, may be {@code null}
+ * @return Whether the given position is included in this mask
+ */
+ boolean partOfMask(int x, int y, int z, BlockState currentState);
+
+ int widthX();
+
+ int heightY();
+
+ int lengthZ();
+
+ default Mask not() {
+ return new NotMask(this);
+ }
+
+ default Mask union(Mask other) {
+ return new BinaryOperatorMask(this, other, BooleanBinaryOperators.OR);
+ }
+
+ default Mask intersection(Mask other) {
+ return new BinaryOperatorMask(this, other, BooleanBinaryOperators.AND);
+ }
+
+ default Mask xor(Mask other) {
+ return new BinaryOperatorMask(this, other, BooleanBinaryOperators.XOR);
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/PreComputedMask.java b/src/api/java/baritone/api/schematic/mask/PreComputedMask.java
new file mode 100644
index 000000000..aed26cc94
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/PreComputedMask.java
@@ -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 .
+ */
+
+package baritone.api.schematic.mask;
+
+/**
+ * @author Brady
+ */
+final class PreComputedMask extends AbstractMask implements StaticMask {
+
+ private final boolean[][][] mask;
+
+ public PreComputedMask(StaticMask mask) {
+ super(mask.widthX(), mask.heightY(), mask.lengthZ());
+
+ this.mask = new boolean[this.heightY()][this.lengthZ()][this.widthX()];
+ for (int y = 0; y < this.heightY(); y++) {
+ for (int z = 0; z < this.lengthZ(); z++) {
+ for (int x = 0; x < this.widthX(); x++) {
+ this.mask[y][z][x] = mask.partOfMask(x, y, z);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ return this.mask[y][z][x];
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/StaticMask.java b/src/api/java/baritone/api/schematic/mask/StaticMask.java
new file mode 100644
index 000000000..9925ffca2
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/StaticMask.java
@@ -0,0 +1,82 @@
+/*
+ * 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.schematic.mask;
+
+import baritone.api.schematic.mask.operator.BinaryOperatorMask;
+import baritone.api.schematic.mask.operator.NotMask;
+import baritone.api.utils.BooleanBinaryOperators;
+import net.minecraft.world.level.block.state.BlockState;
+
+/**
+ * A mask that is context-free. In other words, it doesn't require the current block state to determine if a relative
+ * position is a part of the mask.
+ *
+ * @author Brady
+ */
+public interface StaticMask extends Mask {
+
+ /**
+ * Determines if a given relative coordinate is included in this mask, without the need for the current block state.
+ *
+ * @param x The relative x position of the block
+ * @param y The relative y position of the block
+ * @param z The relative z position of the block
+ * @return Whether the given position is included in this mask
+ */
+ boolean partOfMask(int x, int y, int z);
+
+ /**
+ * Implements the parent {@link Mask#partOfMask partOfMask function} by calling the static function
+ * provided in this functional interface without needing the {@link BlockState} argument. This {@code default}
+ * implementation should NOT be overriden.
+ *
+ * @param x The relative x position of the block
+ * @param y The relative y position of the block
+ * @param z The relative z position of the block
+ * @param currentState The current state of that block in the world, may be {@code null}
+ * @return Whether the given position is included in this mask
+ */
+ @Override
+ default boolean partOfMask(int x, int y, int z, BlockState currentState) {
+ return this.partOfMask(x, y, z);
+ }
+
+ @Override
+ default StaticMask not() {
+ return new NotMask.Static(this);
+ }
+
+ default StaticMask union(StaticMask other) {
+ return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.OR);
+ }
+
+ default StaticMask intersection(StaticMask other) {
+ return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.AND);
+ }
+
+ default StaticMask xor(StaticMask other) {
+ return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.XOR);
+ }
+
+ /**
+ * Returns a pre-computed mask using {@code this} function, with the specified size parameters.
+ */
+ default StaticMask compute() {
+ return new PreComputedMask(this);
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java b/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java
new file mode 100644
index 000000000..08975e521
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java
@@ -0,0 +1,79 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.schematic.mask.operator;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.Mask;
+import baritone.api.schematic.mask.StaticMask;
+import baritone.api.utils.BooleanBinaryOperator;
+import net.minecraft.world.level.block.state.BlockState;
+
+/**
+ * @author Brady
+ */
+public final class BinaryOperatorMask extends AbstractMask {
+
+ private final Mask a;
+ private final Mask b;
+ private final BooleanBinaryOperator operator;
+
+ public BinaryOperatorMask(Mask a, Mask b, BooleanBinaryOperator operator) {
+ 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;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z, BlockState currentState) {
+ return this.operator.applyAsBoolean(
+ partOfMask(a, x, y, z, currentState),
+ partOfMask(b, x, y, z, currentState)
+ );
+ }
+
+ private static boolean partOfMask(Mask mask, int x, int y, int z, BlockState 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;
+ private final StaticMask b;
+ private final BooleanBinaryOperator operator;
+
+ public Static(StaticMask a, StaticMask b, BooleanBinaryOperator operator) {
+ 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;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ return this.operator.applyAsBoolean(
+ 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/operator/NotMask.java b/src/api/java/baritone/api/schematic/mask/operator/NotMask.java
new file mode 100644
index 000000000..9d0dfcd6d
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/operator/NotMask.java
@@ -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 .
+ */
+
+package baritone.api.schematic.mask.operator;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.Mask;
+import baritone.api.schematic.mask.StaticMask;
+import net.minecraft.world.level.block.state.BlockState;
+
+/**
+ * @author Brady
+ */
+public final class NotMask extends AbstractMask {
+
+ private final Mask source;
+
+ public NotMask(Mask source) {
+ super(source.widthX(), source.heightY(), source.lengthZ());
+ this.source = source;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z, BlockState currentState) {
+ return !this.source.partOfMask(x, y, z, currentState);
+ }
+
+ public static final class Static extends AbstractMask implements StaticMask {
+
+ private final StaticMask source;
+
+ public Static(StaticMask source) {
+ super(source.widthX(), source.heightY(), source.lengthZ());
+ this.source = source;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ return !this.source.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
new file mode 100644
index 000000000..093a27e38
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java
@@ -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 .
+ */
+
+package baritone.api.schematic.mask.shape;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.StaticMask;
+import net.minecraft.core.Direction;
+
+/**
+ * @author Brady
+ */
+public final class CylinderMask extends AbstractMask implements StaticMask {
+
+ private final double centerA;
+ private final double centerB;
+ private final double radiusSqA;
+ private final double radiusSqB;
+ private final boolean filled;
+ private final Direction.Axis alignment;
+
+ public CylinderMask(int widthX, int heightY, int lengthZ, boolean filled, Direction.Axis alignment) {
+ super(widthX, heightY, lengthZ);
+ 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;
+ this.alignment = alignment;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ 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;
+ }
+ return this.filled
+ || this.outside(da + 1, db)
+ || this.outside(da, db + 1);
+ }
+
+ private boolean outside(double da, double db) {
+ return da * da / this.radiusSqA + db * db / this.radiusSqB > 1;
+ }
+
+ private static int getA(int x, int y, Direction.Axis alignment) {
+ return alignment == Direction.Axis.X ? y : x;
+ }
+
+ private static int getB(int y, int z, Direction.Axis alignment) {
+ return alignment == Direction.Axis.Z ? y : z;
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/shape/SphereMask.java b/src/api/java/baritone/api/schematic/mask/shape/SphereMask.java
new file mode 100644
index 000000000..d805c98a8
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/shape/SphereMask.java
@@ -0,0 +1,64 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.schematic.mask.shape;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.StaticMask;
+
+/**
+ * @author Brady
+ */
+public final class SphereMask extends AbstractMask implements StaticMask {
+
+ private final double centerX;
+ private final double centerY;
+ private final double centerZ;
+ private final double radiusSqX;
+ private final double radiusSqY;
+ private final double radiusSqZ;
+ private final boolean filled;
+
+ public SphereMask(int widthX, int heightY, int lengthZ, boolean filled) {
+ super(widthX, heightY, lengthZ);
+ this.centerX = widthX / 2.0;
+ this.centerY = heightY / 2.0;
+ this.centerZ = lengthZ / 2.0;
+ this.radiusSqX = this.centerX * this.centerX;
+ this.radiusSqY = this.centerY * this.centerY;
+ this.radiusSqZ = this.centerZ * this.centerZ;
+ this.filled = filled;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ double dx = Math.abs((x + 0.5) - this.centerX);
+ double dy = Math.abs((y + 0.5) - this.centerY);
+ double dz = Math.abs((z + 0.5) - this.centerZ);
+ if (this.outside(dx, dy, dz)) {
+ return false;
+ }
+ return this.filled
+ || this.outside(dx + 1, dy, dz)
+ || this.outside(dx, dy + 1, dz)
+ || this.outside(dx, dy, dz + 1);
+ }
+
+ private boolean outside(double dx, double dy, double dz) {
+ return dx * dx / this.radiusSqX + dy * dy / this.radiusSqY + dz * dz / this.radiusSqZ > 1;
+ }
+}
diff --git a/src/api/java/baritone/api/utils/BetterBlockPos.java b/src/api/java/baritone/api/utils/BetterBlockPos.java
index 676398887..5add76555 100644
--- a/src/api/java/baritone/api/utils/BetterBlockPos.java
+++ b/src/api/java/baritone/api/utils/BetterBlockPos.java
@@ -17,13 +17,12 @@
package baritone.api.utils;
+import javax.annotation.Nonnull;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.util.Mth;
-import javax.annotation.Nonnull;
-
/**
* A better BlockPos that has fewer hash collisions (and slightly more performant offsets)
*
@@ -35,6 +34,15 @@
*/
public final class BetterBlockPos extends BlockPos {
+ private static final int NUM_X_BITS = 26;
+ private static final int NUM_Z_BITS = NUM_X_BITS;
+ private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS;
+ private static final int Y_SHIFT = NUM_Z_BITS;
+ private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS;
+ private static final long X_MASK = (1L << NUM_X_BITS) - 1L;
+ private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L;
+ private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
+
public static final BetterBlockPos ORIGIN = new BetterBlockPos(0, 0, 0);
public final int x;
@@ -202,6 +210,20 @@ public BetterBlockPos west(int amt) {
return amt == 0 ? this : new BetterBlockPos(x - amt, y, z);
}
+ public double distanceSq(final BetterBlockPos to) {
+ double dx = (double) this.x - to.x;
+ double dy = (double) this.y - to.y;
+ double dz = (double) this.z - to.z;
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ public double distanceTo(final BetterBlockPos to) {
+ double dx = (double) this.x - to.x;
+ double dy = (double) this.y - to.y;
+ double dz = (double) this.z - to.z;
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
+ }
+
@Override
@Nonnull
public String toString() {
@@ -212,4 +234,15 @@ public String toString() {
SettingsUtil.maybeCensor(z)
);
}
+
+ public static long serializeToLong(final int x, final int y, final int z) {
+ return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK);
+ }
+
+ public static BetterBlockPos deserializeFromLong(final long serialized) {
+ final int x = (int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS);
+ final int y = (int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS);
+ final int z = (int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS);
+ return new BetterBlockPos(x, y, z);
+ }
}
diff --git a/src/api/java/baritone/api/utils/BlockOptionalMeta.java b/src/api/java/baritone/api/utils/BlockOptionalMeta.java
index fe549375a..ac14d0187 100644
--- a/src/api/java/baritone/api/utils/BlockOptionalMeta.java
+++ b/src/api/java/baritone/api/utils/BlockOptionalMeta.java
@@ -18,6 +18,7 @@
package baritone.api.utils;
import baritone.api.utils.accessor.IItemStack;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import io.netty.util.concurrent.ThreadPerTaskExecutor;
import net.minecraft.client.Minecraft;
@@ -32,8 +33,8 @@
import net.minecraft.server.packs.repository.ServerPacksSource;
import net.minecraft.server.packs.resources.MultiPackResourceManager;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
-import net.minecraft.util.RandomSource;
import net.minecraft.util.Unit;
+import net.minecraft.world.RandomSequences;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@@ -41,63 +42,99 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.ServerLevelData;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootContext;
-import net.minecraft.world.level.storage.loot.LootTables;
-import net.minecraft.world.level.storage.loot.PredicateManager;
+import net.minecraft.world.level.storage.loot.LootDataManager;
+import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.Vec3;
import sun.misc.Unsafe;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
-import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public final class BlockOptionalMeta {
+ // id or id[] or id[properties] where id and properties are any text with at least one character
+ private static final Pattern PATTERN = Pattern.compile("^(?.+?)(?:\\[(?.+?)?\\])?$");
private final Block block;
+ private final String propertiesDescription; // exists so toString() can return something more useful than a list of all blockstates
private final Set blockstates;
private final ImmutableSet stateHashes;
private final ImmutableSet stackHashes;
- private static final Pattern pattern = Pattern.compile("^(.+?)(?::(\\d+))?$");
- private static LootTables lootTables;
- private static PredicateManager predicate = new PredicateManager();
+ private static LootDataManager lootTables;
private static Map> drops = new HashMap<>();
public BlockOptionalMeta(@Nonnull Block block) {
this.block = block;
- this.blockstates = getStates(block);
+ this.propertiesDescription = "{}";
+ this.blockstates = getStates(block, Collections.emptyMap());
this.stateHashes = getStateHashes(blockstates);
this.stackHashes = getStackHashes(blockstates);
}
public BlockOptionalMeta(@Nonnull String selector) {
- Matcher matcher = pattern.matcher(selector);
+ Matcher matcher = PATTERN.matcher(selector);
if (!matcher.find()) {
throw new IllegalArgumentException("invalid block selector");
}
- MatchResult matchResult = matcher.toMatchResult();
+ block = BlockUtils.stringToBlockRequired(matcher.group("id"));
- block = BlockUtils.stringToBlockRequired(matchResult.group(1));
- blockstates = getStates(block);
+ String props = matcher.group("properties");
+ Map, ?> properties = props == null || props.equals("") ? Collections.emptyMap() : parseProperties(block, props);
+
+ propertiesDescription = props == null ? "{}" : "{" + props.replace("=", ":") + "}";
+ blockstates = getStates(block, properties);
stateHashes = getStateHashes(blockstates);
stackHashes = getStackHashes(blockstates);
}
- private static Set getStates(@Nonnull Block block) {
- return new HashSet<>(block.getStateDefinition().getPossibleStates());
+ private static , P extends Property> P castToIProperty(Object value) {
+ //noinspection unchecked
+ return (P) value;
+ }
+
+ private static Map, ?> parseProperties(Block block, String raw) {
+ ImmutableMap.Builder, Object> builder = ImmutableMap.builder();
+ for (String pair : raw.split(",")) {
+ String[] parts = pair.split("=");
+ if (parts.length != 2) {
+ throw new IllegalArgumentException(String.format("\"%s\" is not a valid property-value pair", pair));
+ }
+ String rawKey = parts[0];
+ String rawValue = parts[1];
+ Property> key = block.getStateDefinition().getProperty(rawKey);
+ Comparable> value = castToIProperty(key).getValue(rawValue)
+ .orElseThrow(() -> new IllegalArgumentException(String.format(
+ "\"%s\" is not a valid value for %s on %s",
+ rawValue, key, block
+ )));
+ builder.put(key, value);
+ }
+ return builder.build();
+ }
+
+ private static Set getStates(@Nonnull Block block, @Nonnull Map, ?> properties) {
+ return block.getStateDefinition().getPossibleStates().stream()
+ .filter(blockstate -> properties.entrySet().stream().allMatch(entry ->
+ blockstate.getValue(entry.getKey()) == entry.getValue()
+ ))
+ .collect(Collectors.toSet());
}
private static ImmutableSet getStateHashes(Set blockstates) {
@@ -145,7 +182,23 @@ public boolean matches(ItemStack stack) {
@Override
public String toString() {
- return String.format("BlockOptionalMeta{block=%s}", block);
+ return String.format("BlockOptionalMeta{block=%s,properties=%s}", block, propertiesDescription);
+ }
+
+ public BlockState getAnyBlockState() {
+ if (blockstates.size() > 0) {
+ return blockstates.iterator().next();
+ }
+
+ return null;
+ }
+
+ public Set getAllBlockStates() {
+ return blockstates;
+ }
+
+ public Set stackHashes() {
+ return stackHashes;
}
private static Method getVanillaServerPack;
@@ -165,11 +218,11 @@ private static VanillaPackResources getVanillaServerPack() {
return null;
}
- public static LootTables getManager() {
+ public static LootDataManager getManager() {
if (lootTables == null) {
MultiPackResourceManager resources = new MultiPackResourceManager(PackType.SERVER_DATA, List.of(getVanillaServerPack()));
ReloadableResourceManager resourceManager = new ReloadableResourceManager(PackType.SERVER_DATA);
- lootTables = new LootTables(predicate);
+ lootTables = new LootDataManager();
resourceManager.registerReloadListener(lootTables);
try {
resourceManager.createReload(new ThreadPerTaskExecutor(Thread::new), new ThreadPerTaskExecutor(Thread::new), CompletableFuture.completedFuture(Unit.INSTANCE), resources.listPacks().toList()).done().get();
@@ -189,14 +242,17 @@ private static synchronized List- drops(Block b) {
} else {
List
- items = new ArrayList<>();
try {
- getManager().get(lootTableLocation).getRandomItems(
- new LootContext.Builder(ServerLevelStub.fastCreate())
- .withRandom(RandomSource.create())
- .withParameter(LootContextParams.ORIGIN, Vec3.atLowerCornerOf(BlockPos.ZERO))
- .withParameter(LootContextParams.TOOL, ItemStack.EMPTY)
- .withOptionalParameter(LootContextParams.BLOCK_ENTITY, null)
- .withParameter(LootContextParams.BLOCK_STATE, block.defaultBlockState())
- .create(LootContextParamSets.BLOCK),
+
+ getManager().getLootTable(lootTableLocation).getRandomItemsRaw(
+ new LootContext.Builder(
+ new LootParams.Builder(ServerLevelStub.fastCreate())
+ .withParameter(LootContextParams.ORIGIN, Vec3.atLowerCornerOf(BlockPos.ZERO))
+ .withParameter(LootContextParams.TOOL, ItemStack.EMPTY)
+ .withOptionalParameter(LootContextParams.BLOCK_ENTITY, null)
+ .withParameter(LootContextParams.BLOCK_STATE, block.defaultBlockState())
+ .create(LootContextParamSets.BLOCK)
+ ).withOptionalRandomSeed(1L)
+ .create(null),
stack -> items.add(stack.getItem())
);
} catch (Exception e) {
@@ -207,24 +263,18 @@ private static synchronized List
- drops(Block b) {
});
}
- public static PredicateManager getPredicateManager() {
- return predicate;
- }
-
- public BlockState getAnyBlockState() {
- if (blockstates.size() > 0) {
- return blockstates.iterator().next();
- }
-
- return null;
- }
-
private static class ServerLevelStub extends ServerLevel {
private static Minecraft client = Minecraft.getInstance();
private static Unsafe unsafe = getUnsafe();
- public ServerLevelStub(MinecraftServer $$0, Executor $$1, LevelStorageSource.LevelStorageAccess $$2, ServerLevelData $$3, ResourceKey $$4, LevelStem $$5, ChunkProgressListener $$6, boolean $$7, long $$8, List $$9, boolean $$10) {
- super($$0, $$1, $$2, $$3, $$4, $$5, $$6, $$7, $$8, $$9, $$10);
+ public ServerLevelStub(MinecraftServer $$0, Executor $$1, LevelStorageSource.LevelStorageAccess $$2, ServerLevelData $$3, ResourceKey $$4, LevelStem $$5, ChunkProgressListener $$6, boolean $$7, long $$8, List $$9, boolean $$10, @Nullable RandomSequences $$11) {
+ super($$0, $$1, $$2, $$3, $$4, $$5, $$6, $$7, $$8, $$9, $$10, $$11);
+ }
+
+ @Override
+ public FeatureFlagSet enabledFeatures() {
+ assert client.level != null;
+ return client.level.enabledFeatures();
}
public static ServerLevelStub fastCreate() {
@@ -245,11 +295,5 @@ public static Unsafe getUnsafe() {
}
}
- @Override
- public FeatureFlagSet enabledFeatures() {
- assert client.level != null;
- return client.level.enabledFeatures();
- }
-
}
}
diff --git a/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java
index 86d19ff5e..7ab01cc87 100644
--- a/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java
+++ b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java
@@ -17,68 +17,70 @@
package baritone.api.utils;
+import baritone.api.utils.accessor.IItemStack;
+import com.google.common.collect.ImmutableSet;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.stream.Stream;
public class BlockOptionalMetaLookup {
-
+ private final ImmutableSet blockSet;
+ private final ImmutableSet blockStateSet;
+ private final ImmutableSet stackHashes;
private final BlockOptionalMeta[] boms;
public BlockOptionalMetaLookup(BlockOptionalMeta... boms) {
this.boms = boms;
+ Set blocks = new HashSet<>();
+ Set blockStates = new HashSet<>();
+ Set stacks = new HashSet<>();
+ for (BlockOptionalMeta bom : boms) {
+ blocks.add(bom.getBlock());
+ blockStates.addAll(bom.getAllBlockStates());
+ stacks.addAll(bom.stackHashes());
+ }
+ this.blockSet = ImmutableSet.copyOf(blocks);
+ this.blockStateSet = ImmutableSet.copyOf(blockStates);
+ this.stackHashes = ImmutableSet.copyOf(stacks);
}
public BlockOptionalMetaLookup(Block... blocks) {
- this.boms = Stream.of(blocks)
+ this(Stream.of(blocks)
.map(BlockOptionalMeta::new)
- .toArray(BlockOptionalMeta[]::new);
+ .toArray(BlockOptionalMeta[]::new));
+
}
public BlockOptionalMetaLookup(List blocks) {
- this.boms = blocks.stream()
+ this(blocks.stream()
.map(BlockOptionalMeta::new)
- .toArray(BlockOptionalMeta[]::new);
+ .toArray(BlockOptionalMeta[]::new));
}
public BlockOptionalMetaLookup(String... blocks) {
- this.boms = Stream.of(blocks)
+ this(Stream.of(blocks)
.map(BlockOptionalMeta::new)
- .toArray(BlockOptionalMeta[]::new);
+ .toArray(BlockOptionalMeta[]::new));
}
public boolean has(Block block) {
- for (BlockOptionalMeta bom : boms) {
- if (bom.getBlock() == block) {
- return true;
- }
- }
-
- return false;
+ return blockSet.contains(block);
}
public boolean has(BlockState state) {
- for (BlockOptionalMeta bom : boms) {
- if (bom.matches(state)) {
- return true;
- }
- }
-
- return false;
+ return blockStateSet.contains(state);
}
public boolean has(ItemStack stack) {
- for (BlockOptionalMeta bom : boms) {
- if (bom.matches(stack)) {
- return true;
- }
- }
-
- return false;
+ int hash = ((IItemStack) (Object) stack).getBaritoneHash();
+ hash -= stack.getDamageValue();
+ return stackHashes.contains(hash);
}
public List blocks() {
diff --git a/src/api/java/baritone/api/utils/BlockUtils.java b/src/api/java/baritone/api/utils/BlockUtils.java
index d2132f9a5..a43d78e87 100644
--- a/src/api/java/baritone/api/utils/BlockUtils.java
+++ b/src/api/java/baritone/api/utils/BlockUtils.java
@@ -17,13 +17,13 @@
package baritone.api.utils;
+import java.util.HashMap;
+import java.util.Map;
+import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
-import java.util.HashMap;
-import java.util.Map;
-
public class BlockUtils {
private static transient Map resourceCache = new HashMap<>();
@@ -64,6 +64,5 @@ public static Block stringToBlockNullable(String name) {
return block;
}
- private BlockUtils() {
- }
+ private BlockUtils() {}
}
diff --git a/src/api/java/baritone/api/utils/BooleanBinaryOperator.java b/src/api/java/baritone/api/utils/BooleanBinaryOperator.java
new file mode 100644
index 000000000..cfb85e644
--- /dev/null
+++ b/src/api/java/baritone/api/utils/BooleanBinaryOperator.java
@@ -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 .
+ */
+
+package baritone.api.utils;
+
+/**
+ * @author Brady
+ */
+@FunctionalInterface
+public interface BooleanBinaryOperator {
+
+ boolean applyAsBoolean(boolean a, boolean b);
+}
diff --git a/src/api/java/baritone/api/utils/BooleanBinaryOperators.java b/src/api/java/baritone/api/utils/BooleanBinaryOperators.java
new file mode 100644
index 000000000..11605c965
--- /dev/null
+++ b/src/api/java/baritone/api/utils/BooleanBinaryOperators.java
@@ -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 .
+ */
+
+package baritone.api.utils;
+
+/**
+ * @author Brady
+ */
+public enum BooleanBinaryOperators implements BooleanBinaryOperator {
+ OR((a, b) -> a || b),
+ AND((a, b) -> a && b),
+ XOR((a, b) -> a ^ b);
+
+ private final BooleanBinaryOperator op;
+
+ BooleanBinaryOperators(BooleanBinaryOperator op) {
+ this.op = op;
+ }
+
+ @Override
+ public boolean applyAsBoolean(boolean a, boolean b) {
+ return this.op.applyAsBoolean(a, b);
+ }
+}
diff --git a/src/api/java/baritone/api/utils/Helper.java b/src/api/java/baritone/api/utils/Helper.java
index 2e1830c02..507cd85a7 100755
--- a/src/api/java/baritone/api/utils/Helper.java
+++ b/src/api/java/baritone/api/utils/Helper.java
@@ -18,7 +18,9 @@
package baritone.api.utils;
import baritone.api.BaritoneAPI;
+import baritone.api.Settings;
import net.minecraft.ChatFormatting;
+import net.minecraft.client.GuiMessageTag;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
@@ -39,14 +41,20 @@ public interface Helper {
/**
* Instance of {@link Helper}. Used for static-context reference.
*/
- Helper HELPER = new Helper() {
- };
+ Helper HELPER = new Helper() {};
/**
- * Instance of the game
+ * The main game instance returned by {@link Minecraft#getInstance()}.
+ * Deprecated since {@link IPlayerContext#minecraft()} should be used instead (In the majority of cases).
*/
+ @Deprecated
Minecraft mc = Minecraft.getInstance();
+ /**
+ * The tag to assign to chat messages when {@link Settings#useMessageTag} is {@code true}.
+ */
+ GuiMessageTag MESSAGE_TAG = new GuiMessageTag(0xFF55FF, null, Component.literal("Baritone message."), "Baritone");
+
static Component getPrefix() {
// Inner text component
final Calendar now = Calendar.getInstance();
@@ -71,7 +79,7 @@ static Component getPrefix() {
* @param message The message to display in the popup
*/
default void logToast(Component title, Component message) {
- mc.execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message));
+ Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message));
}
/**
@@ -132,7 +140,7 @@ default void logNotificationDirect(String message) {
* @param error Whether to log as an error
*/
default void logNotificationDirect(String message, boolean error) {
- mc.execute(() -> BaritoneAPI.getSettings().notifier.value.accept(message, error));
+ Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().notifier.value.accept(message, error));
}
/**
@@ -159,13 +167,15 @@ default void logDebug(String message) {
*/
default void logDirect(boolean logAsToast, Component... components) {
MutableComponent component = Component.literal("");
- component.append(getPrefix());
- component.append(Component.literal(" "));
+ if (!logAsToast && !BaritoneAPI.getSettings().useMessageTag.value) {
+ component.append(getPrefix());
+ component.append(Component.literal(" "));
+ }
Arrays.asList(components).forEach(component::append);
if (logAsToast) {
logToast(getPrefix(), component);
} else {
- mc.execute(() -> BaritoneAPI.getSettings().logger.value.accept(component));
+ Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().logger.value.accept(component));
}
}
@@ -225,4 +235,11 @@ default void logDirect(String message, boolean logAsToast) {
default void logDirect(String message) {
logDirect(message, BaritoneAPI.getSettings().logAsToast.value);
}
+
+ default void logUnhandledException(final Throwable exception) {
+ HELPER.logDirect("An unhandled exception occurred. " +
+ "The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
+ ChatFormatting.RED);
+ exception.printStackTrace();
+ }
}
diff --git a/src/api/java/baritone/api/utils/IPlayerContext.java b/src/api/java/baritone/api/utils/IPlayerContext.java
index 32e331544..a97475a5b 100644
--- a/src/api/java/baritone/api/utils/IPlayerContext.java
+++ b/src/api/java/baritone/api/utils/IPlayerContext.java
@@ -18,6 +18,7 @@
package baritone.api.utils;
import baritone.api.cache.IWorldData;
+import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
@@ -38,11 +39,11 @@
*/
public interface IPlayerContext {
+ Minecraft minecraft();
+
LocalPlayer player();
- static double eyeHeight(boolean ifSneaking) {
- return ifSneaking ? 1.27 : 1.62;
- }
+ IPlayerController playerController();
Level world();
@@ -54,7 +55,8 @@ default Stream entitiesStream() {
return StreamSupport.stream(entities().spliterator(), false);
}
- IPlayerController playerController();
+
+ IWorldData worldData();
HitResult objectMouseOver();
@@ -74,8 +76,7 @@ default BetterBlockPos playerFeet() {
if (world().getBlockState(feet).getBlock() instanceof SlabBlock) {
return feet.above();
}
- } catch (NullPointerException ignored) {
- }
+ } catch (NullPointerException ignored) {}
return feet;
}
@@ -88,11 +89,19 @@ default Vec3 playerHead() {
return new Vec3(player().position().x, player().position().y + player().getEyeHeight(), player().position().z);
}
+ default Vec3 playerMotion() {
+ return player().getDeltaMovement();
+ }
+
+ BetterBlockPos viewerPos();
+
default Rotation playerRotations() {
return new Rotation(player().getYRot(), player().getXRot());
}
- IWorldData worldData();
+ static double eyeHeight(boolean ifSneaking) {
+ return ifSneaking ? 1.27 : 1.62;
+ }
/**
* Returns the block that the crosshair is currently placed over. Updated once per tick.
diff --git a/src/api/java/baritone/api/utils/Pair.java b/src/api/java/baritone/api/utils/Pair.java
new file mode 100644
index 000000000..ca7259520
--- /dev/null
+++ b/src/api/java/baritone/api/utils/Pair.java
@@ -0,0 +1,59 @@
+/*
+ * 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.utils;
+
+import java.util.Objects;
+
+/**
+ * @author Brady
+ */
+public final class Pair {
+
+ private final A a;
+ private final B b;
+
+ public Pair(A a, B b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ public A first() {
+ return this.a;
+ }
+
+ public B second() {
+ return this.b;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || o.getClass() != Pair.class) {
+ return false;
+ }
+ Pair, ?> pair = (Pair, ?>) o;
+ return Objects.equals(this.a, pair.a) && Objects.equals(this.b, pair.b);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * Objects.hashCode(this.a) + Objects.hashCode(this.b);
+ }
+}
diff --git a/src/api/java/baritone/api/utils/RandomSpotNearby.java b/src/api/java/baritone/api/utils/RandomSpotNearby.java
deleted file mode 100644
index 8dbcaa9d6..000000000
--- a/src/api/java/baritone/api/utils/RandomSpotNearby.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package baritone.api.utils;
-
-import java.util.Random;
-
-public class RandomSpotNearby {
- private final Random rand;
- private BetterBlockPos end;
- private double r;
- private double old_r;
-
- public RandomSpotNearby(final double r) {
- this.rand = new Random();
- this.r = r;
- this.old_r = r;
- }
-
- private final double MAX_DIST_INCREASE() {
- return old_r * 2;
- }
-
- private BetterBlockPos calc(final BetterBlockPos start) {
- final double phi = rand.nextInt(360) + rand.nextDouble();
- final double radius = rand.nextInt((int) Math.round(r)) + rand.nextDouble(); //rand.nextDouble(r) + rand.nextDouble();
- final int x = (int) Math.round(radius * Math.sin(phi));
- final int z = (int) Math.round(radius * Math.cos(phi));
-
- this.end = new BetterBlockPos(start.getX() + x, start.getY(), start.getZ() + z);
- return this.end;
- }
-
- public BetterBlockPos next(final BetterBlockPos start) {
- this.r = (this.r - this.old_r > MAX_DIST_INCREASE()) ? this.old_r : this.r;
- return next(start, 0.3d);
- }
-
- public BetterBlockPos next(final BetterBlockPos start, final double increaseRadius) {
- this.r += increaseRadius;
- return calc(start);
- }
-}
diff --git a/src/api/java/baritone/api/utils/RayTraceUtils.java b/src/api/java/baritone/api/utils/RayTraceUtils.java
index 022281b64..38199d071 100644
--- a/src/api/java/baritone/api/utils/RayTraceUtils.java
+++ b/src/api/java/baritone/api/utils/RayTraceUtils.java
@@ -28,8 +28,7 @@
*/
public final class RayTraceUtils {
public static ClipContext.Fluid fluidHandling = ClipContext.Fluid.NONE;
- private RayTraceUtils() {
- }
+ private RayTraceUtils() {}
/**
* Performs a block raytrace with the specified rotations. This should only be used when
@@ -52,13 +51,14 @@ public static HitResult rayTraceTowards(Entity entity, Rotation rotation, double
} else {
start = entity.getEyePosition(1.0F); // do whatever is correct
}
- Vec3 direction = RotationUtils.calcVector3dFromRotation(rotation);
+
+ Vec3 direction = RotationUtils.calcLookDirectionFromRotation(rotation);
Vec3 end = start.add(
direction.x * blockReachDistance,
direction.y * blockReachDistance,
direction.z * blockReachDistance
);
- return entity.level.clip(new ClipContext(start, end, ClipContext.Block.OUTLINE, fluidHandling, entity));
+ return entity.level().clip(new ClipContext(start, end, ClipContext.Block.OUTLINE, fluidHandling, entity));
}
public static Vec3 inferSneakingEyePosition(Entity entity) {
diff --git a/src/api/java/baritone/api/utils/Rotation.java b/src/api/java/baritone/api/utils/Rotation.java
index 36beea7bc..c75a9a559 100644
--- a/src/api/java/baritone/api/utils/Rotation.java
+++ b/src/api/java/baritone/api/utils/Rotation.java
@@ -26,12 +26,12 @@ public class Rotation {
/**
* The yaw angle of this Rotation
*/
- private float yaw;
+ private final float yaw;
/**
* The pitch angle of this Rotation
*/
- private float pitch;
+ private final float pitch;
public Rotation(float yaw, float pitch) {
this.yaw = yaw;
@@ -113,6 +113,10 @@ public Rotation normalizeAndClamp() {
);
}
+ public Rotation withPitch(float pitch) {
+ return new Rotation(this.yaw, pitch);
+ }
+
/**
* Is really close to
*
diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java
index 0f43c730b..6e310bb1c 100644
--- a/src/api/java/baritone/api/utils/RotationUtils.java
+++ b/src/api/java/baritone/api/utils/RotationUtils.java
@@ -44,11 +44,13 @@ public final class RotationUtils {
* Constant that a degree value is multiplied by to get the equivalent radian value
*/
public static final double DEG_TO_RAD = Math.PI / 180.0;
+ public static final float DEG_TO_RAD_F = (float) DEG_TO_RAD;
/**
* Constant that a radian value is multiplied by to get the equivalent degree value
*/
public static final double RAD_TO_DEG = 180.0 / Math.PI;
+ public static final float RAD_TO_DEG_F = (float) RAD_TO_DEG;
/**
* Offsets from the root block position to the center of each side.
@@ -62,8 +64,7 @@ public final class RotationUtils {
new Vec3(1, 0.5, 0.5) // East
};
- private RotationUtils() {
- }
+ private RotationUtils() {}
/**
* Calculates the rotation from BlockPosdest to BlockPosorig
@@ -130,26 +131,31 @@ private static Rotation calcRotationFromVec3d(Vec3 orig, Vec3 dest) {
* @param rotation The input rotation
* @return Look vector for the rotation
*/
- public static Vec3 calcVector3dFromRotation(Rotation rotation) {
- float f = Mth.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
- float f1 = Mth.sin(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
- float f2 = -Mth.cos(-rotation.getPitch() * (float) DEG_TO_RAD);
- float f3 = Mth.sin(-rotation.getPitch() * (float) DEG_TO_RAD);
- return new Vec3((double) (f1 * f2), (double) f3, (double) (f * f2));
+ public static Vec3 calcLookDirectionFromRotation(Rotation rotation) {
+ float flatZ = Mth.cos((-rotation.getYaw() * DEG_TO_RAD_F) - (float) Math.PI);
+ float flatX = Mth.sin((-rotation.getYaw() * DEG_TO_RAD_F) - (float) Math.PI);
+ float pitchBase = -Mth.cos(-rotation.getPitch() * DEG_TO_RAD_F);
+ float pitchHeight = Mth.sin(-rotation.getPitch() * DEG_TO_RAD_F);
+ return new Vec3(flatX * pitchBase, pitchHeight, flatZ * pitchBase);
+ }
+
+ @Deprecated
+ public static Vec3 calcVec3dFromRotation(Rotation rotation) {
+ return calcLookDirectionFromRotation(rotation);
}
/**
* @param ctx Context for the viewing entity
* @param pos The target block position
* @return The optional rotation
- * @see #reachable(LocalPlayer, BlockPos, double)
+ * @see #reachable(IPlayerContext, BlockPos, double)
*/
public static Optional reachable(IPlayerContext ctx, BlockPos pos) {
- return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
+ return reachable(ctx, pos, false);
}
public static Optional reachable(IPlayerContext ctx, BlockPos pos, boolean wouldSneak) {
- return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance(), wouldSneak);
+ return reachable(ctx, pos, ctx.playerController().getBlockReachDistance(), wouldSneak);
}
/**
@@ -159,18 +165,17 @@ public static Optional reachable(IPlayerContext ctx, BlockPos pos, boo
* side that is reachable. The return type will be {@link Optional#empty()} if the entity is
* unable to reach any of the sides of the block.
*
- * @param entity The viewing entity
+ * @param ctx Context for the viewing entity
* @param pos The target block position
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation
*/
- public static Optional reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance) {
- return reachable(entity, pos, blockReachDistance, false);
+ public static Optional reachable(IPlayerContext ctx, BlockPos pos, double blockReachDistance) {
+ return reachable(ctx, pos, blockReachDistance, false);
}
- public static Optional reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
- IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(entity);
- if (baritone.getPlayerContext().isLookingAt(pos)) {
+ public static Optional reachable(IPlayerContext ctx, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
+ if (BaritoneAPI.getSettings().remainWithExistingLookDirection.value && ctx.isLookingAt(pos)) {
/*
* why add 0.0001?
* to indicate that we actually have a desired pitch
@@ -181,10 +186,10 @@ public static Optional reachable(LocalPlayer entity, BlockPos pos, dou
*
* or if you're a normal person literally all this does it ensure that we don't nudge the pitch to a normal level
*/
- Rotation hypothetical = new Rotation(entity.getYRot(), entity.getXRot() + 0.0001F);
+ Rotation hypothetical = ctx.playerRotations().add(new Rotation(0, 0.0001F));
if (wouldSneak) {
// the concern here is: what if we're looking at it now, but as soon as we start sneaking we no longer are
- HitResult result = RayTraceUtils.rayTraceTowards(entity, hypothetical, blockReachDistance, true);
+ HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), hypothetical, blockReachDistance, true);
if (result != null && result.getType() == HitResult.Type.BLOCK && ((BlockHitResult) result).getBlockPos().equals(pos)) {
return Optional.of(hypothetical); // yes, if we sneaked we would still be looking at the block
}
@@ -192,14 +197,14 @@ public static Optional reachable(LocalPlayer entity, BlockPos pos, dou
return Optional.of(hypothetical);
}
}
- Optional possibleRotation = reachableCenter(entity, pos, blockReachDistance, wouldSneak);
+ Optional possibleRotation = reachableCenter(ctx, pos, blockReachDistance, wouldSneak);
//System.out.println("center: " + possibleRotation);
if (possibleRotation.isPresent()) {
return possibleRotation;
}
- BlockState state = entity.level.getBlockState(pos);
- VoxelShape shape = state.getShape(entity.level, pos);
+ BlockState state = ctx.world().getBlockState(pos);
+ VoxelShape shape = state.getShape(ctx.world(), pos);
if (shape.isEmpty()) {
shape = Shapes.block();
}
@@ -207,7 +212,7 @@ public static Optional reachable(LocalPlayer entity, BlockPos pos, dou
double xDiff = shape.min(Direction.Axis.X) * sideOffset.x + shape.max(Direction.Axis.X) * (1 - sideOffset.x);
double yDiff = shape.min(Direction.Axis.Y) * sideOffset.y + shape.max(Direction.Axis.Y) * (1 - sideOffset.y);
double zDiff = shape.min(Direction.Axis.Z) * sideOffset.z + shape.max(Direction.Axis.Z) * (1 - sideOffset.z);
- possibleRotation = reachableOffset(entity, pos, new Vec3(pos.getX(), pos.getY(), pos.getZ()).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak);
+ possibleRotation = reachableOffset(ctx, pos, new Vec3(pos.getX(), pos.getY(), pos.getZ()).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak);
if (possibleRotation.isPresent()) {
return possibleRotation;
}
@@ -220,22 +225,23 @@ public static Optional reachable(LocalPlayer entity, BlockPos pos, dou
* the given offsetted position. The return type will be {@link Optional#empty()} if
* the entity is unable to reach the block with the offset applied.
*
- * @param entity The viewing entity
+ * @param ctx Context for the viewing entity
* @param pos The target block position
* @param offsetPos The position of the block with the offset applied.
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation
*/
- public static Optional reachableOffset(Entity entity, BlockPos pos, Vec3 offsetPos, double blockReachDistance, boolean wouldSneak) {
- Vec3 eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(entity) : entity.getEyePosition(1.0F);
- Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, new Rotation(entity.getYRot(), entity.getXRot()));
- HitResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance, wouldSneak);
+ public static Optional reachableOffset(IPlayerContext ctx, BlockPos pos, Vec3 offsetPos, double blockReachDistance, boolean wouldSneak) {
+ Vec3 eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(ctx.player()) : ctx.player().getEyePosition(1.0F);
+ Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, ctx.playerRotations());
+ Rotation actualRotation = BaritoneAPI.getProvider().getBaritoneForPlayer(ctx.player()).getLookBehavior().getAimProcessor().peekRotation(rotation);
+ HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), actualRotation, blockReachDistance, wouldSneak);
//System.out.println(result);
if (result != null && result.getType() == HitResult.Type.BLOCK) {
if (((BlockHitResult) result).getBlockPos().equals(pos)) {
return Optional.of(rotation);
}
- if (entity.level.getBlockState(pos).getBlock() instanceof BaseFireBlock && ((BlockHitResult) result).getBlockPos().equals(pos.below())) {
+ if (ctx.world().getBlockState(pos).getBlock() instanceof BaseFireBlock && ((BlockHitResult) result).getBlockPos().equals(pos.below())) {
return Optional.of(rotation);
}
}
@@ -246,12 +252,46 @@ public static Optional reachableOffset(Entity entity, BlockPos pos, Ve
* Determines if the specified entity is able to reach the specified block where it is
* looking at the direct center of it's hitbox.
*
- * @param entity The viewing entity
+ * @param ctx Context for the viewing entity
* @param pos The target block position
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation
*/
+ public static Optional reachableCenter(IPlayerContext ctx, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
+ return reachableOffset(ctx, pos, VecUtils.calculateBlockCenter(ctx.world(), pos), blockReachDistance, wouldSneak);
+ }
+
+ @Deprecated
+ public static Optional reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance) {
+ return reachable(entity, pos, blockReachDistance, false);
+ }
+
+ @Deprecated
+ public static Optional reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(entity);
+ IPlayerContext ctx = baritone.getPlayerContext();
+ return reachable(ctx, pos, blockReachDistance, wouldSneak);
+ }
+
+ @Deprecated
+ public static Optional reachableOffset(Entity entity, BlockPos pos, Vec3 offsetPos, double blockReachDistance, boolean wouldSneak) {
+ Vec3 eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(entity) : entity.getEyePosition(1.0F);
+ Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, new Rotation(entity.getYRot(), entity.getXRot()));
+ HitResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance, wouldSneak);
+ //System.out.println(result);
+ if (result != null && result.getType() == HitResult.Type.BLOCK) {
+ if (((BlockHitResult) result).getBlockPos().equals(pos)) {
+ return Optional.of(rotation);
+ }
+ if (entity.level().getBlockState(pos).getBlock() instanceof BaseFireBlock && ((BlockHitResult) result).getBlockPos().equals(pos.below())) {
+ return Optional.of(rotation);
+ }
+ }
+ return Optional.empty();
+ }
+
+ @Deprecated
public static Optional reachableCenter(Entity entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
- return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(entity.level, pos), blockReachDistance, wouldSneak);
+ return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(entity.level(), pos), blockReachDistance, wouldSneak);
}
}
diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java
index c6e0608eb..53283cd33 100644
--- a/src/api/java/baritone/api/utils/SettingsUtil.java
+++ b/src/api/java/baritone/api/utils/SettingsUtil.java
@@ -21,12 +21,12 @@
import baritone.api.Settings;
import net.minecraft.client.Minecraft;
import net.minecraft.core.Direction;
+import net.minecraft.core.Registry;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
-
import java.awt.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -47,12 +47,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-
public class SettingsUtil {
- private static final Path SETTINGS_PATH = Minecraft.getInstance().gameDirectory.toPath().resolve("baritone").resolve("settings.txt");
+ public static final String SETTINGS_DEFAULT_NAME = "settings.txt";
private static final Pattern SETTING_PATTERN = Pattern.compile("^(?[^ ]+) +(?.+)"); // key and value split by the first space
- private static final String[] JAVA_ONLY_SETTINGS = {"logger", "notifier", "toaster"};
private static boolean isComment(String line) {
@@ -71,12 +69,12 @@ private static void forEachLine(Path file, Consumer consumer) throws IOE
}
}
- public static void readAndApply(Settings settings) {
+ public static void readAndApply(Settings settings, String settingsName) {
try {
- forEachLine(SETTINGS_PATH, line -> {
+ forEachLine(settingsByName(settingsName), line -> {
Matcher matcher = SETTING_PATTERN.matcher(line);
if (!matcher.matches()) {
- System.out.println("Invalid syntax in setting file: " + line);
+ Helper.HELPER.logDirect("Invalid syntax in setting file: " + line);
return;
}
@@ -85,29 +83,33 @@ public static void readAndApply(Settings settings) {
try {
parseAndApply(settings, settingName, settingValue);
} catch (Exception ex) {
- System.out.println("Unable to parse line " + line);
+ Helper.HELPER.logDirect("Unable to parse line " + line);
ex.printStackTrace();
}
});
} catch (NoSuchFileException ignored) {
- System.out.println("Baritone settings file not found, resetting.");
+ Helper.HELPER.logDirect("Baritone settings file not found, resetting.");
} catch (Exception ex) {
- System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
+ Helper.HELPER.logDirect("Exception while reading Baritone settings, some settings may be reset to default values!");
ex.printStackTrace();
}
}
public static synchronized void save(Settings settings) {
- try (BufferedWriter out = Files.newBufferedWriter(SETTINGS_PATH)) {
+ try (BufferedWriter out = Files.newBufferedWriter(settingsByName(SETTINGS_DEFAULT_NAME))) {
for (Settings.Setting setting : modifiedSettings(settings)) {
out.write(settingToString(setting) + "\n");
}
} catch (Exception ex) {
- System.out.println("Exception thrown while saving Baritone settings!");
+ Helper.HELPER.logDirect("Exception thrown while saving Baritone settings!");
ex.printStackTrace();
}
}
+ private static Path settingsByName(String name) {
+ return Minecraft.getInstance().gameDirectory.toPath().resolve("baritone").resolve(name);
+ }
+
public static List modifiedSettings(Settings settings) {
List modified = new ArrayList<>();
for (Settings.Setting setting : settings.allSettings) {
@@ -115,7 +117,7 @@ public static List modifiedSettings(Settings settings) {
System.out.println("NULL SETTING?" + setting.getName());
continue;
}
- if (javaOnlySetting(setting)) {
+ if (setting.isJavaOnly()) {
continue; // NO
}
if (setting.value == setting.defaultValue) {
@@ -169,7 +171,7 @@ public static String maybeCensor(int coord) {
}
public static String settingToString(Settings.Setting setting) throws IllegalStateException {
- if (javaOnlySetting(setting)) {
+ if (setting.isJavaOnly()) {
return setting.getName();
}
@@ -177,18 +179,14 @@ public static String settingToString(Settings.Setting setting) throws IllegalSta
}
/**
- * This should always be the same as whether the setting can be parsed from or serialized to a string
+ * Deprecated. Use {@link Settings.Setting#isJavaOnly()} instead.
*
- * @param the setting
+ * @param setting The Setting
* @return true if the setting can not be set or read by the user
*/
+ @Deprecated
public static boolean javaOnlySetting(Settings.Setting setting) {
- for (String name : JAVA_ONLY_SETTINGS) { // no JAVA_ONLY_SETTINGS.contains(...) because that would be case sensitive
- if (setting.getName().equalsIgnoreCase(name)) {
- return true;
- }
- }
- return false;
+ return setting.isJavaOnly();
}
public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
@@ -205,6 +203,28 @@ public static void parseAndApply(Settings settings, String settingName, String s
setting.value = parsed;
}
+ private interface ISettingParser {
+
+ T parse(ParserContext context, String raw);
+
+ String toString(ParserContext context, T value);
+
+ boolean accepts(Type type);
+ }
+
+ private static class ParserContext {
+
+ private final Settings.Setting> setting;
+
+ private ParserContext(Settings.Setting> setting) {
+ this.setting = setting;
+ }
+
+ private Settings.Setting> getSetting() {
+ return this.setting;
+ }
+ }
+
private enum Parser implements ISettingParser {
DOUBLE(Double.class, Double::parseDouble),
@@ -333,26 +353,4 @@ public static Parser getParser(Type type) {
.findFirst().orElse(null);
}
}
-
- private interface ISettingParser {
-
- T parse(ParserContext context, String raw);
-
- String toString(ParserContext context, T value);
-
- boolean accepts(Type type);
- }
-
- private static class ParserContext {
-
- private final Settings.Setting> setting;
-
- private ParserContext(Settings.Setting> setting) {
- this.setting = setting;
- }
-
- private Settings.Setting> getSetting() {
- return this.setting;
- }
- }
}
diff --git a/src/api/java/baritone/api/utils/TypeUtils.java b/src/api/java/baritone/api/utils/TypeUtils.java
index 01fe45459..457cc449a 100644
--- a/src/api/java/baritone/api/utils/TypeUtils.java
+++ b/src/api/java/baritone/api/utils/TypeUtils.java
@@ -26,8 +26,7 @@
*/
public final class TypeUtils {
- private TypeUtils() {
- }
+ private TypeUtils() {}
/**
* Resolves the "base type" for the specified type. For example, if the specified
diff --git a/src/api/java/baritone/api/utils/VecUtils.java b/src/api/java/baritone/api/utils/VecUtils.java
index dceab6c61..4ea94b95a 100644
--- a/src/api/java/baritone/api/utils/VecUtils.java
+++ b/src/api/java/baritone/api/utils/VecUtils.java
@@ -32,8 +32,7 @@
*/
public final class VecUtils {
- private VecUtils() {
- }
+ private VecUtils() {}
/**
* Calculates the center of the block at the specified position's bounding box
diff --git a/src/api/java/baritone/api/utils/gui/BaritoneToast.java b/src/api/java/baritone/api/utils/gui/BaritoneToast.java
index 87f0aac6a..6cdc57cc0 100644
--- a/src/api/java/baritone/api/utils/gui/BaritoneToast.java
+++ b/src/api/java/baritone/api/utils/gui/BaritoneToast.java
@@ -17,8 +17,10 @@
package baritone.api.utils.gui;
+import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraft.client.gui.components.toasts.ToastComponent;
import net.minecraft.network.chat.Component;
@@ -37,7 +39,7 @@ public BaritoneToast(Component titleComponent, Component subtitleComponent, long
this.totalShowTime = totalShowTime;
}
- public Visibility render(PoseStack matrixStack, ToastComponent toastGui, long delta) {
+ public Visibility render(GuiGraphics gui, ToastComponent toastGui, long delta) {
if (this.newDisplay) {
this.firstDrawTime = delta;
this.newDisplay = false;
@@ -45,15 +47,13 @@ public Visibility render(PoseStack matrixStack, ToastComponent toastGui, long de
//TODO: check
- toastGui.getMinecraft().getTextureManager().bindForSetup(new ResourceLocation("textures/gui/toasts.png"));
- //GlStateManager._color4f(1.0F, 1.0F, 1.0F, 255.0F);
- toastGui.blit(matrixStack, 0, 0, 0, 32, 160, 32);
+ gui.blit(new ResourceLocation("textures/gui/toasts.png"), 0, 0, 0, 32, 160, 32);
if (this.subtitle == null) {
- toastGui.getMinecraft().font.draw(matrixStack, this.title, 18, 12, -11534256);
+ gui.drawString(toastGui.getMinecraft().font, this.title, 18, 12, -11534256);
} else {
- toastGui.getMinecraft().font.draw(matrixStack, this.title, 18, 7, -11534256);
- toastGui.getMinecraft().font.draw(matrixStack, this.subtitle, 18, 18, -16777216);
+ gui.drawString(toastGui.getMinecraft().font, this.title, 18, 7, -11534256);
+ gui.drawString(toastGui.getMinecraft().font, this.subtitle, 18, 18, -16777216);
}
return delta - this.firstDrawTime < totalShowTime ? Visibility.SHOW : Visibility.HIDE;
diff --git a/src/launch/java/baritone/launch/mixins/MixinChunkArray.java b/src/launch/java/baritone/launch/mixins/MixinChunkArray.java
index 9f88fb1fe..711ca6554 100644
--- a/src/launch/java/baritone/launch/mixins/MixinChunkArray.java
+++ b/src/launch/java/baritone/launch/mixins/MixinChunkArray.java
@@ -18,13 +18,13 @@
package baritone.launch.mixins;
import baritone.utils.accessor.IChunkArray;
-import net.minecraft.world.level.ChunkPos;
-import net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.concurrent.atomic.AtomicReferenceArray;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.chunk.LevelChunk;
@Mixin(targets = "net.minecraft.client.multiplayer.ClientChunkCache$Storage")
public abstract class MixinChunkArray implements IChunkArray {
diff --git a/src/launch/java/baritone/launch/mixins/MixinClientChunkProvider.java b/src/launch/java/baritone/launch/mixins/MixinClientChunkProvider.java
index d25837754..de465b82a 100644
--- a/src/launch/java/baritone/launch/mixins/MixinClientChunkProvider.java
+++ b/src/launch/java/baritone/launch/mixins/MixinClientChunkProvider.java
@@ -19,14 +19,14 @@
import baritone.utils.accessor.IChunkArray;
import baritone.utils.accessor.IClientChunkProvider;
-import net.minecraft.client.multiplayer.ClientChunkCache;
-import net.minecraft.client.multiplayer.ClientLevel;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.lang.reflect.Field;
import java.util.Arrays;
+import net.minecraft.client.multiplayer.ClientChunkCache;
+import net.minecraft.client.multiplayer.ClientLevel;
@Mixin(ClientChunkCache.class)
public class MixinClientChunkProvider implements IClientChunkProvider {
diff --git a/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java b/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java
index 1eafa8d54..d603ca632 100644
--- a/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java
+++ b/src/launch/java/baritone/launch/mixins/MixinClientPlayNetHandler.java
@@ -20,28 +20,36 @@
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
+import baritone.api.event.events.BlockChangeEvent;
import baritone.api.event.events.ChatEvent;
import baritone.api.event.events.ChunkEvent;
import baritone.api.event.events.type.EventState;
+import baritone.api.utils.Pair;
import baritone.cache.CachedChunk;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
import net.minecraft.client.multiplayer.ClientPacketListener;
+import net.minecraft.client.multiplayer.CommonListenerCookie;
import net.minecraft.client.player.LocalPlayer;
+import net.minecraft.core.BlockPos;
+import net.minecraft.network.Connection;
import net.minecraft.network.protocol.game.*;
import net.minecraft.world.level.ChunkPos;
-import org.spongepowered.asm.mixin.Final;
+import net.minecraft.world.level.block.state.BlockState;
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;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* @author Brady
* @since 8/3/2018
*/
@Mixin(ClientPacketListener.class)
-public class MixinClientPlayNetHandler {
+public abstract class MixinClientPlayNetHandler extends ClientCommonPacketListenerImpl {
// unused lol
/*@Inject(
@@ -67,9 +75,9 @@ private void preRead(SPacketChunkData packetIn, CallbackInfo ci) {
}
}*/
- @Shadow
- @Final
- private Minecraft minecraft;
+ protected MixinClientPlayNetHandler(final Minecraft arg, final Connection arg2, final CommonListenerCookie arg3) {
+ super(arg, arg2, arg3);
+ }
@Inject(
method = "sendChat(Ljava/lang/String;)V",
@@ -117,7 +125,7 @@ private void preChunkUnload(ClientboundForgetLevelChunkPacket packet, CallbackIn
LocalPlayer player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (ClientPacketListener) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
- new ChunkEvent(EventState.PRE, ChunkEvent.Type.UNLOAD, packet.getX(), packet.getZ())
+ new ChunkEvent(EventState.PRE, ChunkEvent.Type.UNLOAD, packet.pos().x, packet.pos().z)
);
}
}
@@ -132,7 +140,7 @@ private void postChunkUnload(ClientboundForgetLevelChunkPacket packet, CallbackI
LocalPlayer player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (ClientPacketListener) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
- new ChunkEvent(EventState.POST, ChunkEvent.Type.UNLOAD, packet.getX(), packet.getZ())
+ new ChunkEvent(EventState.POST, ChunkEvent.Type.UNLOAD, packet.pos().x, packet.pos().z)
);
}
}
@@ -169,31 +177,22 @@ private void postHandleBlockChange(ClientboundBlockUpdatePacket packetIn, Callba
at = @At("RETURN")
)
private void postHandleMultiBlockChange(ClientboundSectionBlocksUpdatePacket packetIn, CallbackInfo ci) {
- if (!Baritone.settings().repackOnAnyBlockChange.value) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((ClientPacketListener) (Object) this);
+ if (baritone == null) {
return;
}
- ChunkPos[] chunkPos = new ChunkPos[1];
- packetIn.runUpdates((pos, state) -> {
- if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(state.getBlock())) {
- chunkPos[0] = new ChunkPos(pos);
- }
+
+ List> changes = new ArrayList<>();
+ packetIn.runUpdates((mutPos, state) -> {
+ changes.add(new Pair<>(mutPos.immutable(), state));
});
- if (chunkPos[0] == null) {
+ if (changes.isEmpty()) {
return;
}
- for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
- LocalPlayer player = ibaritone.getPlayerContext().player();
- if (player != null && player.connection == (ClientPacketListener) (Object) this) {
- ibaritone.getGameEventHandler().onChunkEvent(
- new ChunkEvent(
- EventState.POST,
- ChunkEvent.Type.POPULATE_FULL,
- chunkPos[0].x,
- chunkPos[0].z
- )
- );
- }
- }
+ baritone.getGameEventHandler().onBlockChange(new BlockChangeEvent(
+ new ChunkPos(changes.get(0).first()),
+ changes
+ ));
}
@Inject(
@@ -211,4 +210,71 @@ private void onPlayerDeath(ClientboundPlayerCombatKillPacket packetIn, CallbackI
}
}
}
+
+ /*
+ @Inject(
+ method = "handleChunkData",
+ at = @At(
+ value = "INVOKE",
+ target = "net/minecraft/world/chunk/Chunk.read(Lnet/minecraft/network/PacketBuffer;IZ)V"
+ )
+ )
+ private void preRead(SPacketChunkData packetIn, CallbackInfo ci) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this);
+ if (baritone == null) {
+ return;
+ }
+ baritone.getGameEventHandler().onChunkEvent(
+ new ChunkEvent(
+ EventState.PRE,
+ packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL,
+ packetIn.getChunkX(),
+ packetIn.getChunkZ()
+ )
+ );
+ }
+
+ @Inject(
+ method = "handleChunkData",
+ at = @At("RETURN")
+ )
+ private void postHandleChunkData(SPacketChunkData packetIn, CallbackInfo ci) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this);
+ if (baritone == null) {
+ return;
+ }
+ baritone.getGameEventHandler().onChunkEvent(
+ new ChunkEvent(
+ EventState.POST,
+ packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL,
+ packetIn.getChunkX(),
+ packetIn.getChunkZ()
+ )
+ );
+ }
+
+ @Inject(
+ method = "handleBlockChange",
+ at = @At("RETURN")
+ )
+ private void postHandleBlockChange(SPacketBlockChange packetIn, CallbackInfo ci) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this);
+ if (baritone == null) {
+ return;
+ }
+
+ final ChunkPos pos = new ChunkPos(packetIn.getBlockPosition().getX() >> 4, packetIn.getBlockPosition().getZ() >> 4);
+ final Pair changed = new Pair<>(packetIn.getBlockPosition(), packetIn.getBlockState());
+ baritone.getGameEventHandler().onBlockChange(new BlockChangeEvent(pos, Collections.singletonList(changed)));
+ }
+
+ @Inject(
+ method = "handleMultiBlockChange",
+ at = @At("RETURN")
+ )
+ private void postHandleMultiBlockChange(SPacketMultiBlockChange packetIn, CallbackInfo ci) {
+
+ }
+
+ */
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java b/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java
index 4eea7d219..24e807f62 100644
--- a/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java
+++ b/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java
@@ -43,9 +43,8 @@ public class MixinClientPlayerEntity {
method = "tick",
at = @At(
value = "INVOKE",
- target = "net/minecraft/client/player/LocalPlayer.isPassenger()Z",
- shift = At.Shift.BY,
- by = -3
+ target = "net/minecraft/client/player/AbstractClientPlayer.tick()V",
+ shift = At.Shift.AFTER
)
)
private void onPreUpdate(CallbackInfo ci) {
@@ -55,22 +54,6 @@ private void onPreUpdate(CallbackInfo ci) {
}
}
- @Inject(
- method = "tick",
- at = @At(
- value = "INVOKE",
- target = "net/minecraft/client/player/LocalPlayer.sendPosition()V",
- shift = At.Shift.BY,
- by = 2
- )
- )
- private void onPostUpdate(CallbackInfo ci) {
- IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this);
- if (baritone != null) {
- baritone.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST));
- }
- }
-
@Redirect(
method = "aiStep",
at = @At(
@@ -122,4 +105,19 @@ private void updateRidden(CallbackInfo cb) {
((LookBehavior) baritone.getLookBehavior()).pig();
}
}
+
+ @Redirect(
+ method = "aiStep",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/player/LocalPlayer;tryToStartFallFlying()Z"
+ )
+ )
+ private boolean tryToStartFallFlying(final LocalPlayer instance) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(instance);
+ if (baritone != null && baritone.getPathingBehavior().isPathing()) {
+ return false;
+ }
+ return instance.tryToStartFallFlying();
+ }
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinCommandSuggestionHelper.java b/src/launch/java/baritone/launch/mixins/MixinCommandSuggestionHelper.java
index 70d5861cb..2bcdb2d78 100644
--- a/src/launch/java/baritone/launch/mixins/MixinCommandSuggestionHelper.java
+++ b/src/launch/java/baritone/launch/mixins/MixinCommandSuggestionHelper.java
@@ -19,6 +19,7 @@
import baritone.api.BaritoneAPI;
import baritone.api.event.events.TabCompleteEvent;
+import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
@@ -51,9 +52,18 @@ public class MixinCommandSuggestionHelper {
@Final
private List commandUsage;
+ @Shadow
+ private ParseResults currentParse;
+
@Shadow
private CompletableFuture pendingSuggestions;
+ @Shadow
+ private CommandSuggestions.SuggestionsList suggestions;
+
+ @Shadow
+ boolean keepSuggestions;
+
@Inject(
method = "updateCommandInfo",
at = @At("HEAD"),
@@ -74,27 +84,32 @@ private void preUpdateSuggestion(CallbackInfo ci) {
if (event.completions != null) {
ci.cancel();
+ this.currentParse = null; // stop coloring
+
+ if (this.keepSuggestions) { // Supress suggestions update when cycling suggestions.
+ return;
+ }
+
+ this.input.setSuggestion(null); // clear old suggestions
+ this.suggestions = null;
// TODO: Support populating the command usage
this.commandUsage.clear();
if (event.completions.length == 0) {
this.pendingSuggestions = Suggestions.empty();
} else {
- int offset = this.input.getValue().endsWith(" ")
- ? this.input.getCursorPosition()
- : this.input.getValue().lastIndexOf(" ") + 1; // If there is no space this is still 0 haha yes
+ StringRange range = StringRange.between(prefix.lastIndexOf(" ") + 1, prefix.length()); // if there is no space this starts at 0
List suggestionList = Stream.of(event.completions)
- .map(s -> new Suggestion(StringRange.between(offset, offset + s.length()), s))
+ .map(s -> new Suggestion(range, s))
.collect(Collectors.toList());
- Suggestions suggestions = new Suggestions(
- StringRange.between(offset, offset + suggestionList.stream().mapToInt(s -> s.getText().length()).max().orElse(0)),
- suggestionList);
+ Suggestions suggestions = new Suggestions(range, suggestionList);
this.pendingSuggestions = new CompletableFuture<>();
this.pendingSuggestions.complete(suggestions);
}
+ ((CommandSuggestions) (Object) this).showSuggestions(true); // actually populate the suggestions list from the suggestions future
}
}
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinEntity.java b/src/launch/java/baritone/launch/mixins/MixinEntity.java
index b48e919f2..748095351 100644
--- a/src/launch/java/baritone/launch/mixins/MixinEntity.java
+++ b/src/launch/java/baritone/launch/mixins/MixinEntity.java
@@ -23,6 +23,7 @@
import net.minecraft.world.entity.Entity;
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;
@@ -33,21 +34,25 @@ public class MixinEntity {
@Shadow
private float yRot;
- float yawRestore;
+ @Shadow
+ private float xRot;
+
+ @Unique
+ private RotationMoveEvent motionUpdateRotationEvent;
@Inject(
method = "moveRelative",
at = @At("HEAD")
)
private void moveRelativeHead(CallbackInfo info) {
- this.yawRestore = this.yRot;
// noinspection ConstantConditions
if (!LocalPlayer.class.isInstance(this) || BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this) == null) {
return;
}
- RotationMoveEvent motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.yRot);
+ this.motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.yRot, this.xRot);
BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this).getGameEventHandler().onPlayerRotationMove(motionUpdateRotationEvent);
- this.yRot = motionUpdateRotationEvent.getYaw();
+ this.yRot = this.motionUpdateRotationEvent.getYaw();
+ this.xRot = this.motionUpdateRotationEvent.getPitch();
}
@Inject(
@@ -55,6 +60,10 @@ private void moveRelativeHead(CallbackInfo info) {
at = @At("RETURN")
)
private void moveRelativeReturn(CallbackInfo info) {
- this.yRot = this.yawRestore;
+ if (this.motionUpdateRotationEvent != null) {
+ this.yRot = this.motionUpdateRotationEvent.getOriginal().getYaw();
+ this.xRot = this.motionUpdateRotationEvent.getOriginal().getPitch();
+ this.motionUpdateRotationEvent = null;
+ }
}
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinFireworkRocketEntity.java b/src/launch/java/baritone/launch/mixins/MixinFireworkRocketEntity.java
new file mode 100644
index 000000000..b4c8e05b6
--- /dev/null
+++ b/src/launch/java/baritone/launch/mixins/MixinFireworkRocketEntity.java
@@ -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 .
+ */
+
+package baritone.launch.mixins;
+
+import baritone.utils.accessor.IFireworkRocketEntity;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.projectile.FireworkRocketEntity;
+import net.minecraft.world.level.Level;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import java.util.OptionalInt;
+
+@Mixin(FireworkRocketEntity.class)
+public abstract class MixinFireworkRocketEntity extends Entity implements IFireworkRocketEntity {
+
+ @Shadow
+ @Final
+ private static EntityDataAccessor DATA_ATTACHED_TO_TARGET;
+
+ @Shadow
+ private LivingEntity attachedToEntity;
+
+ @Shadow
+ public abstract boolean isAttachedToEntity();
+
+ private MixinFireworkRocketEntity(Level level) {
+ super(EntityType.FIREWORK_ROCKET, level);
+ }
+
+ @Override
+ public LivingEntity getBoostedEntity() {
+ if (this.isAttachedToEntity() && this.attachedToEntity == null) { // isAttachedToEntity checks if the optional is present
+ final Entity entity = this.level().getEntity(this.entityData.get(DATA_ATTACHED_TO_TARGET).getAsInt());
+ if (entity instanceof LivingEntity) {
+ this.attachedToEntity = (LivingEntity) entity;
+ }
+ }
+ return this.attachedToEntity;
+ }
+}
diff --git a/src/launch/java/baritone/launch/mixins/MixinLivingEntity.java b/src/launch/java/baritone/launch/mixins/MixinLivingEntity.java
index c14f1b846..ada92f6c2 100644
--- a/src/launch/java/baritone/launch/mixins/MixinLivingEntity.java
+++ b/src/launch/java/baritone/launch/mixins/MixinLivingEntity.java
@@ -25,12 +25,16 @@
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
+import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
+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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import java.util.Optional;
+
/**
* @author Brady
* @since 9/10/2018
@@ -41,9 +45,13 @@ public abstract class MixinLivingEntity extends Entity {
/**
* Event called to override the movement direction when jumping
*/
+ @Unique
private RotationMoveEvent jumpRotationEvent;
- public MixinLivingEntity(EntityType> entityTypeIn, Level worldIn) {
+ @Unique
+ private RotationMoveEvent elytraRotationEvent;
+
+ private MixinLivingEntity(EntityType> entityTypeIn, Level worldIn) {
super(entityTypeIn, worldIn);
}
@@ -52,14 +60,10 @@ public MixinLivingEntity(EntityType> entityTypeIn, Level worldIn) {
at = @At("HEAD")
)
private void preMoveRelative(CallbackInfo ci) {
- // noinspection ConstantConditions
- if (LocalPlayer.class.isInstance(this)) {
- IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this);
- if (baritone != null) {
- this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.getYRot());
- baritone.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent);
- }
- }
+ this.getBaritone().ifPresent(baritone -> {
+ this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.getYRot(), this.getXRot());
+ baritone.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent);
+ });
}
@Redirect(
@@ -76,5 +80,45 @@ private float overrideYaw(LivingEntity self) {
return self.getYRot();
}
+ @Inject(
+ method = "travel",
+ at = @At(
+ value = "INVOKE",
+ target = "net/minecraft/world/entity/LivingEntity.getLookAngle()Lnet/minecraft/world/phys/Vec3;"
+ )
+ )
+ private void onPreElytraMove(Vec3 direction, CallbackInfo ci) {
+ this.getBaritone().ifPresent(baritone -> {
+ this.elytraRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.getYRot(), this.getXRot());
+ baritone.getGameEventHandler().onPlayerRotationMove(this.elytraRotationEvent);
+ this.setYRot(this.elytraRotationEvent.getYaw());
+ this.setXRot(this.elytraRotationEvent.getPitch());
+ });
+ }
+ @Inject(
+ method = "travel",
+ at = @At(
+ value = "INVOKE",
+ target = "net/minecraft/world/entity/LivingEntity.move(Lnet/minecraft/world/entity/MoverType;Lnet/minecraft/world/phys/Vec3;)V",
+ shift = At.Shift.AFTER
+ )
+ )
+ private void onPostElytraMove(Vec3 direction, CallbackInfo ci) {
+ if (this.elytraRotationEvent != null) {
+ this.setYRot(this.elytraRotationEvent.getOriginal().getYaw());
+ this.setXRot(this.elytraRotationEvent.getOriginal().getPitch());
+ this.elytraRotationEvent = null;
+ }
+ }
+
+ @Unique
+ private Optional getBaritone() {
+ // noinspection ConstantConditions
+ if (LocalPlayer.class.isInstance(this)) {
+ return Optional.ofNullable(BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this));
+ } else {
+ return Optional.empty();
+ }
+ }
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinLootContext.java b/src/launch/java/baritone/launch/mixins/MixinLootContext.java
index 7c7960cf1..223444e12 100644
--- a/src/launch/java/baritone/launch/mixins/MixinLootContext.java
+++ b/src/launch/java/baritone/launch/mixins/MixinLootContext.java
@@ -21,8 +21,7 @@
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.storage.loot.LootContext;
-import net.minecraft.world.level.storage.loot.LootTables;
-import net.minecraft.world.level.storage.loot.PredicateManager;
+import net.minecraft.world.level.storage.loot.LootDataManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@@ -48,27 +47,13 @@ private MinecraftServer getServer(ServerLevel world) {
method = "create",
at = @At(
value = "INVOKE",
- target = "Lnet/minecraft/server/MinecraftServer;getLootTables()Lnet/minecraft/world/level/storage/loot/LootTables;"
+ target = "Lnet/minecraft/server/MinecraftServer;getLootData()Lnet/minecraft/world/level/storage/loot/LootDataManager;"
)
)
- private LootTables getLootTableManager(MinecraftServer server) {
+ private LootDataManager getLootTableManager(MinecraftServer server) {
if (server == null) {
return BlockOptionalMeta.getManager();
}
- return server.getLootTables();
- }
-
- @Redirect(
- method = "create",
- at = @At(
- value = "INVOKE",
- target = "Lnet/minecraft/server/MinecraftServer;getPredicateManager()Lnet/minecraft/world/level/storage/loot/PredicateManager;"
- )
- )
- private PredicateManager getLootPredicateManager(MinecraftServer server) {
- if (server == null) {
- return BlockOptionalMeta.getPredicateManager();
- }
- return server.getPredicateManager();
+ return server.getLootData();
}
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java
index 604feaa85..e615a822a 100644
--- a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java
+++ b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java
@@ -19,6 +19,7 @@
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
+import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState;
@@ -29,9 +30,11 @@
import org.objectweb.asm.Opcodes;
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.Redirect;
+import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.BiFunction;
@@ -48,6 +51,9 @@ public class MixinMinecraft {
@Shadow
public ClientLevel level;
+ @Unique
+ private BiFunction tickProvider;
+
@Inject(
method = "",
at = @At("RETURN")
@@ -56,30 +62,68 @@ private void postInit(CallbackInfo ci) {
BaritoneAPI.getProvider().getPrimaryBaritone();
}
-
@Inject(
method = "tick",
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
- target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
- ordinal = 4,
- shift = At.Shift.BY,
- by = -3
+ target = "net/minecraft/client/Minecraft.screen:Lnet/minecraft/client/gui/screens/Screen;",
+ ordinal = 0,
+ shift = At.Shift.BEFORE
+ ),
+ slice = @Slice(
+ from = @At(
+ value = "FIELD",
+ opcode = Opcodes.PUTFIELD,
+ target = "net/minecraft/client/Minecraft.missTime:I"
+ )
)
)
private void runTick(CallbackInfo ci) {
- final BiFunction tickProvider = TickEvent.createNextProvider();
+ this.tickProvider = TickEvent.createNextProvider();
for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) {
-
TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null
? TickEvent.Type.IN
: TickEvent.Type.OUT;
+ baritone.getGameEventHandler().onTick(this.tickProvider.apply(EventState.PRE, type));
+ }
+ }
+
+ @Inject(
+ method = "tick",
+ at = @At("RETURN")
+ )
+ private void postRunTick(CallbackInfo ci) {
+ if (this.tickProvider == null) {
+ return;
+ }
- baritone.getGameEventHandler().onTick(tickProvider.apply(EventState.PRE, type));
+ for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) {
+ TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null
+ ? TickEvent.Type.IN
+ : TickEvent.Type.OUT;
+ baritone.getGameEventHandler().onPostTick(this.tickProvider.apply(EventState.POST, type));
}
+ this.tickProvider = null;
+ }
+
+ @Inject(
+ method = "tick",
+ at = @At(
+ value = "INVOKE",
+ target = "net/minecraft/client/multiplayer/ClientLevel.tickEntities()V",
+ shift = At.Shift.AFTER
+ )
+ )
+ private void postUpdateEntities(CallbackInfo ci) {
+ IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(this.player);
+ if (baritone != null) {
+ // Intentionally call this after all entities have been updated. That way, any modification to rotations
+ // can be recognized by other entity code. (Fireworks and Pigs, for example)
+ baritone.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST));
+ }
}
@Inject(
@@ -123,12 +167,25 @@ private void postLoadWorld(ClientLevel world, CallbackInfo ci) {
at = @At(
value = "FIELD",
opcode = Opcodes.GETFIELD,
- target = "Lnet/minecraft/client/gui/screens/Screen;passEvents:Z"
+ target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;"
+ ),
+ slice = @Slice(
+ from = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/client/gui/components/DebugScreenOverlay;showDebugScreen()Z"
+ ),
+ to = @At(
+ value = "CONSTANT",
+ args = "stringValue=Keybindings"
+ )
)
)
- private boolean passEvents(Screen screen) {
+ private Screen passEvents(Minecraft instance) {
// allow user input is only the primary baritone
- return (BaritoneAPI.getProvider().getPrimaryBaritone().getPathingBehavior().isPathing() && player != null) || screen.passEvents;
+ if (BaritoneAPI.getProvider().getPrimaryBaritone().getPathingBehavior().isPathing() && player != null) {
+ return null;
+ }
+ return instance.screen;
}
// TODO
diff --git a/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java b/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java
index 52543ed91..2d35800eb 100644
--- a/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java
+++ b/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java
@@ -52,7 +52,7 @@ public class MixinNetworkManager {
method = "sendPacket",
at = @At("HEAD")
)
- private void preDispatchPacket(Packet> packet, PacketSendListener packetSendListener, CallbackInfo ci) {
+ private void preDispatchPacket(Packet> packet, PacketSendListener packetSendListener, boolean flush, CallbackInfo ci) {
if (this.receiving != PacketFlow.CLIENTBOUND) {
return;
}
@@ -68,7 +68,7 @@ private void preDispatchPacket(Packet> packet, PacketSendListener packetSendLi
method = "sendPacket",
at = @At("RETURN")
)
- private void postDispatchPacket(Packet> packet, PacketSendListener packetSendListener, CallbackInfo ci) {
+ private void postDispatchPacket(Packet> packet, PacketSendListener packetSendListener, boolean flush, CallbackInfo ci) {
if (this.receiving != PacketFlow.CLIENTBOUND) {
return;
}
diff --git a/src/launch/java/baritone/launch/mixins/MixinPalettedContainer$Data.java b/src/launch/java/baritone/launch/mixins/MixinPalettedContainer$Data.java
new file mode 100644
index 000000000..e4c3cc61d
--- /dev/null
+++ b/src/launch/java/baritone/launch/mixins/MixinPalettedContainer$Data.java
@@ -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 .
+ */
+
+package baritone.launch.mixins;
+
+import baritone.utils.accessor.IPalettedContainer.IData;
+import net.minecraft.util.BitStorage;
+import net.minecraft.world.level.chunk.Palette;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(targets = "net/minecraft/world/level/chunk/PalettedContainer$Data")
+public abstract class MixinPalettedContainer$Data implements IData {
+
+ @Accessor
+ public abstract Palette getPalette();
+
+ @Accessor
+ public abstract BitStorage getStorage();
+}
diff --git a/src/launch/java/baritone/launch/mixins/MixinPalettedContainer.java b/src/launch/java/baritone/launch/mixins/MixinPalettedContainer.java
new file mode 100644
index 000000000..a1b409a09
--- /dev/null
+++ b/src/launch/java/baritone/launch/mixins/MixinPalettedContainer.java
@@ -0,0 +1,100 @@
+/*
+ * 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.launch.mixins;
+
+import baritone.utils.accessor.IPalettedContainer;
+import baritone.utils.accessor.IPalettedContainer.IData;
+import net.minecraft.util.BitStorage;
+import net.minecraft.world.level.chunk.Palette;
+import net.minecraft.world.level.chunk.PalettedContainer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+@Mixin(PalettedContainer.class)
+public abstract class MixinPalettedContainer implements IPalettedContainer {
+
+ private static final MethodHandle DATA_GETTER;
+
+ // Mixin has no way of referring to the data field and we can't use inheritance
+ // tricks to determine its name, so we use this ugly workaround instead.
+ // Classloading is hell here and causes accessor mixins (@Mixin interfaces with
+ // only @Accessor and @Invoker methods) to break on use and proguard hates method
+ // handles and on top of that mojang decided that error messages during world
+ // load are not needed so if you want to debug this you'll probably need an extra
+ // mixin just to display the error and hard quit the game before follow up errors
+ // blow up your log file.
+ // Mumphrey, please add the shadow classes you promised 5 years ago.
+ static {
+ Field dataField = null;
+ for (Field field : PalettedContainer.class.getDeclaredFields()) {
+ Class> fieldType = field.getType();
+ if (IData.class.isAssignableFrom(fieldType)) {
+ if ((field.getModifiers() & (Modifier.STATIC | Modifier.FINAL)) != 0 || field.isSynthetic()) {
+ continue;
+ }
+ if (dataField != null) {
+ throw new IllegalStateException("PalettedContainer has more than one Data field.");
+ }
+ dataField = field;
+ }
+ }
+ if (dataField == null) {
+ throw new IllegalStateException("PalettedContainer has no Data field.");
+ }
+ MethodHandle rawGetter;
+ try {
+ rawGetter = MethodHandles.lookup().unreflectGetter(dataField);
+ } catch (IllegalAccessException impossible) {
+ // we literally are the owning class, wtf?
+ throw new IllegalStateException("PalettedContainer may not access its own field?!", impossible);
+ }
+ MethodType getterType = MethodType.methodType(IData.class, PalettedContainer.class);
+ DATA_GETTER = MethodHandles.explicitCastArguments(rawGetter, getterType);
+ }
+
+ @Override
+ public Palette getPalette() {
+ return data().getPalette();
+ }
+
+ @Override
+ public BitStorage getStorage() {
+ return data().getStorage();
+ }
+
+ @Unique
+ private IData data() {
+ try {
+ // cast to Object first so the method handle doesn't hide the interface usage from proguard
+ return (IData) (Object) DATA_GETTER.invoke((PalettedContainer) (Object) this);
+ } catch (Throwable t) {
+ throw sneaky(t, RuntimeException.class);
+ }
+ }
+
+ @Unique
+ private static T sneaky(Throwable t, Class as) throws T {
+ throw (T) t;
+ }
+}
diff --git a/src/launch/java/baritone/launch/mixins/MixinScreen.java b/src/launch/java/baritone/launch/mixins/MixinScreen.java
index f53c7e602..c99c7776c 100644
--- a/src/launch/java/baritone/launch/mixins/MixinScreen.java
+++ b/src/launch/java/baritone/launch/mixins/MixinScreen.java
@@ -21,17 +21,17 @@
import baritone.api.IBaritone;
import baritone.api.event.events.ChatEvent;
import baritone.utils.accessor.IGuiScreen;
-import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Style;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
+
+import java.net.URI;
+import net.minecraft.client.gui.screens.Screen;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-import java.net.URI;
-
@Mixin(Screen.class)
public abstract class MixinScreen implements IGuiScreen {
@@ -43,7 +43,6 @@ public abstract class MixinScreen implements IGuiScreen {
//TODO: switch to enum extention with mixin 9.0 or whenever Mumfrey gets around to it
@Inject(at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;)V", remap = false, ordinal = 1), method = "handleComponentClicked", cancellable = true)
public void handleCustomClickEvent(Style style, CallbackInfoReturnable cir) {
- System.out.println("handleCustomClickEvent");
ClickEvent clickEvent = style.getClickEvent();
if (clickEvent == null) {
return;
diff --git a/src/launch/resources/mixins.baritone-meteor.json b/src/launch/resources/mixins.baritone-meteor.json
index 02f905891..f686c92e3 100644
--- a/src/launch/resources/mixins.baritone-meteor.json
+++ b/src/launch/resources/mixins.baritone-meteor.json
@@ -15,15 +15,17 @@
"MixinCommandSuggestionHelper",
"MixinEntity",
"MixinEntityRenderManager",
+ "MixinFireworkRocketEntity",
"MixinItemStack",
"MixinLivingEntity",
- "MixinLongArrayNBT",
"MixinLootContext",
"MixinMinecraft",
"MixinNetworkManager",
+ "MixinPalettedContainer",
+ "MixinPalettedContainer$Data",
"MixinPlayerController",
"MixinScreen",
"MixinWorldRenderer"
],
"plugin": "baritone.launch.FabricMixinPlugin"
-}
\ No newline at end of file
+}
diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java
index b81e17b38..c1176a3d4 100755
--- a/src/main/java/baritone/Baritone.java
+++ b/src/main/java/baritone/Baritone.java
@@ -20,8 +20,10 @@
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.Settings;
+import baritone.api.behavior.IBehavior;
import baritone.api.event.listener.IEventBus;
-import baritone.api.utils.Helper;
+import baritone.api.process.IBaritoneProcess;
+import baritone.api.process.IElytraProcess;
import baritone.api.utils.IPlayerContext;
import baritone.behavior.*;
import baritone.cache.WorldProvider;
@@ -33,16 +35,19 @@
import baritone.utils.GuiClick;
import baritone.utils.InputOverrideHandler;
import baritone.utils.PathingControlManager;
-import baritone.utils.player.PrimaryPlayerContext;
+import baritone.utils.player.BaritonePlayerContext;
import net.minecraft.client.Minecraft;
-import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
/**
* @author Brady
@@ -50,88 +55,103 @@
*/
public class Baritone implements IBaritone {
- private static ThreadPoolExecutor threadPool;
- private static File dir;
+ private static final ThreadPoolExecutor threadPool;
static {
threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
-
- dir = new File(Minecraft.getInstance().gameDirectory, "baritone");
- if (!Files.exists(dir.toPath())) {
- try {
- Files.createDirectories(dir.toPath());
- } catch (IOException ignored) {
- }
- }
}
- private GameEventHandler gameEventHandler;
+ private final Minecraft mc;
+ private final Path directory;
+
+ private final GameEventHandler gameEventHandler;
- private PathingBehavior pathingBehavior;
- private LookBehavior lookBehavior;
- private InventoryBehavior inventoryBehavior;
- private WaypointBehavior waypointBehavior;
- private InputOverrideHandler inputOverrideHandler;
+ private final PathingBehavior pathingBehavior;
+ private final LookBehavior lookBehavior;
+ private final InventoryBehavior inventoryBehavior;
+ private final InputOverrideHandler inputOverrideHandler;
- private FollowProcess followProcess;
- private MineProcess mineProcess;
- private GetToBlockProcess getToBlockProcess;
- private CustomGoalProcess customGoalProcess;
- private BuilderProcess builderProcess;
- private ExploreProcess exploreProcess;
- private BackfillProcess backfillProcess;
- private FarmProcess farmProcess;
+ private final FollowProcess followProcess;
+ private final MineProcess mineProcess;
+ private final GetToBlockProcess getToBlockProcess;
+ private final CustomGoalProcess customGoalProcess;
+ private final BuilderProcess builderProcess;
+ private final ExploreProcess exploreProcess;
+ private final FarmProcess farmProcess;
+ private final InventoryPauserProcess inventoryPauserProcess;
+ private final ElytraProcess elytraProcess;
- private PathingControlManager pathingControlManager;
- private SelectionManager selectionManager;
- private CommandManager commandManager;
+ private final PathingControlManager pathingControlManager;
+ private final SelectionManager selectionManager;
+ private final CommandManager commandManager;
- private IPlayerContext playerContext;
- private WorldProvider worldProvider;
+ private final IPlayerContext playerContext;
+ private final WorldProvider worldProvider;
public BlockStateInterface bsi;
- Baritone() {
+ Baritone(Minecraft mc) {
+ this.mc = mc;
this.gameEventHandler = new GameEventHandler(this);
+ this.directory = mc.gameDirectory.toPath().resolve("baritone");
+ if (!Files.exists(this.directory)) {
+ try {
+ Files.createDirectories(this.directory);
+ } catch (IOException ignored) {}
+ }
+
// Define this before behaviors try and get it, or else it will be null and the builds will fail!
- this.playerContext = PrimaryPlayerContext.INSTANCE;
+ this.playerContext = new BaritonePlayerContext(this, mc);
{
- // the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist
- pathingBehavior = new PathingBehavior(this);
- lookBehavior = new LookBehavior(this);
- inventoryBehavior = new InventoryBehavior(this);
- inputOverrideHandler = new InputOverrideHandler(this);
- waypointBehavior = new WaypointBehavior(this);
+ this.lookBehavior = this.registerBehavior(LookBehavior::new);
+ this.pathingBehavior = this.registerBehavior(PathingBehavior::new);
+ this.inventoryBehavior = this.registerBehavior(InventoryBehavior::new);
+ this.inputOverrideHandler = this.registerBehavior(InputOverrideHandler::new);
+ this.registerBehavior(WaypointBehavior::new);
}
this.pathingControlManager = new PathingControlManager(this);
{
- this.pathingControlManager.registerProcess(followProcess = new FollowProcess(this));
- this.pathingControlManager.registerProcess(mineProcess = new MineProcess(this));
- this.pathingControlManager.registerProcess(customGoalProcess = new CustomGoalProcess(this)); // very high iq
- this.pathingControlManager.registerProcess(getToBlockProcess = new GetToBlockProcess(this));
- this.pathingControlManager.registerProcess(builderProcess = new BuilderProcess(this));
- this.pathingControlManager.registerProcess(exploreProcess = new ExploreProcess(this));
- this.pathingControlManager.registerProcess(backfillProcess = new BackfillProcess(this));
- this.pathingControlManager.registerProcess(farmProcess = new FarmProcess(this));
+ this.followProcess = this.registerProcess(FollowProcess::new);
+ this.mineProcess = this.registerProcess(MineProcess::new);
+ this.customGoalProcess = this.registerProcess(CustomGoalProcess::new); // very high iq
+ this.getToBlockProcess = this.registerProcess(GetToBlockProcess::new);
+ this.builderProcess = this.registerProcess(BuilderProcess::new);
+ this.exploreProcess = this.registerProcess(ExploreProcess::new);
+ this.farmProcess = this.registerProcess(FarmProcess::new);
+ this.inventoryPauserProcess = this.registerProcess(InventoryPauserProcess::new);
+ this.elytraProcess = this.registerProcess(ElytraProcess::create);
+ this.registerProcess(BackfillProcess::new);
}
- this.worldProvider = new WorldProvider();
+ this.worldProvider = new WorldProvider(this);
this.selectionManager = new SelectionManager(this);
this.commandManager = new CommandManager(this);
}
+ public void registerBehavior(IBehavior behavior) {
+ this.gameEventHandler.registerEventListener(behavior);
+ }
+
+ public T registerBehavior(Function constructor) {
+ final T behavior = constructor.apply(this);
+ this.registerBehavior(behavior);
+ return behavior;
+ }
+
+ public T registerProcess(Function constructor) {
+ final T behavior = constructor.apply(this);
+ this.pathingControlManager.registerProcess(behavior);
+ return behavior;
+ }
+
@Override
public PathingControlManager getPathingControlManager() {
return this.pathingControlManager;
}
- public void registerBehavior(Behavior behavior) {
- this.gameEventHandler.registerEventListener(behavior);
- }
-
@Override
public InputOverrideHandler getInputOverrideHandler() {
return this.inputOverrideHandler;
@@ -171,6 +191,7 @@ public LookBehavior getLookBehavior() {
return this.lookBehavior;
}
+ @Override
public ExploreProcess getExploreProcess() {
return this.exploreProcess;
}
@@ -180,10 +201,15 @@ public MineProcess getMineProcess() {
return this.mineProcess;
}
+ @Override
public FarmProcess getFarmProcess() {
return this.farmProcess;
}
+ public InventoryPauserProcess getInventoryPauserProcess() {
+ return this.inventoryPauserProcess;
+ }
+
@Override
public PathingBehavior getPathingBehavior() {
return this.pathingBehavior;
@@ -209,23 +235,27 @@ public CommandManager getCommandManager() {
return this.commandManager;
}
+ @Override
+ public IElytraProcess getElytraProcess() {
+ return this.elytraProcess;
+ }
+
@Override
public void openClick() {
new Thread(() -> {
try {
Thread.sleep(100);
- Helper.mc.execute(() -> Helper.mc.setScreen(new GuiClick()));
- } catch (Exception ignored) {
- }
+ mc.execute(() -> mc.setScreen(new GuiClick()));
+ } catch (Exception ignored) {}
}).start();
}
- public static Settings settings() {
- return BaritoneAPI.getSettings();
+ public Path getDirectory() {
+ return this.directory;
}
- public static File getDir() {
- return dir;
+ public static Settings settings() {
+ return BaritoneAPI.getSettings();
}
public static Executor getExecutor() {
diff --git a/src/main/java/baritone/BaritoneProvider.java b/src/main/java/baritone/BaritoneProvider.java
index d5457cf85..f34d9bcb9 100644
--- a/src/main/java/baritone/BaritoneProvider.java
+++ b/src/main/java/baritone/BaritoneProvider.java
@@ -22,13 +22,15 @@
import baritone.api.cache.IWorldScanner;
import baritone.api.command.ICommandSystem;
import baritone.api.schematic.ISchematicSystem;
-import baritone.cache.WorldScanner;
+import baritone.cache.FasterWorldScanner;
import baritone.command.CommandSystem;
import baritone.command.ExampleBaritoneControl;
import baritone.utils.schematic.SchematicSystem;
+import net.minecraft.client.Minecraft;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author Brady
@@ -36,30 +38,45 @@
*/
public final class BaritoneProvider implements IBaritoneProvider {
- private final Baritone primary;
private final List all;
+ private final List allView;
- {
- this.primary = new Baritone();
- this.all = Collections.singletonList(this.primary);
+ public BaritoneProvider() {
+ this.all = new CopyOnWriteArrayList<>();
+ this.allView = Collections.unmodifiableList(this.all);
// Setup chat control, just for the primary instance
- new ExampleBaritoneControl(this.primary);
+ final Baritone primary = (Baritone) this.createBaritone(Minecraft.getInstance());
+ primary.registerBehavior(ExampleBaritoneControl::new);
}
@Override
public IBaritone getPrimaryBaritone() {
- return primary;
+ return this.all.get(0);
}
@Override
public List getAllBaritones() {
- return all;
+ return this.allView;
+ }
+
+ @Override
+ public synchronized IBaritone createBaritone(Minecraft minecraft) {
+ IBaritone baritone = this.getBaritoneForMinecraft(minecraft);
+ if (baritone == null) {
+ this.all.add(baritone = new Baritone(minecraft));
+ }
+ return baritone;
+ }
+
+ @Override
+ public synchronized boolean destroyBaritone(IBaritone baritone) {
+ return baritone != this.getPrimaryBaritone() && this.all.remove(baritone);
}
@Override
public IWorldScanner getWorldScanner() {
- return WorldScanner.INSTANCE;
+ return FasterWorldScanner.INSTANCE;
}
@Override
diff --git a/src/main/java/baritone/KeepName.java b/src/main/java/baritone/KeepName.java
index 8fe29cd71..7fc04cd68 100644
--- a/src/main/java/baritone/KeepName.java
+++ b/src/main/java/baritone/KeepName.java
@@ -18,5 +18,4 @@
package baritone;
// Annotation for classes and class members that should not be renamed by proguard
-public @interface KeepName {
-}
+public @interface KeepName {}
diff --git a/src/main/java/baritone/altoclef/AltoClefSettings.java b/src/main/java/baritone/altoclef/AltoClefSettings.java
index eb75a913e..cfd1e0c28 100644
--- a/src/main/java/baritone/altoclef/AltoClefSettings.java
+++ b/src/main/java/baritone/altoclef/AltoClefSettings.java
@@ -33,48 +33,39 @@ public class AltoClefSettings {
// woo singletons
private static AltoClefSettings _instance = new AltoClefSettings();
-
- public static AltoClefSettings getInstance() {
- return _instance;
- }
-
private final Object breakMutex = new Object();
private final Object placeMutex = new Object();
-
private final Object propertiesMutex = new Object();
-
private final Object globalHeuristicMutex = new Object();
-
private final HashSet _blocksToAvoidBreaking = new HashSet<>();
private final List> _breakAvoiders = new ArrayList<>();
-
private final List> _placeAvoiders = new ArrayList<>();
-
private final List> _forceCanWalkOn = new ArrayList<>();
-
private final List> _forceAvoidWalkThrough = new ArrayList<>();
-
private final List> _forceUseTool = new ArrayList<>();
-
private final List> _globalHeuristics = new ArrayList<>();
-
private final HashSet
- _protectedItems = new HashSet<>();
-
private boolean _allowFlowingWaterPass;
-
private boolean _pauseInteractions;
-
private boolean _dontPlaceBucketButStillFall;
-
private boolean _allowSwimThroughLava = false;
-
private boolean _treatSoulSandAsOrdinaryBlock = false;
+ private boolean canWalkOnEndPortal = false;
+
+ public static AltoClefSettings getInstance() {
+ return _instance;
+ }
+
+ public void canWalkOnEndPortal(boolean canWalk) {
+ canWalkOnEndPortal = canWalk;
+ }
public void avoidBlockBreak(BlockPos pos) {
synchronized (breakMutex) {
_blocksToAvoidBreaking.add(pos);
}
}
+
public void avoidBlockBreak(Predicate avoider) {
synchronized (breakMutex) {
_breakAvoiders.add(avoider);
@@ -102,6 +93,7 @@ public void avoidBlockPlace(Predicate avoider) {
public boolean shouldAvoidBreaking(int x, int y, int z) {
return shouldAvoidBreaking(new BlockPos(x, y, z));
}
+
public boolean shouldAvoidBreaking(BlockPos pos) {
synchronized (breakMutex) {
if (_blocksToAvoidBreaking.contains(pos))
@@ -109,11 +101,13 @@ public boolean shouldAvoidBreaking(BlockPos pos) {
return (_breakAvoiders.stream().anyMatch(pred -> pred.test(pos)));
}
}
+
public boolean shouldAvoidPlacingAt(BlockPos pos) {
synchronized (placeMutex) {
return _placeAvoiders.stream().anyMatch(pred -> pred.test(pos));
}
}
+
public boolean shouldAvoidPlacingAt(int x, int y, int z) {
return shouldAvoidPlacingAt(new BlockPos(x, y, z));
}
@@ -129,6 +123,7 @@ public boolean shouldAvoidWalkThroughForce(BlockPos pos) {
return _forceAvoidWalkThrough.stream().anyMatch(pred -> pred.test(pos));
}
}
+
public boolean shouldAvoidWalkThroughForce(int x, int y, int z) {
return shouldAvoidWalkThroughForce(new BlockPos(x, y, z));
}
@@ -156,21 +151,22 @@ public boolean isInteractionPaused() {
return _pauseInteractions;
}
}
- public boolean isFlowingWaterPassAllowed() {
+
+ public void setInteractionPaused(boolean paused) {
synchronized (propertiesMutex) {
- return _allowFlowingWaterPass;
+ _pauseInteractions = paused;
}
}
- public boolean canSwimThroughLava() {
+ public boolean isFlowingWaterPassAllowed() {
synchronized (propertiesMutex) {
- return _allowSwimThroughLava;
+ return _allowFlowingWaterPass;
}
}
- public void setInteractionPaused(boolean paused) {
+ public boolean canSwimThroughLava() {
synchronized (propertiesMutex) {
- _pauseInteractions = paused;
+ return _allowSwimThroughLava;
}
}
@@ -202,15 +198,19 @@ public double applyGlobalHeuristic(double prev, int x, int y, int z) {
public HashSet getBlocksToAvoidBreaking() {
return _blocksToAvoidBreaking;
}
+
public List> getBreakAvoiders() {
return _breakAvoiders;
}
+
public List> getPlaceAvoiders() {
return _placeAvoiders;
}
+
public List> getForceWalkOnPredicates() {
return _forceCanWalkOn;
}
+
public List> getForceAvoidWalkThroughPredicates() {
return _forceAvoidWalkThrough;
}
@@ -226,9 +226,11 @@ public List> getGlobalHeuristics() {
public boolean isItemProtected(Item item) {
return _protectedItems.contains(item);
}
+
public HashSet
- getProtectedItems() {
return _protectedItems;
}
+
public void protectItem(Item item) {
_protectedItems.add(item);
}
@@ -252,4 +254,8 @@ public Object getPropertiesMutex() {
public Object getGlobalHeuristicMutex() {
return globalHeuristicMutex;
}
+
+ public boolean isCanWalkOnEndPortal() {
+ return canWalkOnEndPortal;
+ }
}
diff --git a/src/main/java/baritone/behavior/Behavior.java b/src/main/java/baritone/behavior/Behavior.java
index 36273c026..848beb298 100644
--- a/src/main/java/baritone/behavior/Behavior.java
+++ b/src/main/java/baritone/behavior/Behavior.java
@@ -35,6 +35,5 @@ public class Behavior implements IBehavior {
protected Behavior(Baritone baritone) {
this.baritone = baritone;
this.ctx = baritone.getPlayerContext();
- baritone.registerBehavior(this);
}
}
diff --git a/src/main/java/baritone/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java
index bd61150dd..f8a7ac491 100644
--- a/src/main/java/baritone/behavior/InventoryBehavior.java
+++ b/src/main/java/baritone/behavior/InventoryBehavior.java
@@ -20,6 +20,7 @@
import baritone.Baritone;
import baritone.altoclef.AltoClefSettings;
import baritone.api.event.events.TickEvent;
+import baritone.api.utils.Helper;
import baritone.utils.ToolSet;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.Direction;
@@ -40,7 +41,10 @@
import java.util.Random;
import java.util.function.Predicate;
-public final class InventoryBehavior extends Behavior {
+public final class InventoryBehavior extends Behavior implements Helper {
+
+ int ticksSinceLastInventoryMove;
+ int[] lastTickRequestedMove; // not everything asks every tick, so remember the request while coming to a halt
public InventoryBehavior(Baritone baritone) {
super(baritone);
@@ -58,21 +62,29 @@ public void onTick(TickEvent event) {
// we have a crafting table or a chest or something open
return;
}
+ ticksSinceLastInventoryMove++;
if (firstValidThrowaway() >= 9) { // aka there are none on the hotbar, but there are some in main inventory
- swapWithHotBar(firstValidThrowaway(), 8);
+ requestSwapWithHotBar(firstValidThrowaway(), 8);
}
int pick = bestToolAgainst(Blocks.STONE, PickaxeItem.class);
if (pick >= 9) {
- swapWithHotBar(pick, 0);
+ requestSwapWithHotBar(pick, 0);
+ }
+ if (lastTickRequestedMove != null) {
+ logDebug("Remembering to move " + lastTickRequestedMove[0] + " " + lastTickRequestedMove[1] + " from a previous tick");
+ requestSwapWithHotBar(lastTickRequestedMove[0], lastTickRequestedMove[1]);
}
}
- public void attemptToPutOnHotbar(int inMainInvy, Predicate disallowedHotbar) {
- if (AltoClefSettings.getInstance().isInteractionPaused()) return;
+ public boolean attemptToPutOnHotbar(int inMainInvy, Predicate disallowedHotbar) {
+ if (AltoClefSettings.getInstance().isInteractionPaused()) return false;
OptionalInt destination = getTempHotbarSlot(disallowedHotbar);
if (destination.isPresent()) {
- swapWithHotBar(inMainInvy, destination.getAsInt());
+ if (!requestSwapWithHotBar(inMainInvy, destination.getAsInt())) {
+ return false;
+ }
}
+ return true;
}
public OptionalInt getTempHotbarSlot(Predicate disallowedHotbar) {
@@ -96,9 +108,21 @@ public OptionalInt getTempHotbarSlot(Predicate disallowedHotbar) {
return OptionalInt.of(candidates.get(new Random().nextInt(candidates.size())));
}
- private void swapWithHotBar(int inInventory, int inHotbar) {
- if (AltoClefSettings.getInstance().isInteractionPaused()) return;
+ private boolean requestSwapWithHotBar(int inInventory, int inHotbar) {
+ lastTickRequestedMove = new int[]{inInventory, inHotbar};
+ if (ticksSinceLastInventoryMove < Baritone.settings().ticksBetweenInventoryMoves.value) {
+ logDebug("Inventory move requested but delaying " + ticksSinceLastInventoryMove + " " + Baritone.settings().ticksBetweenInventoryMoves.value);
+ return false;
+ }
+ if (Baritone.settings().inventoryMoveOnlyIfStationary.value && !baritone.getInventoryPauserProcess().stationaryForInventoryMove()) {
+ logDebug("Inventory move requested but delaying until stationary");
+ return false;
+ }
+ if (AltoClefSettings.getInstance().isInteractionPaused()) return false;
ctx.playerController().windowClick(ctx.player().inventoryMenu.containerId, inInventory < 9 ? inInventory + 36 : inInventory, inHotbar, ClickType.SWAP, ctx.player());
+ ticksSinceLastInventoryMove = 0;
+ lastTickRequestedMove = null;
+ return true;
}
private int firstValidThrowaway() { // TODO offhand idk
@@ -151,8 +175,7 @@ public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) {
if (AltoClefSettings.getInstance().isInteractionPaused()) return false;
if (AltoClefSettings.getInstance().shouldAvoidPlacingAt(x, y, z)) return false;
BlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z, baritone.bsi.get0(x, y, z));
- if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof BlockItem && maybe.equals(((BlockItem) stack.getItem()).getBlock().getStateForPlacement(new BlockPlaceContext(new UseOnContext(ctx.world(), ctx.player(), InteractionHand.MAIN_HAND, stack, new BlockHitResult(new Vec3(ctx.player().position().x, ctx.player().position().y, ctx.player().position().z), Direction.UP, ctx.playerFeet(), false)) {
- }))))) {
+ if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof BlockItem && maybe.equals(((BlockItem) stack.getItem()).getBlock().getStateForPlacement(new BlockPlaceContext(new UseOnContext(ctx.world(), ctx.player(), InteractionHand.MAIN_HAND, stack, new BlockHitResult(new Vec3(ctx.player().position().x, ctx.player().position().y, ctx.player().position().z), Direction.UP, ctx.playerFeet(), false)) {}))))) {
return true; // gotem
}
if (maybe != null && throwaway(select, stack -> stack.getItem() instanceof BlockItem && ((BlockItem) stack.getItem()).getBlock().equals(maybe.getBlock()))) {
@@ -172,8 +195,7 @@ public boolean throwaway(boolean select, Predicate super ItemStack> desired) {
}
public boolean throwaway(boolean select, Predicate super ItemStack> desired, boolean allowInventory) {
- if (AltoClefSettings.getInstance().isInteractionPaused())
- return false;
+ if (AltoClefSettings.getInstance().isInteractionPaused()) return false;
LocalPlayer p = ctx.player();
NonNullList inv = p.getInventory().items;
for (int i = 0; i < 9; i++) {
@@ -210,8 +232,8 @@ public boolean throwaway(boolean select, Predicate super ItemStack> desired, b
if (allowInventory) {
for (int i = 9; i < 36; i++) {
if (desired.test(inv.get(i))) {
- swapWithHotBar(i, 7);
if (select) {
+ requestSwapWithHotBar(i, 7);
p.getInventory().selected = 7;
}
return true;
diff --git a/src/main/java/baritone/behavior/LookBehavior.java b/src/main/java/baritone/behavior/LookBehavior.java
index 13b8ebdd4..98e12aeff 100644
--- a/src/main/java/baritone/behavior/LookBehavior.java
+++ b/src/main/java/baritone/behavior/LookBehavior.java
@@ -20,80 +20,112 @@
import baritone.Baritone;
import baritone.api.Settings;
import baritone.api.behavior.ILookBehavior;
-import baritone.api.event.events.PlayerUpdateEvent;
-import baritone.api.event.events.RotationMoveEvent;
+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.protocol.game.ServerboundMovePlayerPacket;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Optional;
public final class LookBehavior extends Behavior implements ILookBehavior {
/**
- * Target's values are as follows:
+ * The current look target, may be {@code null}.
*/
- private Rotation target;
+ private Target target;
/**
- * Whether or not rotations are currently being forced
+ * The rotation known to the server. Returned by {@link #getEffectiveRotation()} for use in {@link IPlayerContext}.
*/
- private boolean force;
+ private Rotation serverRotation;
/**
- * The last player yaw angle. Used when free looking
+ * The last player rotation. Used to restore the player's angle when using free look.
*
* @see Settings#freeLook
*/
- private float lastYaw;
+ private Rotation prevRotation;
+
+ private final AimProcessor processor;
+
+ private final Deque smoothYawBuffer;
+ private final Deque smoothPitchBuffer;
public LookBehavior(Baritone baritone) {
super(baritone);
+ this.processor = new AimProcessor(baritone.getPlayerContext());
+ this.smoothYawBuffer = new ArrayDeque<>();
+ this.smoothPitchBuffer = new ArrayDeque<>();
}
@Override
- public void updateTarget(Rotation target, boolean force) {
- this.target = target;
- if (!force) {
- double rand = Math.random() - 0.5;
- if (Math.abs(rand) < 0.1) {
- rand *= 4;
- }
- this.target = new Rotation(this.target.getYaw() + (float) (rand * Baritone.settings().randomLooking113.value), this.target.getPitch());
+ public void updateTarget(Rotation rotation, boolean blockInteract) {
+ 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();
}
- this.force = force || !Baritone.settings().freeLook.value;
}
@Override
public void onPlayerUpdate(PlayerUpdateEvent event) {
+
if (this.target == null) {
return;
}
- // Whether or not we're going to silently set our angles
- boolean silent = Baritone.settings().antiCheatCompatibility.value && !this.force;
-
switch (event.getState()) {
case PRE: {
- if (this.force) {
- ctx.player().setYRot(this.target.getYaw());
- float oldPitch = ctx.player().getXRot();
- float desiredPitch = this.target.getPitch();
- ctx.player().setXRot(desiredPitch);
- ctx.player().setYRot((float) (ctx.player().getYRot() + (Math.random() - 0.5) * Baritone.settings().randomLooking.value));
- ctx.player().setXRot((float) (ctx.player().getXRot() + (Math.random() - 0.5) * Baritone.settings().randomLooking.value));
- if (desiredPitch == oldPitch && !Baritone.settings().freeLook.value) {
- nudgeToLevel();
- }
- this.target = null;
- }
- if (silent) {
- this.lastYaw = ctx.player().getYRot();
- ctx.player().setYRot(this.target.getYaw());
+ if (this.target.mode == Target.Mode.NONE) {
+ // Just return for PRE, we still want to set target to null on POST
+ return;
}
+
+ this.prevRotation = new Rotation(ctx.player().getYRot(), ctx.player().getXRot());
+ final Rotation actual = this.processor.peekRotation(this.target.rotation);
+ ctx.player().setYRot(actual.getYaw());
+ ctx.player().setXRot(actual.getPitch());
break;
}
case POST: {
- if (silent) {
- ctx.player().setYRot(this.lastYaw);
- this.target = null;
+ // Reset the player's rotations back to their original values
+ if (this.prevRotation != null) {
+ this.smoothYawBuffer.addLast(this.target.rotation.getYaw());
+ while (this.smoothYawBuffer.size() > Baritone.settings().smoothLookTicks.value) {
+ this.smoothYawBuffer.removeFirst();
+ }
+ this.smoothPitchBuffer.addLast(this.target.rotation.getPitch());
+ while (this.smoothPitchBuffer.size() > Baritone.settings().smoothLookTicks.value) {
+ this.smoothPitchBuffer.removeFirst();
+ }
+ if (this.target.mode == Target.Mode.SERVER) {
+ ctx.player().setYRot(this.prevRotation.getYaw());
+ ctx.player().setXRot(this.prevRotation.getPitch());
+ } else if (ctx.player().isFallFlying() ? Baritone.settings().elytraSmoothLook.value : Baritone.settings().smoothLook.value) {
+ ctx.player().setYRot((float) this.smoothYawBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getYaw()));
+ if (ctx.player().isFallFlying()) {
+ ctx.player().setXRot((float) this.smoothPitchBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getPitch()));
+ }
+ }
+ //ctx.player().xRotO = prevRotation.getPitch();
+ //ctx.player().yRotO = prevRotation.getYaw();
+ this.prevRotation = null;
}
+ // The target is done being used for this game tick, so it can be invalidated
+ this.target = null;
break;
}
default:
@@ -101,34 +133,227 @@ public void onPlayerUpdate(PlayerUpdateEvent event) {
}
}
+ @Override
+ public void onSendPacket(PacketEvent event) {
+ if (!(event.getPacket() instanceof ServerboundMovePlayerPacket)) {
+ return;
+ }
+
+ final ServerboundMovePlayerPacket packet = (ServerboundMovePlayerPacket) event.getPacket();
+ if (packet instanceof ServerboundMovePlayerPacket.Rot || packet instanceof ServerboundMovePlayerPacket.PosRot) {
+ this.serverRotation = new Rotation(packet.getYRot(0.0f), packet.getXRot(0.0f));
+ }
+ }
+
+ @Override
+ public void onWorldEvent(WorldEvent event) {
+ this.serverRotation = null;
+ this.target = null;
+ }
+
public void pig() {
if (this.target != null) {
- ctx.player().setYRot(this.target.getYaw());
+ final Rotation actual = this.processor.peekRotation(this.target.rotation);
+ ctx.player().setYRot(actual.getYaw());
}
}
+ public Optional getEffectiveRotation() {
+ if (Baritone.settings().freeLook.value) {
+ return Optional.ofNullable(this.serverRotation);
+ }
+ // If freeLook isn't on, just defer to the player's actual rotations
+ return Optional.empty();
+ }
+
@Override
public void onPlayerRotationMove(RotationMoveEvent event) {
if (this.target != null) {
+ final Rotation actual = this.processor.peekRotation(this.target.rotation);
+ event.setYaw(actual.getYaw());
+ event.setPitch(actual.getPitch());
+ }
+ }
- event.setYaw(this.target.getYaw());
+ private static final class AimProcessor extends AbstractAimProcessor {
- // If we have antiCheatCompatibility on, we're going to use the target value later in onPlayerUpdate()
- // Also the type has to be MOTION_UPDATE because that is called after JUMP
- if (!Baritone.settings().antiCheatCompatibility.value && event.getType() == RotationMoveEvent.Type.MOTION_UPDATE && !this.force) {
- this.target = null;
+ public AimProcessor(final IPlayerContext ctx) {
+ super(ctx);
+ }
+
+ @Override
+ protected Rotation getPrevRotation() {
+ // Implementation will use LookBehavior.serverRotation
+ return ctx.playerRotations();
+ }
+ }
+
+ private static abstract class AbstractAimProcessor implements ITickableAimProcessor {
+
+ protected final IPlayerContext ctx;
+ private final ForkableRandom rand;
+ private double randomYawOffset;
+ private double randomPitchOffset;
+
+ 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)
+ ).clamp();
+ }
+
+ @Override
+ public final void tick() {
+ // randomLooking
+ this.randomYawOffset = (this.rand.nextDouble() - 0.5) * Baritone.settings().randomLooking.value;
+ this.randomPitchOffset = (this.rand.nextDouble() - 0.5) * Baritone.settings().randomLooking.value;
+
+ // randomLooking113
+ double random = this.rand.nextDouble() - 0.5;
+ if (Math.abs(random) < 0.1) {
+ random *= 4;
+ }
+ this.randomYawOffset += random * Baritone.settings().randomLooking113.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 double deltaPx = angleToMouse(delta); // yes, even the mouse movements use double
+ return current + mouseToAngle(deltaPx);
+ }
+
+ private double angleToMouse(float angleDelta) {
+ final float minAngleChange = mouseToAngle(1);
+ return Math.round(angleDelta / minAngleChange);
+ }
+
+ private float mouseToAngle(double mouseDelta) {
+ // casting float literals to double gets us the precise values used by mc
+ final double f = ctx.minecraft().options.sensitivity().get() * (double) 0.6f + (double) 0.2f;
+ return (float) (mouseDelta * f * f * f * 8.0d) * 0.15f; // yes, one double and one float scaling factor
+ }
}
- /**
- * Nudges the player's pitch to a regular level. (Between {@code -20} and {@code 10}, increments are by {@code 1})
- */
- private void nudgeToLevel() {
- if (ctx.player().getXRot() < -20) {
- ctx.player().setXRot(ctx.player().getXRot() + 1);
- } else if (ctx.player().getXRot() > 10) {
- ctx.player().setXRot(ctx.player().getXRot() - 1);
+ private static class Target {
+
+ public final Rotation rotation;
+ public final Mode mode;
+
+ public Target(Rotation rotation, Mode mode) {
+ this.rotation = rotation;
+ this.mode = mode;
+ }
+
+ enum Mode {
+ /**
+ * Rotation will be set client-side and is visual to the player
+ */
+ CLIENT,
+
+ /**
+ * Rotation will be set server-side and is silent to the player
+ */
+ SERVER,
+
+ /**
+ * Rotation will remain unaffected on both the client and server
+ */
+ NONE;
+
+ static Mode resolve(IPlayerContext ctx, boolean blockInteract) {
+ final Settings settings = Baritone.settings();
+ final boolean antiCheat = settings.antiCheatCompatibility.value;
+ final boolean blockFreeLook = settings.blockFreeLook.value;
+
+ if (ctx.player().isFallFlying()) {
+ // always need to set angles while flying
+ return settings.elytraFreeLook.value ? SERVER : CLIENT;
+ } else if (settings.freeLook.value) {
+ // Regardless of if antiCheatCompatibility is enabled, if a blockInteract is requested then the player
+ // rotation needs to be set somehow, otherwise Baritone will halt since objectMouseOver() will just be
+ // whatever the player is mousing over visually. Let's just settle for setting it silently.
+ if (blockInteract) {
+ return blockFreeLook ? SERVER : CLIENT;
+ }
+ return antiCheat ? SERVER : NONE;
+ }
+
+ // all freeLook settings are disabled so set the angles
+ return CLIENT;
+ }
}
}
}
diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java
index f18bd862b..b7c035598 100644
--- a/src/main/java/baritone/behavior/PathingBehavior.java
+++ b/src/main/java/baritone/behavior/PathingBehavior.java
@@ -33,16 +33,16 @@
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.PathExecutor;
+import baritone.process.ElytraProcess;
import baritone.utils.PathRenderer;
import baritone.utils.PathingCommandContext;
import baritone.utils.pathing.Favoring;
-import net.minecraft.core.BlockPos;
-
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
+import net.minecraft.core.BlockPos;
public final class PathingBehavior extends Behavior implements IPathingBehavior, Helper {
@@ -99,6 +99,7 @@ public void onTick(TickEvent event) {
baritone.getPathingControlManager().cancelEverything();
return;
}
+
expectedSegmentStart = pathStart();
baritone.getPathingControlManager().preTick();
tickPath();
@@ -238,11 +239,11 @@ public void onPlayerUpdate(PlayerUpdateEvent event) {
if (current != null) {
switch (event.getState()) {
case PRE:
- lastAutoJump = mc.options.autoJump().get();
- mc.options.autoJump().set(false);
+ lastAutoJump = ctx.minecraft().options.autoJump().get();
+ ctx.minecraft().options.autoJump().set(false);
break;
case POST:
- mc.options.autoJump().set(lastAutoJump);
+ ctx.minecraft().options.autoJump().set(lastAutoJump);
break;
default:
break;
@@ -308,7 +309,10 @@ public Optional getInProgress() {
}
public boolean isSafeToCancel() {
- return current == null || safeToCancel;
+ if (current == null) {
+ return !baritone.getElytraProcess().isActive() || baritone.getElytraProcess().isSafeToCancel();
+ }
+ return safeToCancel;
}
public void requestPause() {
@@ -351,7 +355,7 @@ public void softCancelIfSafe() {
}
// just cancel the current path
- private void secretInternalSegmentCancel() {
+ public void secretInternalSegmentCancel() {
queuePathEvent(PathEvent.CANCELED);
synchronized (pathPlanLock) {
getInProgress().ifPresent(AbstractNodeCostSearch::cancel);
@@ -419,7 +423,7 @@ private void resetEstimatedTicksToGoal(BetterBlockPos start) {
public BetterBlockPos pathStart() { // TODO move to a helper or util class
BetterBlockPos feet = ctx.playerFeet();
if (!MovementHelper.canWalkOn(ctx, feet.below())) {
- if (ctx.player().isOnGround()) {
+ if (ctx.player().onGround()) {
double playerX = ctx.player().position().x;
double playerZ = ctx.player().position().z;
ArrayList closest = new ArrayList<>();
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/cache/CachedChunk.java b/src/main/java/baritone/cache/CachedChunk.java
index 3109d9293..2659c4feb 100644
--- a/src/main/java/baritone/cache/CachedChunk.java
+++ b/src/main/java/baritone/cache/CachedChunk.java
@@ -218,7 +218,7 @@ public final BlockState getBlock(int x, int y, int z, DimensionType dimension) {
// nether roof is always unbreakable
return Blocks.BEDROCK.defaultBlockState();
}
- if (y < 5 && dimension.natural()) {
+ if (y < -59 && dimension.natural()) {
// solid blocks below 5 are commonly bedrock
// however, returning bedrock always would be a little yikes
// discourage paths that include breaking blocks below 5 a little more heavily just so that it takes paths breaking what's known to be stone (at 5 or above) instead of what could maybe be bedrock (below 5)
diff --git a/src/main/java/baritone/cache/CachedRegion.java b/src/main/java/baritone/cache/CachedRegion.java
index 6c70f1eba..8aa992d79 100644
--- a/src/main/java/baritone/cache/CachedRegion.java
+++ b/src/main/java/baritone/cache/CachedRegion.java
@@ -167,7 +167,7 @@ public synchronized final void save(String directory) {
out.writeShort(entry.getValue().size());
for (BlockPos pos : entry.getValue()) {
out.writeByte((byte) (pos.getZ() << 4 | pos.getX()));
- out.writeInt(pos.getY() - dimension.minY());
+ out.writeInt(pos.getY()-dimension.minY());
}
}
}
@@ -272,7 +272,7 @@ public synchronized void load(String directory) {
int X = xz & 0x0f;
int Z = (xz >>> 4) & 0x0f;
int Y = in.readInt();
- locs.add(new BlockPos(X, Y + dimension.minY(), Z));
+ locs.add(new BlockPos(X, Y+dimension.minY(), Z));
}
}
}
diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java
index 2384d1c58..aed1faeb5 100644
--- a/src/main/java/baritone/cache/CachedWorld.java
+++ b/src/main/java/baritone/cache/CachedWorld.java
@@ -23,6 +23,7 @@
import baritone.api.cache.ICachedWorld;
import baritone.api.cache.IWorldData;
import baritone.api.utils.Helper;
+import com.google.common.cache.CacheBuilder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.core.BlockPos;
@@ -36,7 +37,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
/**
@@ -70,7 +70,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
* All chunk positions pending packing. This map will be updated in-place if a new update to the chunk occurs
* while waiting in the queue for the packer thread to get to it.
*/
- private final Map toPackMap = new ConcurrentHashMap<>();
+ private final Map toPackMap = CacheBuilder.newBuilder().softValues().build().asMap();
private final DimensionType dimension;
@@ -196,9 +196,7 @@ private synchronized void prune() {
int distZ = ((region.getZ() << 9) + 256) - pruneCenter.getZ();
double dist = Math.sqrt(distX * distX + distZ * distZ);
if (dist > 1024) {
- if (!Baritone.settings().censorCoordinates.value) {
- logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram");
- }
+ logDebug("Deleting cached region from ram");
cachedRegions.remove(getRegionID(region.getX(), region.getZ()));
}
}
@@ -308,6 +306,9 @@ public void run() {
try {
ChunkPos pos = toPackQueue.take();
LevelChunk chunk = toPackMap.remove(pos);
+ if (toPackQueue.size() > Baritone.settings().chunkPackerQueueMaxSize.value) {
+ continue;
+ }
CachedChunk cached = ChunkPacker.pack(chunk);
CachedWorld.this.updateCachedChunk(cached);
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);
diff --git a/src/main/java/baritone/cache/ChunkPacker.java b/src/main/java/baritone/cache/ChunkPacker.java
index b90b74432..5d619543d 100644
--- a/src/main/java/baritone/cache/ChunkPacker.java
+++ b/src/main/java/baritone/cache/ChunkPacker.java
@@ -21,7 +21,12 @@
import baritone.pathing.movement.MovementHelper;
import baritone.utils.pathing.PathingBlockType;
import net.minecraft.core.BlockPos;
-import net.minecraft.world.level.block.*;
+import net.minecraft.world.level.block.AirBlock;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.DoublePlantBlock;
+import net.minecraft.world.level.block.FlowerBlock;
+import net.minecraft.world.level.block.TallGrassBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
@@ -40,8 +45,7 @@
*/
public final class ChunkPacker {
- private ChunkPacker() {
- }
+ private ChunkPacker() {}
public static CachedChunk pack(LevelChunk chunk) {
//long start = System.nanoTime() / 1000000L;
@@ -80,7 +84,7 @@ public static CachedChunk pack(LevelChunk chunk) {
Block block = state.getBlock();
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(block)) {
String name = BlockUtils.blockToString(block);
- specialBlocks.computeIfAbsent(name, b -> new ArrayList<>()).add(new BlockPos(x, y + chunk.getMinBuildHeight(), z));
+ specialBlocks.computeIfAbsent(name, b -> new ArrayList<>()).add(new BlockPos(x, y+chunk.getMinBuildHeight(), z));
}
}
}
@@ -96,8 +100,7 @@ public static CachedChunk pack(LevelChunk chunk) {
// get top block in columns
// @formatter:off
for (int z = 0; z < 16; z++) {
- https:
-//www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html
+ https://www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html
for (int x = 0; x < 16; x++) {
for (int y = height - 1; y >= 0; y--) {
int index = CachedChunk.getPositionIndex(x, y, z);
diff --git a/src/main/java/baritone/cache/FasterWorldScanner.java b/src/main/java/baritone/cache/FasterWorldScanner.java
new file mode 100644
index 000000000..e364fd7b4
--- /dev/null
+++ b/src/main/java/baritone/cache/FasterWorldScanner.java
@@ -0,0 +1,303 @@
+/*
+ * 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.cache;
+
+import baritone.api.cache.ICachedWorld;
+import baritone.api.cache.IWorldScanner;
+import baritone.api.utils.BetterBlockPos;
+import baritone.api.utils.BlockOptionalMeta;
+import baritone.api.utils.BlockOptionalMetaLookup;
+import baritone.api.utils.IPlayerContext;
+import baritone.utils.accessor.IPalettedContainer;
+import io.netty.buffer.Unpooled;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.IdMapper;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.util.BitStorage;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.chunk.GlobalPalette;
+import net.minecraft.world.level.chunk.ChunkSource;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.Palette;
+import net.minecraft.world.level.chunk.PalettedContainer;
+import net.minecraft.world.level.chunk.SingleValuePalette;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public enum FasterWorldScanner implements IWorldScanner {
+ INSTANCE;
+
+ private static final BlockState[] PALETTE_REGISTRY_SENTINEL = new BlockState[0];
+
+ @Override
+ public List scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius) {
+ assert ctx.world() != null;
+ if (maxSearchRadius < 0) {
+ throw new IllegalArgumentException("chunkRange must be >= 0");
+ }
+ return scanChunksInternal(ctx, filter, getChunkRange(ctx.playerFeet().x >> 4, ctx.playerFeet().z >> 4, maxSearchRadius), max);
+ }
+
+ @Override
+ public List scanChunk(IPlayerContext ctx, BlockOptionalMetaLookup filter, ChunkPos pos, int max, int yLevelThreshold) {
+ Stream stream = scanChunkInternal(ctx, filter, pos);
+ if (max >= 0) {
+ stream = stream.limit(max);
+ }
+ return stream.collect(Collectors.toList());
+ }
+
+ @Override
+ public int repack(IPlayerContext ctx) {
+ return this.repack(ctx, 40);
+ }
+
+ @Override
+ public int repack(IPlayerContext ctx, int range) {
+ ChunkSource chunkProvider = ctx.world().getChunkSource();
+ ICachedWorld cachedWorld = ctx.worldData().getCachedWorld();
+
+ BetterBlockPos playerPos = ctx.playerFeet();
+
+ int playerChunkX = playerPos.getX() >> 4;
+ int playerChunkZ = playerPos.getZ() >> 4;
+
+ int minX = playerChunkX - range;
+ int minZ = playerChunkZ - range;
+ int maxX = playerChunkX + range;
+ int maxZ = playerChunkZ + range;
+
+ int queued = 0;
+ for (int x = minX; x <= maxX; x++) {
+ for (int z = minZ; z <= maxZ; z++) {
+ LevelChunk chunk = chunkProvider.getChunk(x, z, false);
+
+ if (chunk != null && !chunk.isEmpty()) {
+ queued++;
+ cachedWorld.queueForPacking(chunk);
+ }
+ }
+ }
+
+ return queued;
+ }
+
+ // ordered in a way that the closest blocks are generally first
+ public static List getChunkRange(int centerX, int centerZ, int chunkRadius) {
+ List chunks = new ArrayList<>();
+ // spiral out
+ chunks.add(new ChunkPos(centerX, centerZ));
+ for (int i = 1; i < chunkRadius; i++) {
+ for (int j = 0; j <= i; j++) {
+ chunks.add(new ChunkPos(centerX - j, centerZ - i));
+ if (j != 0) {
+ chunks.add(new ChunkPos(centerX + j, centerZ - i));
+ chunks.add(new ChunkPos(centerX - j, centerZ + i));
+ }
+ chunks.add(new ChunkPos(centerX + j, centerZ + i));
+ if (j != i) {
+ chunks.add(new ChunkPos(centerX - i, centerZ - j));
+ chunks.add(new ChunkPos(centerX + i, centerZ - j));
+ if (j != 0) {
+ chunks.add(new ChunkPos(centerX - i, centerZ + j));
+ chunks.add(new ChunkPos(centerX + i, centerZ + j));
+ }
+ }
+ }
+ }
+ return chunks;
+ }
+
+ private List scanChunksInternal(IPlayerContext ctx, BlockOptionalMetaLookup lookup, List chunkPositions, int maxBlocks) {
+ assert ctx.world() != null;
+ try {
+ // p -> scanChunkInternal(ctx, lookup, p)
+ Stream posStream = chunkPositions.parallelStream().flatMap(p -> scanChunkInternal(ctx, lookup, p));
+ if (maxBlocks >= 0) {
+ // WARNING: this can be expensive if maxBlocks is large...
+ // see limit's javadoc
+ posStream = posStream.limit(maxBlocks);
+ }
+ return posStream.collect(Collectors.toList());
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ private Stream scanChunkInternal(IPlayerContext ctx, BlockOptionalMetaLookup lookup, ChunkPos pos) {
+ ChunkSource chunkProvider = ctx.world().getChunkSource();
+ // if chunk is not loaded, return empty stream
+ if (!chunkProvider.hasChunk(pos.x, pos.z)) {
+ return Stream.empty();
+ }
+
+ long chunkX = (long) pos.x << 4;
+ long chunkZ = (long) pos.z << 4;
+
+ int playerSectionY = (ctx.playerFeet().y - ctx.world().getMinBuildHeight()) >> 4;
+
+ return collectChunkSections(lookup, chunkProvider.getChunk(pos.x, pos.z, false), chunkX, chunkZ, playerSectionY).stream();
+ }
+
+
+ private List collectChunkSections(BlockOptionalMetaLookup lookup, LevelChunk chunk, long chunkX, long chunkZ, int playerSection) {
+ // iterate over sections relative to player
+ List blocks = new ArrayList<>();
+ int chunkY = chunk.getMinBuildHeight();
+ LevelChunkSection[] sections = chunk.getSections();
+ int l = sections.length;
+ int i = playerSection - 1;
+ int j = playerSection;
+ for (; i >= 0 || j < l; ++j, --i) {
+ if (j < l) {
+ visitSection(lookup, sections[j], blocks, chunkX, chunkY + j * 16, chunkZ);
+ }
+ if (i >= 0) {
+ visitSection(lookup, sections[i], blocks, chunkX, chunkY + i * 16, chunkZ);
+ }
+ }
+ return blocks;
+ }
+
+ private void visitSection(BlockOptionalMetaLookup lookup, LevelChunkSection section, List blocks, long chunkX, int sectionY, long chunkZ) {
+ if (section == null || section.hasOnlyAir()) {
+ return;
+ }
+
+ PalettedContainer sectionContainer = section.getStates();
+ //this won't work if the PaletteStorage is of the type EmptyPaletteStorage
+ if (((IPalettedContainer) sectionContainer).getStorage() == null) {
+ return;
+ }
+
+ Palette palette = ((IPalettedContainer) sectionContainer).getPalette();
+
+ if (palette instanceof SingleValuePalette) {
+ // single value palette doesn't have any data
+ if (lookup.has(palette.valueFor(0))) {
+ // TODO this is 4k hits, maybe don't return all of them?
+ for (int x = 0; x < 16; ++x) {
+ for (int y = 0; y < 16; ++y) {
+ for (int z = 0; z < 16; ++z) {
+ blocks.add(new BlockPos(
+ (int) chunkX + x,
+ sectionY + y,
+ (int) chunkZ + z
+ ));
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ boolean[] isInFilter = getIncludedFilterIndices(lookup, palette);
+ if (isInFilter.length == 0) {
+ return;
+ }
+
+ BitStorage array = ((IPalettedContainer) section.getStates()).getStorage();
+ long[] longArray = array.getRaw();
+ int arraySize = array.getSize();
+ int bitsPerEntry = array.getBits();
+ long maxEntryValue = (1L << bitsPerEntry) - 1L;
+
+ for (int i = 0, idx = 0; i < longArray.length && idx < arraySize; ++i) {
+ long l = longArray[i];
+ for (int offset = 0; offset <= (64 - bitsPerEntry) && idx < arraySize; offset += bitsPerEntry, ++idx) {
+ int value = (int) ((l >> offset) & maxEntryValue);
+ if (isInFilter[value]) {
+ //noinspection DuplicateExpressions
+ blocks.add(new BlockPos(
+ (int) chunkX + ((idx & 255) & 15),
+ sectionY + (idx >> 8),
+ (int) chunkZ + ((idx & 255) >> 4)
+ ));
+ }
+ }
+ }
+ }
+
+ private boolean[] getIncludedFilterIndices(BlockOptionalMetaLookup lookup, Palette palette) {
+ boolean commonBlockFound = false;
+ BlockState[] paletteMap = getPalette(palette);
+
+ if (paletteMap == PALETTE_REGISTRY_SENTINEL) {
+ return getIncludedFilterIndicesFromRegistry(lookup);
+ }
+
+ int size = paletteMap.length;
+
+ boolean[] isInFilter = new boolean[size];
+
+ for (int i = 0; i < size; i++) {
+ BlockState state = paletteMap[i];
+ if (lookup.has(state)) {
+ isInFilter[i] = true;
+ commonBlockFound = true;
+ } else {
+ isInFilter[i] = false;
+ }
+ }
+
+ if (!commonBlockFound) {
+ return new boolean[0];
+ }
+ return isInFilter;
+ }
+
+ private boolean[] getIncludedFilterIndicesFromRegistry(BlockOptionalMetaLookup lookup) {
+ boolean[] isInFilter = new boolean[Block.BLOCK_STATE_REGISTRY.size()];
+
+ for (BlockOptionalMeta bom : lookup.blocks()) {
+ for (BlockState state : bom.getAllBlockStates()) {
+ isInFilter[Block.BLOCK_STATE_REGISTRY.getId(state)] = true;
+ }
+ }
+
+ return isInFilter;
+ }
+
+ /**
+ * cheats to get the actual map of id -> blockstate from the various palette implementations
+ */
+ private static BlockState[] getPalette(Palette palette) {
+ if (palette instanceof GlobalPalette) {
+ // copying the entire registry is not nice so we treat it as a special case
+ return PALETTE_REGISTRY_SENTINEL;
+ } else {
+ FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
+ palette.write(buf);
+ int size = buf.readVarInt();
+ BlockState[] states = new BlockState[size];
+ for (int i = 0; i < size; i++) {
+ BlockState state = Block.BLOCK_STATE_REGISTRY.byId(buf.readVarInt());
+ assert state != null;
+ states[i] = state;
+ }
+ return states;
+ }
+ }
+}
diff --git a/src/main/java/baritone/cache/WaypointCollection.java b/src/main/java/baritone/cache/WaypointCollection.java
index 52dd1f539..222adfdf6 100644
--- a/src/main/java/baritone/cache/WaypointCollection.java
+++ b/src/main/java/baritone/cache/WaypointCollection.java
@@ -48,8 +48,7 @@ public class WaypointCollection implements IWaypointCollection {
if (!Files.exists(directory)) {
try {
Files.createDirectories(directory);
- } catch (IOException ignored) {
- }
+ } catch (IOException ignored) {}
}
System.out.println("Would save waypoints to " + directory);
this.waypoints = new HashMap<>();
@@ -89,8 +88,7 @@ private synchronized void load(Waypoint.Tag tag) {
int z = in.readInt();
this.waypoints.get(tag).add(new Waypoint(name, tag, new BetterBlockPos(x, y, z), creationTimestamp));
}
- } catch (IOException ignored) {
- }
+ } catch (IOException ignored) {}
}
private synchronized void save(Waypoint.Tag tag) {
diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java
index 0fc89c3e9..38202e65b 100644
--- a/src/main/java/baritone/cache/WorldProvider.java
+++ b/src/main/java/baritone/cache/WorldProvider.java
@@ -19,123 +19,163 @@
import baritone.Baritone;
import baritone.api.cache.IWorldProvider;
-import baritone.api.utils.Helper;
-import net.minecraft.client.server.IntegratedServer;
-import net.minecraft.resources.ResourceKey;
+import baritone.api.utils.IPlayerContext;
+import net.minecraft.client.multiplayer.ServerData;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.util.Tuple;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.storage.LevelResource;
import org.apache.commons.lang3.SystemUtils;
-import java.io.FileOutputStream;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
-import java.util.function.Consumer;
+import java.util.Optional;
/**
* @author Brady
* @since 8/4/2018
*/
-public class WorldProvider implements IWorldProvider, Helper {
+public class WorldProvider implements IWorldProvider {
- private static final Map worldCache = new HashMap<>(); // this is how the bots have the same cached world
+ private static final Map worldCache = new HashMap<>();
+ private final Baritone baritone;
+ private final IPlayerContext ctx;
private WorldData currentWorld;
+ /**
+ * This lets us detect a broken load/unload hook.
+ * @see #detectAndHandleBrokenLoading()
+ */
+ private Level mcWorld;
+
+ public WorldProvider(Baritone baritone) {
+ this.baritone = baritone;
+ this.ctx = baritone.getPlayerContext();
+ }
+
@Override
public final WorldData getCurrentWorld() {
- // attempt reload if the worldData is null
- if (currentWorld == null && mc.level != null) {
- initWorld(mc.level.dimension(), mc.level.dimensionType());
- }
+ this.detectAndHandleBrokenLoading();
return this.currentWorld;
}
/**
* Called when a new world is initialized to discover the
*
- * @param world The world's Registry Data
+ * @param world The new world
*/
- public final void initWorld(ResourceKey worldKey, DimensionType world) {
- Path directory;
- Path readme;
+ public final void initWorld(Level world) {
+ this.getSaveDirectories(world).ifPresent(dirs -> {
+ final Path worldDir = dirs.getA();
+ final Path readmeDir = dirs.getB();
+
+ try {
+ // lol wtf is this baritone folder in my minecraft save?
+ // good thing we have a readme
+ Files.createDirectories(readmeDir);
+ Files.write(
+ readmeDir.resolve("readme.txt"),
+ "https://github.com/cabaletta/baritone\n".getBytes(StandardCharsets.US_ASCII)
+ );
+ } catch (IOException ignored) {}
+
+ // We will actually store the world data in a subfolder: "DIM"
+ final Path worldDataDir = this.getWorldDataDirectory(worldDir, world);
+ try {
+ Files.createDirectories(worldDataDir);
+ } catch (IOException ignored) {}
+
+ System.out.println("Baritone world data dir: " + worldDataDir);
+ synchronized (worldCache) {
+ this.currentWorld = worldCache.computeIfAbsent(worldDataDir, d -> new WorldData(d, world.dimensionType()));
+ }
+ this.mcWorld = ctx.world();
+ });
+ }
- IntegratedServer integratedServer = mc.getSingleplayerServer();
+ public final void closeWorld() {
+ WorldData world = this.currentWorld;
+ this.currentWorld = null;
+ this.mcWorld = null;
+ if (world == null) {
+ return;
+ }
+ world.onClose();
+ }
+
+ private Path getWorldDataDirectory(Path parent, Level world) {
+ ResourceLocation dimId = world.dimension().location();
+ int height = world.dimensionType().logicalHeight();
+ return parent.resolve(dimId.getNamespace()).resolve(dimId.getPath() + "_" + height);
+ }
+
+ /**
+ * @param world The world
+ * @return An {@link Optional} containing the world's baritone dir and readme dir, or {@link Optional#empty()} if
+ * the world isn't valid for caching.
+ */
+ private Optional