diff --git a/README.md b/README.md index e2c83ddec..c6a90ff93 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,16 @@

- Minecraft - Minecraft - Minecraft - Minecraft - Minecraft - Minecraft - Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft

@@ -33,7 +36,7 @@

Impact integration - KAMI Blue integration + Lambda integration ForgeHax integration Aristois add-on integration rootNET integration @@ -48,21 +51,26 @@ A Minecraft pathfinder bot. +Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do. + [**Baritone Discord Server**](http://discord.gg/s6fRBAUpmr) -Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#0730 on Baritone which I recommend. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do. +**Quick download links:** -[Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa) +| Forge | Fabric | +|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------| +| [1.12.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.2.17/baritone-api-forge-1.2.17.jar) | | +| [1.16.5 Forge](https://github.com/cabaletta/baritone/releases/download/v1.6.4/baritone-api-forge-1.6.4.jar) | [1.16.5 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.6.4/baritone-api-fabric-1.6.4.jar) | +| [1.17.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.7.3/baritone-api-forge-1.7.3.jar) | [1.17.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.7.3/baritone-api-fabric-1.7.3.jar) | +| [1.18.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.8.4/baritone-api-forge-1.8.4.jar) | [1.18.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.8.4/baritone-api-fabric-1.8.4.jar) | +| [1.19.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.4/baritone-api-forge-1.9.4.jar) | [1.19.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.4/baritone-api-fabric-1.9.4.jar) | +| [1.19.3 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.1/baritone-api-forge-1.9.1.jar) | [1.19.3 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.1/baritone-api-fabric-1.9.1.jar) | +| [1.19.4 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-forge-1.9.3.jar) | [1.19.4 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-fabric-1.9.3.jar) | +| [1.20.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-forge-1.10.1.jar) | [1.20.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-fabric-1.10.1.jar) | -The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to -install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click -[here](https://github.com/cabaletta/baritone/releases/download/v1.2.17/baritone-api-forge-1.2.17.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. +**How to immediately get started:** Type `#goto 1000 500` in chat to go to x=1000 z=500. Type `#mine diamond_ore` to mine diamond ore. Type `#stop` to stop. For more, read [the usage page](USAGE.md) and/or watch this [tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa) -For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. If you need Forge or Fabric 1.16.5, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.6.3) and get the `api-forge` or `api-fabric` jar. **For 1.16.5 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.6.3/baritone-api-fabric-1.6.3.jar)**. - -If you need Forge or Fabric 1.17.1, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.7.2) and get the `api-forge` or `api-fabric` jar. **For 1.17.1 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.7.2/baritone-api-fabric-1.7.2.jar)**. - -If you need Forge or Fabric 1.18.2, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.8.3) and get the `api-forge` or `api-fabric` jar. **For 1.18.2 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.8.3/baritone-api-fabric-1.8.3.jar)**. **For 1.18.2 Forge, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.8.3/baritone-api-forge-1.8.3.jar)**. +For other versions of Minecraft or more complicated situations or for development, see [Installation & setup](SETUP.md). Also consider just installing [Impact](https://impactclient.net/), which comes with Baritone and is easier to install than wrangling with version JSONs and zips. For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#6313 on Baritone which I recommend. This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/), the original version of the bot for Minecraft 1.8.9, rebuilt for 1.12.2 onwards. Baritone focuses on reliability and particularly performance (it's over [30x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths). diff --git a/SETUP.md b/SETUP.md index 57866b192..1daeb9f89 100644 --- a/SETUP.md +++ b/SETUP.md @@ -43,13 +43,13 @@ If another one of your Forge mods has a Baritone integration, you want `baritone ## Command Line On Mac OSX and Linux, use `./gradlew` instead of `gradlew`. -If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8 for 1.12.2-1.16.5, JDK 16 for 1.17.1, and JDK 17 for 1.18.1. +If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8 for 1.12.2-1.16.5, JDK 16+ for 1.17.1, and JDK 17+ for 1.18.1. To check which java you are using do `java -version` in a command prompt or terminal. If you are using anything above OpenJDK 8 for 1.12.2-1.16.5, it might not work because the Java distributions above JDK 8 using may not have the needed javax classes. -Open JDK download: https://openjdk.java.net/install/ +Download java: https://adoptium.net/ #### macOS guide In order to get JDK 8, Try running the following command: `% /usr/libexec/java_home -V` @@ -66,68 +66,13 @@ In order to get JDK 8 running in the **current terminal window** you will have t To add OpenJDK 8 to your PATH add the export line to the end of your `.zshrc / .bashrc` if you want it to apply to each new terminal. If you're using bash change the .bachrc and if you're using zsh change the .zshrc -Setting up the Environment: +### Building Baritone -``` -$ gradlew setupDecompWorkspace -$ gradlew --refresh-dependencies -``` +These tasks depend on the minecraft version, but are (for the most part) standard for building mods. -Building Baritone: - -``` -$ gradlew build -``` - -For minecraft 1.15.2+, run the following instead to include the Forge jars: - -``` -$ gradlew build -Pbaritone.forge_build -``` - -Do this instead for Fabric jars: - -``` -$ gradlew build -Pbaritone.fabric_build -``` - -Running Baritone: - -``` -$ gradlew runClient -``` - -For information on how to build baritone, see [Building Baritone](#building-baritone) +for more details, see [the build ci action](/.github/workflows/gradle_build.yml) ## IntelliJ - Open the project in IntelliJ as a Gradle project - - ![Image](https://i.imgur.com/jw7Q6vY.png) - -- Run the Gradle tasks `setupDecompWorkspace` then `genIntellijRuns` - - ![Image](https://i.imgur.com/QEfVvWP.png) - - Refresh the Gradle project (or, to be safe, just restart IntelliJ) - - ![Image](https://i.imgur.com/3V7EdWr.png) - -- Select the "Minecraft Client" launch config - - ![Image](https://i.imgur.com/1qz2QGV.png) - -- Click on ``Edit Configurations...`` from the same dropdown and select the "Minecraft Client" config - - ![Image](https://i.imgur.com/s4ly0ZF.png) - -- In `Edit Configurations...` you need to select `baritone_launch` for `Use classpath of module:`. - - ![Image](https://i.imgur.com/hrLhG9u.png) - -## IntelliJ - -- Navigate to the gradle tasks on the right tab as follows - - ![Image](https://i.imgur.com/PE6r9iN.png) - -- Double click on **build** to run it +- depending on the minecraft version, you may need to run `setupDecompWorkspace` or `genIntellijRuns` in order to get everything working \ No newline at end of file diff --git a/src/api/java/baritone/api/BaritoneAPI.java b/src/api/java/baritone/api/BaritoneAPI.java index 53937bd80..935bf9e4f 100644 --- a/src/api/java/baritone/api/BaritoneAPI.java +++ b/src/api/java/baritone/api/BaritoneAPI.java @@ -35,7 +35,7 @@ public final class BaritoneAPI { static { settings = new Settings(); - SettingsUtil.readAndApply(settings); + SettingsUtil.readAndApply(settings, SettingsUtil.SETTINGS_DEFAULT_NAME); ServiceLoader baritoneLoader = ServiceLoader.load(IBaritoneProvider.class); Iterator instances = baritoneLoader.iterator(); diff --git a/src/api/java/baritone/api/IBaritoneProvider.java b/src/api/java/baritone/api/IBaritoneProvider.java index e4f2ffc30..94c410ed5 100644 --- a/src/api/java/baritone/api/IBaritoneProvider.java +++ b/src/api/java/baritone/api/IBaritoneProvider.java @@ -21,6 +21,7 @@ import baritone.api.cache.IWorldScanner; import baritone.api.command.ICommand; import baritone.api.command.ICommandSystem; import baritone.api.schematic.ISchematicSystem; +import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import java.util.List; @@ -52,15 +53,13 @@ public interface IBaritoneProvider { List getAllBaritones(); /** - * Provides the {@link IBaritone} instance for a given {@link ClientPlayerEntity}. This will likely be - * replaced with or be overloaded in addition to {@code #getBaritoneForUser(IBaritoneUser)} when - * {@code bot-system} is merged into {@code master}. + * Provides the {@link IBaritone} instance for a given {@link ClientPlayerEntity}. * * @param player The player * @return The {@link IBaritone} instance. */ default IBaritone getBaritoneForPlayer(ClientPlayerEntity player) { - for (IBaritone baritone : getAllBaritones()) { + for (IBaritone baritone : this.getAllBaritones()) { if (Objects.equals(player, baritone.getPlayerContext().player())) { return baritone; } @@ -68,6 +67,39 @@ public interface IBaritoneProvider { return null; } + /** + * Provides the {@link IBaritone} instance for a given {@link Minecraft}. + * + * @param minecraft The minecraft + * @return The {@link IBaritone} instance. + */ + default IBaritone getBaritoneForMinecraft(Minecraft minecraft) { + for (IBaritone baritone : this.getAllBaritones()) { + if (Objects.equals(minecraft, baritone.getPlayerContext().minecraft())) { + return baritone; + } + } + return null; + } + + /** + * Creates and registers a new {@link IBaritone} instance using the specified {@link Minecraft}. The existing + * instance is returned if already registered. + * + * @param minecraft The minecraft + * @return The {@link IBaritone} instance + */ + IBaritone createBaritone(Minecraft minecraft); + + /** + * Destroys and removes the specified {@link IBaritone} instance. If the specified instance is the + * {@link #getPrimaryBaritone() primary baritone}, this operation has no effect and will return {@code false}. + * + * @param baritone The baritone instance to remove + * @return Whether the baritone instance was removed + */ + boolean destroyBaritone(IBaritone baritone); + /** * Returns the {@link IWorldScanner} instance. This is not a type returned by * {@link IBaritone} implementation, because it is not linked with {@link IBaritone}. diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 655cad0e2..e3e048353 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -29,6 +29,10 @@ import net.minecraft.util.math.Vec3i; import net.minecraft.util.text.ITextComponent; import java.awt.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -69,6 +73,16 @@ public final class Settings { */ public final Setting allowInventory = new Setting<>(false); + /** + * Wait this many ticks between InventoryBehavior moving inventory items + */ + public final Setting ticksBetweenInventoryMoves = new Setting<>(1); + + /** + * Come to a halt before doing any inventory moves. Intended for anticheat such as 2b2t + */ + public final Setting inventoryMoveOnlyIfStationary = new Setting<>(false); + /** * Disable baritone's auto-tool at runtime, but still assume that another mod will provide auto tool functionality *

@@ -610,6 +624,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 */ @@ -711,6 +732,17 @@ 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); + + /** + * 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. *

@@ -845,6 +877,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<>(255); // 1.17+ defaults to maximum possible world height + /** * This will only allow baritone to mine exposed ores, can be used to stop ore obfuscators on servers that use them. */ @@ -1141,6 +1178,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> logger = new Setting<>(msg -> Minecraft.getInstance().ingameGUI.getChatGUI().printChatMessage(msg)); /** @@ -1148,6 +1186,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> notifier = new Setting<>(NotificationHelper::notify); /** @@ -1155,6 +1194,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); /** @@ -1299,6 +1339,7 @@ public final class Settings { public T value; public final T defaultValue; private String name; + private boolean javaOnly; @SuppressWarnings("unchecked") private Setting(T value) { @@ -1307,6 +1348,7 @@ public final class Settings { } this.value = value; this.defaultValue = value; + this.javaOnly = false; } /** @@ -1343,8 +1385,25 @@ public final class Settings { 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() { @@ -1360,6 +1419,7 @@ public final class Settings { 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/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 @@ import baritone.api.utils.Rotation; 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/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/command/datatypes/BlockById.java b/src/api/java/baritone/api/command/datatypes/BlockById.java index 113238df0..1ad4f552d 100644 --- a/src/api/java/baritone/api/command/datatypes/BlockById.java +++ b/src/api/java/baritone/api/command/datatypes/BlockById.java @@ -23,11 +23,17 @@ import net.minecraft.block.Block; import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; +import java.util.regex.Pattern; import java.util.stream.Stream; public enum BlockById implements IDatatypeFor { INSTANCE; + /** + * Matches (domain:)?name? where domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ respectively. + */ + private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?[a-z0-9/_.-]*"); + @Override public Block get(IDatatypeContext ctx) throws CommandException { ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString()); @@ -40,13 +46,19 @@ public enum BlockById implements IDatatypeFor { @Override public Stream tabComplete(IDatatypeContext ctx) throws CommandException { + String arg = ctx.getConsumer().getString(); + + if (!PATTERN.matcher(arg).matches()) { + return Stream.empty(); + } + return new TabCompleteHelper() .append( Registry.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..37d112929 --- /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.util.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..2a1b01b4d 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.block.Block; +import net.minecraft.state.IProperty; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; +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 = Registry.BLOCK.getValue(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.getStateContainer() + .getProperties() + .stream() + .map(IProperty::getName) + ) + .filter(prop -> !usedProps.contains(prop)) + .filterPrefix(lastProperty) + .sortAlphabetically() + .map(prop -> prefix + prop) + .stream(); + } + + String lastName, lastValue; + { + String[] parts = splitLast(lastProperty, '='); + lastName = parts[0]; + lastValue = parts[1]; + } + + // We are completing the value of a property + String prefix = arg.substring(0, arg.length() - lastValue.length()); + + IProperty property = block.getStateContainer().getProperty(lastName); + if (property == null) { + // The property does not exist so there's no values to complete + return Stream.empty(); + } + + return new TabCompleteHelper() + .append(getValues(property)) + .filterPrefix(lastValue) + .sortAlphabetically() + .map(val -> prefix + val) + .stream(); + } + + /** + * Always returns exactly two strings. + * If the separator is not found the FIRST returned string is empty. + */ + private static String[] splitLast(String string, char chr) { + int idx = string.lastIndexOf(chr); + if (idx == -1) { + return new String[]{"", string}; + } + return new String[]{string.substring(0, idx), string.substring(idx + 1)}; + } + + // this shouldn't need to be a separate method? + private static > Stream getValues(IProperty property) { + return property.getAllowedValues().stream().map(property::getName); } } diff --git a/src/api/java/baritone/api/command/datatypes/RelativeFile.java b/src/api/java/baritone/api/command/datatypes/RelativeFile.java index 0bc3604ab..6eccbb302 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 @@ package baritone.api.command.datatypes; 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.Locale; 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 enum RelativeFile implements IDatatypePost { .filter(s -> !s.contains(" ")); } + @Deprecated public static File gameDir() { - File gameDir = HELPER.mc.gameDir.getAbsoluteFile(); + return gameDir(Helper.mc); + } + + public static File gameDir(Minecraft mc) { + File gameDir = mc.gameDir.getAbsoluteFile(); if (gameDir.getName().equals(".")) { return gameDir.getParentFile(); } diff --git a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java index e438da308..96706d08b 100644 --- a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java +++ b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java @@ -253,7 +253,7 @@ public class TabCompleteHelper { 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/event/events/RotationMoveEvent.java b/src/api/java/baritone/api/event/events/RotationMoveEvent.java index e8c8917a3..1f4a74192 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.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.util.math.Vec3d; @@ -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 final class RotationMoveEvent { * * @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/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 class GoalAxis implements Goal { 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 bd339549b..24faa9b34 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalBlock.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -66,6 +67,26 @@ public class GoalBlock implements Goal, IGoalRenderPos { 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 class GoalComposite implements Goal { 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 8d6fdcb30..b8934a480 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -60,6 +61,26 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos { 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 class GoalInverted implements Goal { 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 2252446cd..e211c0194 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalNear.java +++ b/src/api/java/baritone/api/pathing/goals/GoalNear.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import it.unimi.dsi.fastutil.doubles.DoubleIterator; @@ -86,6 +87,27 @@ public class GoalNear implements Goal, IGoalRenderPos { 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 b704ae4a6..1e65d30f7 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 it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; import net.minecraft.util.math.BlockPos; import java.util.Arrays; +import java.util.Objects; /** * Useful for automated combat (retreating specifically) @@ -124,6 +125,29 @@ public class GoalRunAway implements Goal { 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 cd9fef200..00f3db238 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java +++ b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -69,6 +70,31 @@ public class GoalStrictDirection implements Goal { 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 27be981e4..475d6e972 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java +++ b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java @@ -17,6 +17,7 @@ package baritone.api.pathing.goals; +import baritone.api.utils.BetterBlockPos; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -72,6 +73,26 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos { 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 63d39cd78..1c7535b38 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 class GoalXZ implements Goal { 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 class GoalYLevel implements Goal, ActionCosts { 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 65711246b..8df6d949b 100644 --- a/src/api/java/baritone/api/process/IBuilderProcess.java +++ b/src/api/java/baritone/api/process/IBuilderProcess.java @@ -51,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().gameDir, "schematics"), schematicFile); return build(schematicFile, file, origin); diff --git a/src/api/java/baritone/api/schematic/MaskSchematic.java b/src/api/java/baritone/api/schematic/MaskSchematic.java index 95629b7c9..735ab98f8 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.block.BlockState; import java.util.List; @@ -41,4 +42,14 @@ public abstract class MaskSchematic extends AbstractSchematic { 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/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..86ad27223 --- /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.block.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..e64bf8816 --- /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.block.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..39462e107 --- /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.block.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..f95f406a9 --- /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.block.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..deb40badd --- /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.util.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/BlockOptionalMeta.java b/src/api/java/baritone/api/utils/BlockOptionalMeta.java index 73ebb77c4..10046c89b 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.block.Block; @@ -25,6 +26,7 @@ import net.minecraft.block.BlockState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.resources.*; +import net.minecraft.state.IProperty; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Unit; import net.minecraft.util.math.BlockPos; @@ -32,53 +34,91 @@ import net.minecraft.util.registry.Registry; import net.minecraft.world.storage.loot.*; import javax.annotation.Nonnull; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; import java.util.concurrent.CompletableFuture; -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 final Set stateHashes; + private final Set stackHashes; private static LootTableManager manager; 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(); - - ResourceLocation id = new ResourceLocation(matchResult.group(1)); + ResourceLocation id = new ResourceLocation(matcher.group("id")); if (!Registry.BLOCK.containsKey(id)) { throw new IllegalArgumentException("Invalid block ID"); } - block = Registry.BLOCK.getValue(id).orElse(null); - 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.getStateContainer().getValidStates()); + private static , P extends IProperty> 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]; + IProperty key = block.getStateContainer().getProperty(rawKey); + Comparable value = castToIProperty(key).parseValue(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.getStateContainer().getValidStates().stream() + .filter(blockstate -> properties.entrySet().stream().allMatch(entry -> + blockstate.get(entry.getKey()) == entry.getValue() + )) + .collect(Collectors.toSet()); } private static ImmutableSet getStateHashes(Set blockstates) { @@ -126,7 +166,7 @@ public final class BlockOptionalMeta { @Override public String toString() { - return String.format("BlockOptionalMeta{block=%s}", block); + return String.format("BlockOptionalMeta{block=%s,properties=%s}", block, propertiesDescription); } public BlockState getAnyBlockState() { @@ -137,6 +177,14 @@ public final class BlockOptionalMeta { return null; } + public Set getAllBlockStates() { + return blockstates; + } + + public Set stackHashes() { + return stackHashes; + } + public static LootTableManager getManager() { if (manager == null) { ResourcePackList rpl = new ResourcePackList<>(ResourcePackInfo::new); diff --git a/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java index b68432c2b..120b1bc21 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.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; 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.getDamage(); + return stackHashes.contains(hash); } public List blocks() { 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 b10032df9..da56424ab 100755 --- a/src/api/java/baritone/api/utils/Helper.java +++ b/src/api/java/baritone/api/utils/Helper.java @@ -42,8 +42,10 @@ public interface 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(); static ITextComponent getPrefix() { @@ -70,7 +72,7 @@ public interface Helper { * @param message The message to display in the popup */ default void logToast(ITextComponent title, ITextComponent message) { - mc.execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message)); + Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message)); } /** @@ -131,7 +133,7 @@ public interface Helper { * @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)); } /** @@ -164,7 +166,7 @@ public interface Helper { if (logAsToast) { logToast(getPrefix(), component); } else { - mc.execute(() -> BaritoneAPI.getSettings().logger.value.accept(component)); + Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().logger.value.accept(component)); } } diff --git a/src/api/java/baritone/api/utils/IPlayerContext.java b/src/api/java/baritone/api/utils/IPlayerContext.java index b213d27df..637ad94fa 100644 --- a/src/api/java/baritone/api/utils/IPlayerContext.java +++ b/src/api/java/baritone/api/utils/IPlayerContext.java @@ -19,6 +19,7 @@ package baritone.api.utils; import baritone.api.cache.IWorldData; import net.minecraft.block.SlabBlock; +import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; @@ -38,6 +39,8 @@ import java.util.stream.StreamSupport; */ public interface IPlayerContext { + Minecraft minecraft(); + ClientPlayerEntity player(); IPlayerController playerController(); @@ -86,6 +89,8 @@ public interface IPlayerContext { return new Vec3d(player().posX, player().posY + player().getEyeHeight(), player().posZ); } + BetterBlockPos viewerPos(); + default Rotation playerRotations() { return new Rotation(player().rotationYaw, player().rotationPitch); } 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 class Rotation { ); } + 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 38e72b0b3..f506fd9bb 100644 --- a/src/api/java/baritone/api/utils/RotationUtils.java +++ b/src/api/java/baritone/api/utils/RotationUtils.java @@ -137,14 +137,14 @@ public final class RotationUtils { * @param ctx Context for the viewing entity * @param pos The target block position * @return The optional rotation - * @see #reachable(ClientPlayerEntity, 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); } /** @@ -154,18 +154,17 @@ public final class RotationUtils { * 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(ClientPlayerEntity 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(ClientPlayerEntity 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 @@ -176,10 +175,10 @@ public final class RotationUtils { * * 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.rotationYaw, entity.rotationPitch + 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 - RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, hypothetical, blockReachDistance, true); + RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), hypothetical, blockReachDistance, true); if (result != null && result.getType() == RayTraceResult.Type.BLOCK && ((BlockRayTraceResult) result).getPos().equals(pos)) { return Optional.of(hypothetical); // yes, if we sneaked we would still be looking at the block } @@ -187,14 +186,14 @@ public final class RotationUtils { 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.world.getBlockState(pos); - VoxelShape shape = state.getShape(entity.world, pos); + BlockState state = ctx.world().getBlockState(pos); + VoxelShape shape = state.getShape(ctx.world(), pos); if (shape.isEmpty()) { shape = VoxelShapes.fullCube(); } @@ -202,7 +201,7 @@ public final class RotationUtils { double xDiff = shape.getStart(Direction.Axis.X) * sideOffset.x + shape.getEnd(Direction.Axis.X) * (1 - sideOffset.x); double yDiff = shape.getStart(Direction.Axis.Y) * sideOffset.y + shape.getEnd(Direction.Axis.Y) * (1 - sideOffset.y); double zDiff = shape.getStart(Direction.Axis.Z) * sideOffset.z + shape.getEnd(Direction.Axis.Z) * (1 - sideOffset.z); - possibleRotation = reachableOffset(entity, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak); + possibleRotation = reachableOffset(ctx, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak); if (possibleRotation.isPresent()) { return possibleRotation; } @@ -215,12 +214,55 @@ public final class RotationUtils { * 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(IPlayerContext ctx, BlockPos pos, Vec3d offsetPos, double blockReachDistance, boolean wouldSneak) { + Vec3d 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); + RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), actualRotation, blockReachDistance, wouldSneak); + //System.out.println(result); + if (result != null && result.getType() == RayTraceResult.Type.BLOCK) { + if (((BlockRayTraceResult) result).getPos().equals(pos)) { + return Optional.of(rotation); + } + if (ctx.world().getBlockState(pos).getBlock() instanceof FireBlock && ((BlockRayTraceResult) result).getPos().equals(pos.down())) { + return Optional.of(rotation); + } + } + return Optional.empty(); + } + + /** + * 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 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(ClientPlayerEntity entity, BlockPos pos, double blockReachDistance) { + return reachable(entity, pos, blockReachDistance, false); + } + + @Deprecated + public static Optional reachable(ClientPlayerEntity 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, Vec3d offsetPos, double blockReachDistance, boolean wouldSneak) { Vec3d eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(entity) : entity.getEyePosition(1.0F); Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, new Rotation(entity.rotationYaw, entity.rotationPitch)); @@ -237,15 +279,7 @@ public final class RotationUtils { return Optional.empty(); } - /** - * 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 pos The target block position - * @param blockReachDistance The block reach distance of the entity - * @return The optional rotation - */ + @Deprecated public static Optional reachableCenter(Entity entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) { return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(entity.world, pos), blockReachDistance, wouldSneak); } diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index 9df8a5e6e..3546ae6b7 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -47,12 +47,10 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; - public class SettingsUtil { - private static final Path SETTINGS_PATH = Minecraft.getInstance().gameDir.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 @@ public class SettingsUtil { } } - 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 class SettingsUtil { 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().gameDir.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 class SettingsUtil { 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 class SettingsUtil { } public static String settingToString(Settings.Setting setting) throws IllegalStateException { - if (javaOnlySetting(setting)) { + if (setting.isJavaOnly()) { return setting.getName(); } @@ -177,18 +179,14 @@ public class SettingsUtil { } /** - * 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 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 { diff --git a/src/api/java/baritone/api/utils/gui/BaritoneToast.java b/src/api/java/baritone/api/utils/gui/BaritoneToast.java index 3b300444c..56031bc5e 100644 --- a/src/api/java/baritone/api/utils/gui/BaritoneToast.java +++ b/src/api/java/baritone/api/utils/gui/BaritoneToast.java @@ -18,6 +18,7 @@ package baritone.api.utils.gui; import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.toasts.IToast; import net.minecraft.client.gui.toasts.ToastGui; import net.minecraft.util.ResourceLocation; @@ -73,6 +74,6 @@ public class BaritoneToast implements IToast { } public static void addOrUpdate(ITextComponent title, ITextComponent subtitle) { - addOrUpdate(net.minecraft.client.Minecraft.getInstance().getToastGui(), title, subtitle, baritone.api.BaritoneAPI.getSettings().toastTimer.value); + addOrUpdate(Minecraft.getInstance().getToastGui(), title, subtitle, baritone.api.BaritoneAPI.getSettings().toastTimer.value); } } diff --git a/src/launch/java/baritone/launch/mixins/MixinBitArray.java b/src/launch/java/baritone/launch/mixins/MixinBitArray.java index bece3e3bf..166dc51c9 100644 --- a/src/launch/java/baritone/launch/mixins/MixinBitArray.java +++ b/src/launch/java/baritone/launch/mixins/MixinBitArray.java @@ -64,4 +64,9 @@ public abstract class MixinBitArray implements IBitArray { return out; } + + @Override + public long getMaxEntryValue() { + return maxEntryValue; + } } diff --git a/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java b/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java index d6e223d99..8f96e3ad4 100644 --- a/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java +++ b/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java @@ -19,7 +19,6 @@ package baritone.launch.mixins; import baritone.utils.accessor.IBitArray; import baritone.utils.accessor.IBlockStateContainer; -import net.minecraft.block.BlockState; import net.minecraft.util.BitArray; import net.minecraft.world.chunk.BlockStateContainer; import net.minecraft.world.chunk.IBlockStatePalette; @@ -27,16 +26,26 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(BlockStateContainer.class) -public abstract class MixinBlockStateContainer implements IBlockStateContainer { +public abstract class MixinBlockStateContainer implements IBlockStateContainer { @Shadow protected BitArray storage; @Shadow - protected IBlockStatePalette palette; + protected IBlockStatePalette palette; @Override - public BlockState getAtPalette(int index) { + public IBlockStatePalette getPalette() { + return palette; + } + + @Override + public BitArray getStorage() { + return storage; + } + + @Override + public T getAtPalette(int index) { return palette.get(index); } diff --git a/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java b/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java index c10a4831d..459c26203 100644 --- a/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java +++ b/src/launch/java/baritone/launch/mixins/MixinClientPlayerEntity.java @@ -61,9 +61,8 @@ public class MixinClientPlayerEntity { method = "tick", at = @At( value = "INVOKE", - target = "net/minecraft/client/entity/player/ClientPlayerEntity.isPassenger()Z", - shift = At.Shift.BY, - by = -3 + target = "net/minecraft/client/entity/player/AbstractClientPlayerEntity.tick()V", + shift = At.Shift.AFTER ) ) private void onPreUpdate(CallbackInfo ci) { @@ -73,22 +72,6 @@ public class MixinClientPlayerEntity { } } - @Inject( - method = "tick", - at = @At( - value = "INVOKE", - target = "net/minecraft/client/entity/player/ClientPlayerEntity.onUpdateWalkingPlayer()V", - shift = At.Shift.BY, - by = 2 - ) - ) - private void onPostUpdate(CallbackInfo ci) { - IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((ClientPlayerEntity) (Object) this); - if (baritone != null) { - baritone.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST)); - } - } - @Redirect( method = "livingTick", at = @At( diff --git a/src/launch/java/baritone/launch/mixins/MixinEntity.java b/src/launch/java/baritone/launch/mixins/MixinEntity.java index 9cd2a3c96..dec1dc292 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.client.entity.player.ClientPlayerEntity; import net.minecraft.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 rotationYaw; - float yawRestore; + @Shadow + private float rotationPitch; + + @Unique + private RotationMoveEvent motionUpdateRotationEvent; @Inject( method = "moveRelative", at = @At("HEAD") ) private void moveRelativeHead(CallbackInfo info) { - this.yawRestore = this.rotationYaw; // noinspection ConstantConditions if (!ClientPlayerEntity.class.isInstance(this) || BaritoneAPI.getProvider().getBaritoneForPlayer((ClientPlayerEntity) (Object) this) == null) { return; } - RotationMoveEvent motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.rotationYaw); + this.motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.rotationYaw, this.rotationPitch); BaritoneAPI.getProvider().getBaritoneForPlayer((ClientPlayerEntity) (Object) this).getGameEventHandler().onPlayerRotationMove(motionUpdateRotationEvent); - this.rotationYaw = motionUpdateRotationEvent.getYaw(); + this.rotationYaw = this.motionUpdateRotationEvent.getYaw(); + this.rotationPitch = this.motionUpdateRotationEvent.getPitch(); } @Inject( @@ -55,6 +60,10 @@ public class MixinEntity { at = @At("RETURN") ) private void moveRelativeReturn(CallbackInfo info) { - this.rotationYaw = this.yawRestore; + if (this.motionUpdateRotationEvent != null) { + this.rotationYaw = this.motionUpdateRotationEvent.getOriginal().getYaw(); + this.rotationPitch = this.motionUpdateRotationEvent.getOriginal().getPitch(); + this.motionUpdateRotationEvent = null; + } } } diff --git a/src/launch/java/baritone/launch/mixins/MixinLivingEntity.java b/src/launch/java/baritone/launch/mixins/MixinLivingEntity.java index a3536ff55..23ae35bea 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.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; import net.minecraft.world.World; +import net.minecraft.util.math.Vec3d; 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; + import static org.spongepowered.asm.lib.Opcodes.GETFIELD; /** @@ -43,8 +47,12 @@ public abstract class MixinLivingEntity extends Entity { /** * Event called to override the movement direction when jumping */ + @Unique private RotationMoveEvent jumpRotationEvent; + @Unique + private RotationMoveEvent elytraRotationEvent; + public MixinLivingEntity(EntityType entityTypeIn, World worldIn) { super(entityTypeIn, worldIn); } @@ -54,14 +62,10 @@ public abstract class MixinLivingEntity extends Entity { at = @At("HEAD") ) private void preMoveRelative(CallbackInfo ci) { - // noinspection ConstantConditions - if (ClientPlayerEntity.class.isInstance(this)) { - IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((ClientPlayerEntity) (Object) this); - if (baritone != null) { - this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.rotationYaw); - baritone.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent); - } - } + this.getBaritone().ifPresent(baritone -> { + this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.rotationYaw, this.rotationPitch); + baritone.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent); + }); } @Redirect( @@ -79,5 +83,45 @@ public abstract class MixinLivingEntity extends Entity { return self.rotationYaw; } + @Inject( + method = "travel", + at = @At( + value = "INVOKE", + target = "net/minecraft/entity/LivingEntity.getLookVec()Lnet/minecraft/util/math/Vec3d;" + ) + ) + private void onPreElytraMove(Vec3d direction, CallbackInfo ci) { + this.getBaritone().ifPresent(baritone -> { + this.elytraRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.rotationYaw, this.rotationPitch); + baritone.getGameEventHandler().onPlayerRotationMove(this.elytraRotationEvent); + this.rotationYaw = this.elytraRotationEvent.getYaw(); + this.rotationPitch = this.elytraRotationEvent.getPitch(); + }); + } + @Inject( + method = "travel", + at = @At( + value = "INVOKE", + target = "net/minecraft/entity/Entity.move(Lnet/minecraft/entity/MoverType;Lnet/minecraft/util/math/Vec3d;)V", + shift = At.Shift.AFTER + ) + ) + private void onPostElytraMove(float strafe, float vertical, float forward, CallbackInfo ci) { + if (this.elytraRotationEvent != null) { + this.rotationYaw = this.elytraRotationEvent.getOriginal().getYaw(); + this.rotationPitch = this.elytraRotationEvent.getOriginal().getPitch(); + this.elytraRotationEvent = null; + } + } + + @Unique + private Optional getBaritone() { + // noinspection ConstantConditions + if (ClientPlayerEntity.class.isInstance(this)) { + return Optional.ofNullable(BaritoneAPI.getProvider().getBaritoneForPlayer((ClientPlayerEntity) (Object) this)); + } else { + return Optional.empty(); + } + } } diff --git a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java index 02f082009..c648f28a6 100644 --- a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java +++ b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java @@ -20,6 +20,7 @@ package baritone.launch.mixins; import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.event.events.BlockInteractEvent; +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; @@ -84,7 +85,21 @@ public class MixinMinecraft { baritone.getGameEventHandler().onTick(tickProvider.apply(EventState.PRE, type)); } + } + @Inject( + method = "runTick", + at = @At( + value = "INVOKE", + target = "net/minecraft/client/world/ClientWorld.tickEntities()V", + shift = At.Shift.AFTER + ) + ) + private void postUpdateEntities(CallbackInfo ci) { + IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(this.player); + if (baritone != null) { + baritone.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST)); + } } @Inject( diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index fea481cda..396836797 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -20,8 +20,9 @@ package baritone; 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.utils.IPlayerContext; import baritone.behavior.*; import baritone.cache.WorldProvider; @@ -33,16 +34,17 @@ import baritone.utils.BlockStateInterface; 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.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,87 +52,101 @@ import java.util.concurrent.TimeUnit; */ 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().gameDir, "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 PathingBehavior pathingBehavior; - private LookBehavior lookBehavior; - private InventoryBehavior inventoryBehavior; - private WaypointBehavior waypointBehavior; - private InputOverrideHandler inputOverrideHandler; + private final GameEventHandler gameEventHandler; - 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 PathingBehavior pathingBehavior; + private final LookBehavior lookBehavior; + private final InventoryBehavior inventoryBehavior; + private final InputOverrideHandler inputOverrideHandler; - private PathingControlManager pathingControlManager; - private SelectionManager selectionManager; - private CommandManager commandManager; + 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 IPlayerContext playerContext; - private WorldProvider worldProvider; + private final PathingControlManager pathingControlManager; + private final SelectionManager selectionManager; + private final CommandManager commandManager; + + 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.gameDir.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.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; @@ -170,6 +186,7 @@ public class Baritone implements IBaritone { return this.lookBehavior; } + @Override public ExploreProcess getExploreProcess() { return this.exploreProcess; } @@ -179,10 +196,15 @@ public class Baritone implements IBaritone { return this.mineProcess; } + @Override public FarmProcess getFarmProcess() { return this.farmProcess; } + public InventoryPauserProcess getInventoryPauserProcess() { + return this.inventoryPauserProcess; + } + @Override public PathingBehavior getPathingBehavior() { return this.pathingBehavior; @@ -213,19 +235,19 @@ public class Baritone implements IBaritone { new Thread(() -> { try { Thread.sleep(100); - Helper.mc.execute(() -> Helper.mc.displayGuiScreen(new GuiClick())); + mc.execute(() -> mc.displayGuiScreen(new GuiClick())); } catch (Exception ignored) {} }).start(); } + public Path getDirectory() { + return this.directory; + } + public static Settings settings() { return BaritoneAPI.getSettings(); } - public static File getDir() { - return dir; - } - public static Executor getExecutor() { return threadPool; } 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.IBaritoneProvider; 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 @@ import java.util.List; */ 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/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 e11a256e6..3257c100e 100644 --- a/src/main/java/baritone/behavior/InventoryBehavior.java +++ b/src/main/java/baritone/behavior/InventoryBehavior.java @@ -19,6 +19,7 @@ package baritone.behavior; import baritone.Baritone; import baritone.api.event.events.TickEvent; +import baritone.api.utils.Helper; import baritone.utils.ToolSet; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -37,7 +38,10 @@ import java.util.OptionalInt; 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); @@ -55,20 +59,28 @@ public final class InventoryBehavior extends Behavior { // 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) { + public boolean attemptToPutOnHotbar(int inMainInvy, Predicate disallowedHotbar) { 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) { @@ -92,8 +104,20 @@ public final class InventoryBehavior extends Behavior { return OptionalInt.of(candidates.get(new Random().nextInt(candidates.size()))); } - private void swapWithHotBar(int inInventory, int inHotbar) { + 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; + } ctx.playerController().windowClick(ctx.player().container.windowId, inInventory < 9 ? inInventory + 36 : inInventory, inHotbar, ClickType.SWAP, ctx.player()); + ticksSinceLastInventoryMove = 0; + lastTickRequestedMove = null; + return true; } private int firstValidThrowaway() { // TODO offhand idk @@ -195,8 +219,8 @@ public final class InventoryBehavior extends Behavior { if (allowInventory) { for (int i = 9; i < 36; i++) { if (desired.test(inv.get(i))) { - swapWithHotBar(i, 7); if (select) { + requestSwapWithHotBar(i, 7); p.inventory.currentItem = 7; } return true; diff --git a/src/main/java/baritone/behavior/LookBehavior.java b/src/main/java/baritone/behavior/LookBehavior.java index 801a5e43e..5d0653a3e 100644 --- a/src/main/java/baritone/behavior/LookBehavior.java +++ b/src/main/java/baritone/behavior/LookBehavior.java @@ -20,44 +20,57 @@ package baritone.behavior; 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.play.client.CPlayerPacket; + +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; public LookBehavior(Baritone baritone) { super(baritone); + this.processor = new AimProcessor(baritone.getPlayerContext()); } @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, 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 @@ -65,35 +78,30 @@ public final class LookBehavior extends Behavior implements ILookBehavior { 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().rotationYaw = this.target.getYaw(); - float oldPitch = ctx.player().rotationPitch; - float desiredPitch = this.target.getPitch(); - ctx.player().rotationPitch = desiredPitch; - ctx.player().rotationYaw += (Math.random() - 0.5) * Baritone.settings().randomLooking.value; - ctx.player().rotationPitch += (Math.random() - 0.5) * Baritone.settings().randomLooking.value; - if (desiredPitch == oldPitch && !Baritone.settings().freeLook.value) { - nudgeToLevel(); - } - this.target = null; + if (this.target.mode == Target.Mode.NONE) { + // Just return for PRE, we still want to set target to null on POST + return; } - if (silent) { - this.lastYaw = ctx.player().rotationYaw; - ctx.player().rotationYaw = this.target.getYaw(); + if (this.target.mode == Target.Mode.SERVER) { + this.prevRotation = new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch); } + + final Rotation actual = this.processor.peekRotation(this.target.rotation); + ctx.player().rotationYaw = actual.getYaw(); + ctx.player().rotationPitch = actual.getPitch(); break; } case POST: { - if (silent) { - ctx.player().rotationYaw = this.lastYaw; - this.target = null; + // Reset the player's rotations back to their original values + if (this.prevRotation != null) { + ctx.player().rotationYaw = this.prevRotation.getYaw(); + ctx.player().rotationPitch = this.prevRotation.getPitch(); + 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 +109,224 @@ public final class LookBehavior extends Behavior implements ILookBehavior { } } + @Override + public void onSendPacket(PacketEvent event) { + if (!(event.getPacket() instanceof CPlayerPacket)) { + return; + } + + final CPlayerPacket packet = (CPlayerPacket) event.getPacket(); + if (packet instanceof CPlayerPacket.RotationPacket || packet instanceof CPlayerPacket.PositionRotationPacket) { + this.serverRotation = new Rotation(packet.getYaw(0.0f), packet.getPitch(0.0f)); + } + } + + @Override + public void onWorldEvent(WorldEvent event) { + this.serverRotation = null; + this.target = null; + } + public void pig() { if (this.target != null) { - ctx.player().rotationYaw = this.target.getYaw(); + final Rotation actual = this.processor.peekRotation(this.target.rotation); + ctx.player().rotationYaw = 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; + } + + // The game uses rotation = (float) ((double) rotation + delta) so we'll do that as well + private float calculateMouseMove(float current, float target) { + final double delta = target - current; + final double deltaPx = angleToMouse(delta); // yes, even the mouse movements use double + return (float) ((double) current + mouseToAngle(deltaPx)); + } + + private double angleToMouse(double angleDelta) { + final double minAngleChange = mouseToAngle(1); + return Math.round(angleDelta / minAngleChange); + } + + private double mouseToAngle(double mouseDelta) { + // casting float literals to double gets us the precise values used by mc + final double f = ctx.minecraft().gameSettings.mouseSensitivity * (double) 0.6f + (double) 0.2f; + return mouseDelta * f * f * f * 8.0d * 0.15d; + } + } + + private static class Target { + + public final Rotation rotation; + public final Mode mode; + + public Target(Rotation rotation, boolean blockInteract) { + this.rotation = rotation; + this.mode = Mode.resolve(blockInteract); + } + + 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(boolean blockInteract) { + final Settings settings = Baritone.settings(); + final boolean antiCheat = settings.antiCheatCompatibility.value; + final boolean blockFreeLook = settings.blockFreeLook.value; + final boolean freeLook = settings.freeLook.value; + + if (!freeLook) return CLIENT; + if (!blockFreeLook && blockInteract) return CLIENT; + + // 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 (antiCheat || blockInteract) return SERVER; + + // Pathing regularly without antiCheatCompatibility, don't set the player rotation + return NONE; } } } - - /** - * 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().rotationPitch < -20) { - ctx.player().rotationPitch++; - } else if (ctx.player().rotationPitch > 10) { - ctx.player().rotationPitch--; - } - } } diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 33ef14ef2..31a884622 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -239,11 +239,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, if (current != null) { switch (event.getState()) { case PRE: - lastAutoJump = mc.gameSettings.autoJump; - mc.gameSettings.autoJump = false; + lastAutoJump = ctx.minecraft().gameSettings.autoJump; + ctx.minecraft().gameSettings.autoJump = false; break; case POST: - mc.gameSettings.autoJump = lastAutoJump; + ctx.minecraft().gameSettings.autoJump = lastAutoJump; break; default: break; 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/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java index 6b3959fe3..32112f20f 100644 --- a/src/main/java/baritone/cache/CachedWorld.java +++ b/src/main/java/baritone/cache/CachedWorld.java @@ -307,6 +307,9 @@ public final class CachedWorld implements ICachedWorld, Helper { try { ChunkPos pos = toPackQueue.take(); Chunk 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/FasterWorldScanner.java b/src/main/java/baritone/cache/FasterWorldScanner.java new file mode 100644 index 000000000..ff107df6c --- /dev/null +++ b/src/main/java/baritone/cache/FasterWorldScanner.java @@ -0,0 +1,271 @@ +/* + * 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.BlockOptionalMetaLookup; +import baritone.api.utils.IPlayerContext; +import baritone.utils.accessor.IBitArray; +import baritone.utils.accessor.IBlockStateContainer; +import io.netty.buffer.Unpooled; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.BitArray; +import net.minecraft.util.ObjectIntIdentityMap; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.chunk.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public enum FasterWorldScanner implements IWorldScanner { + INSTANCE; + @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) { + AbstractChunkProvider chunkProvider = ctx.world().getChunkProvider(); + 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++) { + Chunk 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) { + AbstractChunkProvider chunkProvider = ctx.world().getChunkProvider(); + // if chunk is not loaded, return empty stream + if (!chunkProvider.chunkExists(pos.x, pos.z)) { + return Stream.empty(); + } + + long chunkX = (long) pos.x << 4; + long chunkZ = (long) pos.z << 4; + + int playerSectionY = ctx.playerFeet().y >> 4; + + return collectChunkSections(lookup, chunkProvider.getChunk(pos.x, pos.z, false), chunkX, chunkZ, playerSectionY).stream(); + } + + + + private List collectChunkSections(BlockOptionalMetaLookup lookup, Chunk chunk, long chunkX, long chunkZ, int playerSection) { + // iterate over sections relative to player + List blocks = new ArrayList<>(); + ChunkSection[] 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, chunkZ); + } + if (i >= 0) { + visitSection(lookup, sections[i], blocks, chunkX, chunkZ); + } + } + return blocks; + } + + private void visitSection(BlockOptionalMetaLookup lookup, ChunkSection section, List blocks, long chunkX, long chunkZ) { + if (section == null || section.isEmpty()) { + return; + } + + BlockStateContainer sectionContainer = section.getData(); + //this won't work if the PaletteStorage is of the type EmptyPaletteStorage + if (((IBlockStateContainer) sectionContainer).getStorage() == null) { + return; + } + + boolean[] isInFilter = getIncludedFilterIndices(lookup, ((IBlockStateContainer) sectionContainer).getPalette()); + if (isInFilter.length == 0) { + return; + } + + BitArray array = ((IBlockStateContainer) section.getData()).getStorage(); + long[] longArray = array.getBackingLongArray(); + int arraySize = array.size(); + int bitsPerEntry = array.bitsPerEntry(); + long maxEntryValue = ((IBitArray) array).getMaxEntryValue(); + + + int yOffset = section.getYLocation(); + + for (int idx = 0, kl = bitsPerEntry - 1; idx < arraySize; idx++, kl += bitsPerEntry) { + final int i = idx * bitsPerEntry; + final int j = i >> 6; + final int l = i & 63; + final int k = kl >> 6; + final long jl = longArray[j] >>> l; + + if (j == k) { + if (isInFilter[(int) (jl & maxEntryValue)]) { + //noinspection DuplicateExpressions + blocks.add(new BlockPos( + chunkX + ((idx & 255) & 15), + yOffset + (idx >> 8), + chunkZ + ((idx & 255) >> 4) + )); + } + } else { + if (isInFilter[(int) ((jl | longArray[k] << (64 - l)) & maxEntryValue)]) { + //noinspection DuplicateExpressions + blocks.add(new BlockPos( + chunkX + ((idx & 255) & 15), + yOffset + (idx >> 8), + chunkZ + ((idx & 255) >> 4) + )); + } + } + } + } + + private boolean[] getIncludedFilterIndices(BlockOptionalMetaLookup lookup, IBlockStatePalette palette) { + boolean commonBlockFound = false; + ObjectIntIdentityMap paletteMap = getPalette(palette); + int size = paletteMap.size(); + + boolean[] isInFilter = new boolean[size]; + + for (int i = 0; i < size; i++) { + BlockState state = paletteMap.getByValue(i); + if (lookup.has(state)) { + isInFilter[i] = true; + commonBlockFound = true; + } else { + isInFilter[i] = false; + } + } + + if (!commonBlockFound) { + return new boolean[0]; + } + return isInFilter; + } + + /** + * cheats to get the actual map of id -> blockstate from the various palette implementations + */ + private static ObjectIntIdentityMap getPalette(IBlockStatePalette palette) { + if (palette instanceof BlockStatePaletteRegistry) { + return Block.BLOCK_STATE_IDS; + } else { + PacketBuffer buf = new PacketBuffer(Unpooled.buffer()); + palette.write(buf); + int size = buf.readVarInt(); + ObjectIntIdentityMap states = new ObjectIntIdentityMap<>(); + for (int i = 0; i < size; i++) { + BlockState state = Block.BLOCK_STATE_IDS.getByValue(buf.readVarInt()); + assert state != null; + states.put(state, i); + } + return states; + } + } +} diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index 464f348ef..59f4211b6 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -19,100 +19,84 @@ package baritone.cache; import baritone.Baritone; import baritone.api.cache.IWorldProvider; -import baritone.api.utils.Helper; -import net.minecraft.server.integrated.IntegratedServer; +import baritone.api.utils.IPlayerContext; +import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.util.Tuple; import net.minecraft.world.World; import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.server.ServerWorld; import org.apache.commons.lang3.SystemUtils; -import java.io.File; -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; - private World mcWorld; // this let's us detect a broken load/unload hook + + /** + * This lets us detect a broken load/unload hook. + * @see #detectAndHandleBrokenLoading() + */ + private World mcWorld; + + public WorldProvider(Baritone baritone) { + this.baritone = baritone; + this.ctx = baritone.getPlayerContext(); + } @Override public final WorldData getCurrentWorld() { - detectAndHandleBrokenLoading(); + this.detectAndHandleBrokenLoading(); return this.currentWorld; } /** * Called when a new world is initialized to discover the * - * @param dimension The ID of the world's dimension + * @param world The new world */ - public final void initWorld(DimensionType dimension) { - File directory; - File readme; + public final void initWorld(World world) { + this.getSaveDirectories(world).ifPresent(dirs -> { + final Path worldDir = dirs.getA(); + final Path readmeDir = dirs.getB(); - IntegratedServer integratedServer = mc.getIntegratedServer(); - - // If there is an integrated server running (Aka Singleplayer) then do magic to find the world save file - if (mc.isSingleplayer()) { - ServerWorld localServerWorld = integratedServer.getWorld(dimension); - directory = dimension.getDirectory(localServerWorld.getSaveHandler().getWorldDirectory()); - - // Gets the "depth" of this directory relative the the game's run directory, 2 is the location of the world - if (directory.toPath().relativize(mc.gameDir.toPath()).getNameCount() != 2) { - // subdirectory of the main save directory for this world - directory = directory.getParentFile(); - } - - directory = new File(directory, "baritone"); - readme = directory; - } else { // Otherwise, the server must be remote... - String folderName; - if (mc.getCurrentServerData() != null) { - folderName = mc.isConnectedToRealms() ? "realms" : mc.getCurrentServerData().serverIP; - } else { - //replaymod causes null currentServerData and false singleplayer. - System.out.println("World seems to be a replay. Not loading Baritone cache."); - currentWorld = null; - mcWorld = mc.world; - return; - } - if (SystemUtils.IS_OS_WINDOWS) { - folderName = folderName.replace(":", "_"); - } - directory = new File(Baritone.getDir(), folderName); - readme = Baritone.getDir(); - } - - // lol wtf is this baritone folder in my minecraft save? - try (FileOutputStream out = new FileOutputStream(new File(readme, "readme.txt"))) { - // good thing we have a readme - out.write("https://github.com/cabaletta/baritone\n".getBytes()); - } catch (IOException ignored) {} - - // We will actually store the world data in a subfolder: "DIM" - Path dir = new File(directory, "DIM" + dimension.getId()).toPath(); - if (!Files.exists(dir)) { try { - Files.createDirectories(dir); + // 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) {} - } - System.out.println("Baritone world data dir: " + dir); - synchronized (worldCache) { - this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension.getId())); - } - this.mcWorld = mc.world; + // 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) { + final int dimension = world.getDimension().getType().getId(); + this.currentWorld = worldCache.computeIfAbsent(worldDataDir, d -> new WorldData(d, dimension)); + } + this.mcWorld = ctx.world(); + }); } public final void closeWorld() { @@ -125,26 +109,73 @@ public class WorldProvider implements IWorldProvider, Helper { world.onClose(); } - public final void ifWorldLoaded(Consumer currentWorldConsumer) { - detectAndHandleBrokenLoading(); - if (this.currentWorld != null) { - currentWorldConsumer.accept(this.currentWorld); - } + private Path getWorldDataDirectory(Path parent, World world) { + return parent.resolve("DIM" + world.getDimension().getType().getId()); } - private final void detectAndHandleBrokenLoading() { - if (this.mcWorld != mc.world) { + /** + * @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> getSaveDirectories(World world) { + Path worldDir; + Path readmeDir; + + // If there is an integrated server running (Aka Singleplayer) then do magic to find the world save file + if (ctx.minecraft().isSingleplayer()) { + final DimensionType dimension = world.getDimension().getType(); + final ServerWorld localServerWorld = ctx.minecraft().getIntegratedServer().getWorld(dimension); + worldDir = dimension.getDirectory(localServerWorld.getSaveHandler().getWorldDirectory()).toPath(); + + // Gets the "depth" of this directory relative to the game's run directory, 2 is the location of the world + if (worldDir.relativize(ctx.minecraft().gameDir.toPath()).getNameCount() != 2) { + // subdirectory of the main save directory for this world + worldDir = worldDir.getParent(); + } + + worldDir = worldDir.resolve("baritone"); + readmeDir = worldDir; + } else { // Otherwise, the server must be remote... + String folderName; + final ServerData serverData = ctx.minecraft().getCurrentServerData(); + if (serverData != null) { + folderName = ctx.minecraft().isConnectedToRealms() ? "realms" : serverData.serverIP; + } else { + //replaymod causes null currentServerData and false singleplayer. + System.out.println("World seems to be a replay. Not loading Baritone cache."); + currentWorld = null; + mcWorld = ctx.world(); + return Optional.empty(); + } + if (SystemUtils.IS_OS_WINDOWS) { + folderName = folderName.replace(":", "_"); + } + // TODO: This should probably be in "baritone/servers" + worldDir = baritone.getDirectory().resolve(folderName); + // Just write the readme to the baritone directory instead of each server save in it + readmeDir = baritone.getDirectory(); + } + + return Optional.of(new Tuple<>(worldDir, readmeDir)); + } + + /** + * Why does this exist instead of fixing the event? Some mods break the event. Lol. + */ + private void detectAndHandleBrokenLoading() { + if (this.mcWorld != ctx.world()) { if (this.currentWorld != null) { System.out.println("mc.world unloaded unnoticed! Unloading Baritone cache now."); closeWorld(); } - if (mc.world != null) { + if (ctx.world() != null) { System.out.println("mc.world loaded unnoticed! Loading Baritone cache now."); - initWorld(mc.world.getDimension().getType()); + initWorld(ctx.world()); } - } else if (currentWorld == null && mc.world != null && (mc.isSingleplayer() || mc.getCurrentServerData() != null)) { + } else if (this.currentWorld == null && ctx.world() != null && (ctx.minecraft().isSingleplayer() || ctx.minecraft().getCurrentServerData() != null)) { System.out.println("Retrying to load Baritone cache"); - initWorld(mc.world.getDimension().getType()); + initWorld(ctx.world()); } } } diff --git a/src/main/java/baritone/cache/WorldScanner.java b/src/main/java/baritone/cache/WorldScanner.java index 8d72134b2..748113c50 100644 --- a/src/main/java/baritone/cache/WorldScanner.java +++ b/src/main/java/baritone/cache/WorldScanner.java @@ -155,7 +155,7 @@ public enum WorldScanner implements IWorldScanner { continue; } int yReal = y0 << 4; - IBlockStateContainer bsc = (IBlockStateContainer) section.getData(); + IBlockStateContainer bsc = (IBlockStateContainer) section.getData(); // storageArray uses an optimized algorithm that's faster than getAt // creating this array and then using getAtPalette is faster than even getFast(int index) int[] storage = bsc.storageArray(); diff --git a/src/main/java/baritone/command/ExampleBaritoneControl.java b/src/main/java/baritone/command/ExampleBaritoneControl.java index 43982bfc2..e2172940b 100644 --- a/src/main/java/baritone/command/ExampleBaritoneControl.java +++ b/src/main/java/baritone/command/ExampleBaritoneControl.java @@ -17,8 +17,8 @@ package baritone.command; +import baritone.Baritone; import baritone.api.BaritoneAPI; -import baritone.api.IBaritone; import baritone.api.Settings; import baritone.api.command.argument.ICommandArgument; import baritone.api.command.exception.CommandNotEnoughArgumentsException; @@ -27,9 +27,9 @@ import baritone.api.command.helpers.TabCompleteHelper; import baritone.api.command.manager.ICommandManager; import baritone.api.event.events.ChatEvent; import baritone.api.event.events.TabCompleteEvent; -import baritone.api.event.listener.AbstractGameEventListener; import baritone.api.utils.Helper; import baritone.api.utils.SettingsUtil; +import baritone.behavior.Behavior; import baritone.command.argument.ArgConsumer; import baritone.command.argument.CommandArguments; import baritone.command.manager.CommandManager; @@ -49,14 +49,14 @@ import java.util.stream.Stream; import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX; -public class ExampleBaritoneControl implements Helper, AbstractGameEventListener { +public class ExampleBaritoneControl extends Behavior implements Helper { private static final Settings settings = BaritoneAPI.getSettings(); private final ICommandManager manager; - public ExampleBaritoneControl(IBaritone baritone) { + public ExampleBaritoneControl(Baritone baritone) { + super(baritone); this.manager = baritone.getCommandManager(); - baritone.getGameEventHandler().registerEventListener(this); } @Override @@ -100,7 +100,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener return false; } else if (msg.trim().equalsIgnoreCase("orderpizza")) { try { - ((IGuiScreen) mc.currentScreen).openLinkInvoker(new URI("https://www.dominos.com/en/pages/order/")); + ((IGuiScreen) ctx.minecraft().currentScreen).openLinkInvoker(new URI("https://www.dominos.com/en/pages/order/")); } catch (NullPointerException | URISyntaxException ignored) {} return false; } @@ -124,7 +124,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener } } else if (argc.hasExactlyOne()) { for (Settings.Setting setting : settings.allSettings) { - if (SettingsUtil.javaOnlySetting(setting)) { + if (setting.isJavaOnly()) { continue; } if (setting.getName().equalsIgnoreCase(pair.getA())) { @@ -177,7 +177,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener .stream(); } Settings.Setting setting = settings.byLowerName.get(argc.getString().toLowerCase(Locale.US)); - if (setting != null && !SettingsUtil.javaOnlySetting(setting)) { + if (setting != null && !setting.isJavaOnly()) { if (setting.getValueClass() == Boolean.class) { TabCompleteHelper helper = new TabCompleteHelper(); if ((Boolean) setting.value) { diff --git a/src/main/java/baritone/command/argument/ArgConsumer.java b/src/main/java/baritone/command/argument/ArgConsumer.java index 4a80681dd..42ac1e5a0 100644 --- a/src/main/java/baritone/command/argument/ArgConsumer.java +++ b/src/main/java/baritone/command/argument/ArgConsumer.java @@ -373,6 +373,8 @@ public class ArgConsumer implements IArgConsumer { public Stream tabCompleteDatatype(T datatype) { try { return datatype.tabComplete(this.context); + } catch (CommandException ignored) { + // NOP } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/baritone/command/defaults/BuildCommand.java b/src/main/java/baritone/command/defaults/BuildCommand.java index 75c1673d4..12f287955 100644 --- a/src/main/java/baritone/command/defaults/BuildCommand.java +++ b/src/main/java/baritone/command/defaults/BuildCommand.java @@ -35,10 +35,11 @@ import java.util.stream.Stream; public class BuildCommand extends Command { - private static final File schematicsDir = new File(mc.gameDir, "schematics"); + private final File schematicsDir; public BuildCommand(IBaritone baritone) { super(baritone, "build"); + this.schematicsDir = new File(baritone.getPlayerContext().minecraft().gameDir, "schematics"); } @Override diff --git a/src/main/java/baritone/command/defaults/ComeCommand.java b/src/main/java/baritone/command/defaults/ComeCommand.java index 5d3e3b829..b111ee1de 100644 --- a/src/main/java/baritone/command/defaults/ComeCommand.java +++ b/src/main/java/baritone/command/defaults/ComeCommand.java @@ -21,10 +21,7 @@ import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.exception.CommandException; -import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.pathing.goals.GoalBlock; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; import java.util.Arrays; import java.util.List; @@ -39,11 +36,7 @@ public class ComeCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { args.requireMax(0); - Entity entity = mc.getRenderViewEntity(); - if (entity == null) { - throw new CommandInvalidStateException("render view entity is null"); - } - baritone.getCustomGoalProcess().setGoalAndPath(new GoalBlock(new BlockPos(entity))); + baritone.getCustomGoalProcess().setGoalAndPath(new GoalBlock(ctx.viewerPos())); logDirect("Coming"); } diff --git a/src/main/java/baritone/command/defaults/ExploreFilterCommand.java b/src/main/java/baritone/command/defaults/ExploreFilterCommand.java index c2057551f..6f306a966 100644 --- a/src/main/java/baritone/command/defaults/ExploreFilterCommand.java +++ b/src/main/java/baritone/command/defaults/ExploreFilterCommand.java @@ -41,7 +41,7 @@ public class ExploreFilterCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { args.requireMax(2); - File file = args.getDatatypePost(RelativeFile.INSTANCE, mc.gameDir.getAbsoluteFile().getParentFile()); + File file = args.getDatatypePost(RelativeFile.INSTANCE, ctx.minecraft().gameDir.getAbsoluteFile().getParentFile()); boolean invert = false; if (args.hasAny()) { if (args.getString().equalsIgnoreCase("invert")) { @@ -65,7 +65,7 @@ public class ExploreFilterCommand extends Command { @Override public Stream tabComplete(String label, IArgConsumer args) throws CommandException { if (args.hasExactlyOne()) { - return RelativeFile.tabComplete(args, RelativeFile.gameDir()); + return RelativeFile.tabComplete(args, RelativeFile.gameDir(ctx.minecraft())); } return Stream.empty(); } diff --git a/src/main/java/baritone/command/defaults/GoalCommand.java b/src/main/java/baritone/command/defaults/GoalCommand.java index 40822e057..a174ecad9 100644 --- a/src/main/java/baritone/command/defaults/GoalCommand.java +++ b/src/main/java/baritone/command/defaults/GoalCommand.java @@ -51,7 +51,7 @@ public class GoalCommand extends Command { } } else { args.requireMax(3); - BetterBlockPos origin = baritone.getPlayerContext().playerFeet(); + BetterBlockPos origin = ctx.playerFeet(); Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin); goalProcess.setGoal(goal); logDirect(String.format("Goal: %s", goal.toString())); diff --git a/src/main/java/baritone/command/defaults/GotoCommand.java b/src/main/java/baritone/command/defaults/GotoCommand.java index 896e3f5f8..c64d7fa00 100644 --- a/src/main/java/baritone/command/defaults/GotoCommand.java +++ b/src/main/java/baritone/command/defaults/GotoCommand.java @@ -20,7 +20,6 @@ package baritone.command.defaults; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; -import baritone.api.command.datatypes.BlockById; import baritone.api.command.datatypes.ForBlockOptionalMeta; import baritone.api.command.datatypes.RelativeCoordinate; import baritone.api.command.datatypes.RelativeGoal; @@ -46,7 +45,7 @@ public class GotoCommand extends Command { // is no need to handle the case of empty arguments. if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) { args.requireMax(3); - BetterBlockPos origin = baritone.getPlayerContext().playerFeet(); + BetterBlockPos origin = ctx.playerFeet(); Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin); logDirect(String.format("Going to: %s", goal.toString())); baritone.getCustomGoalProcess().setGoalAndPath(goal); @@ -61,7 +60,8 @@ public class GotoCommand extends Command { public Stream tabComplete(String label, IArgConsumer args) throws CommandException { // since it's either a goal or a block, I don't think we can tab complete properly? // so just tab complete for the block variant - return args.tabCompleteDatatype(BlockById.INSTANCE); + args.requireMax(1); + return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE); } @Override diff --git a/src/main/java/baritone/command/defaults/MineCommand.java b/src/main/java/baritone/command/defaults/MineCommand.java index 63712fe3e..597d105ca 100644 --- a/src/main/java/baritone/command/defaults/MineCommand.java +++ b/src/main/java/baritone/command/defaults/MineCommand.java @@ -17,14 +17,13 @@ package baritone.command.defaults; +import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; -import baritone.api.command.datatypes.BlockById; import baritone.api.command.datatypes.ForBlockOptionalMeta; import baritone.api.command.exception.CommandException; import baritone.api.utils.BlockOptionalMeta; -import baritone.cache.WorldScanner; import java.util.ArrayList; import java.util.Arrays; @@ -45,14 +44,18 @@ public class MineCommand extends Command { while (args.hasAny()) { boms.add(args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE)); } - WorldScanner.INSTANCE.repack(ctx); + BaritoneAPI.getProvider().getWorldScanner().repack(ctx); logDirect(String.format("Mining %s", boms.toString())); baritone.getMineProcess().mine(quantity, boms.toArray(new BlockOptionalMeta[0])); } @Override - public Stream tabComplete(String label, IArgConsumer args) { - return args.tabCompleteDatatype(BlockById.INSTANCE); + public Stream tabComplete(String label, IArgConsumer args) throws CommandException { + args.getAsOrDefault(Integer.class, 0); + while (args.has(2)) { + args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE); + } + return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE); } @Override diff --git a/src/main/java/baritone/command/defaults/PathCommand.java b/src/main/java/baritone/command/defaults/PathCommand.java index 182a1e5bc..b2021adf6 100644 --- a/src/main/java/baritone/command/defaults/PathCommand.java +++ b/src/main/java/baritone/command/defaults/PathCommand.java @@ -17,12 +17,12 @@ package baritone.command.defaults; +import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.exception.CommandException; import baritone.api.process.ICustomGoalProcess; -import baritone.cache.WorldScanner; import java.util.Arrays; import java.util.List; @@ -38,7 +38,7 @@ public class PathCommand extends Command { public void execute(String label, IArgConsumer args) throws CommandException { ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess(); args.requireMax(0); - WorldScanner.INSTANCE.repack(ctx); + BaritoneAPI.getProvider().getWorldScanner().repack(ctx); customGoalProcess.path(); logDirect("Now pathing"); } diff --git a/src/main/java/baritone/command/defaults/RenderCommand.java b/src/main/java/baritone/command/defaults/RenderCommand.java index a77add6e6..4dd99a462 100644 --- a/src/main/java/baritone/command/defaults/RenderCommand.java +++ b/src/main/java/baritone/command/defaults/RenderCommand.java @@ -37,8 +37,8 @@ public class RenderCommand extends Command { public void execute(String label, IArgConsumer args) throws CommandException { args.requireMax(0); BetterBlockPos origin = ctx.playerFeet(); - int renderDistance = (mc.gameSettings.renderDistanceChunks + 1) * 16; - mc.worldRenderer.markBlockRangeForRenderUpdate( + int renderDistance = (ctx.minecraft().gameSettings.renderDistanceChunks + 1) * 16; + ctx.minecraft().worldRenderer.markBlockRangeForRenderUpdate( origin.x - renderDistance, 0, origin.z - renderDistance, diff --git a/src/main/java/baritone/command/defaults/RepackCommand.java b/src/main/java/baritone/command/defaults/RepackCommand.java index cafbea524..9f972561d 100644 --- a/src/main/java/baritone/command/defaults/RepackCommand.java +++ b/src/main/java/baritone/command/defaults/RepackCommand.java @@ -17,11 +17,11 @@ package baritone.command.defaults; +import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.exception.CommandException; -import baritone.cache.WorldScanner; import java.util.Arrays; import java.util.List; @@ -36,7 +36,7 @@ public class RepackCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { args.requireMax(0); - logDirect(String.format("Queued %d chunks for repacking", WorldScanner.INSTANCE.repack(ctx))); + logDirect(String.format("Queued %d chunks for repacking", BaritoneAPI.getProvider().getWorldScanner().repack(ctx))); } @Override diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java index 32878633e..97d1e6111 100644 --- a/src/main/java/baritone/command/defaults/SelCommand.java +++ b/src/main/java/baritone/command/defaults/SelCommand.java @@ -21,6 +21,7 @@ import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; +import baritone.api.command.datatypes.ForAxis; import baritone.api.command.datatypes.ForBlockOptionalMeta; import baritone.api.command.datatypes.ForDirection; import baritone.api.command.datatypes.RelativeBlockPos; @@ -31,6 +32,8 @@ import baritone.api.command.helpers.TabCompleteHelper; import baritone.api.event.events.RenderEvent; import baritone.api.event.listener.AbstractGameEventListener; import baritone.api.schematic.*; +import baritone.api.schematic.mask.shape.CylinderMask; +import baritone.api.schematic.mask.shape.SphereMask; import baritone.api.selection.ISelection; import baritone.api.selection.ISelectionManager; import baritone.api.utils.BetterBlockPos; @@ -50,6 +53,7 @@ import java.awt.*; import java.util.List; import java.util.*; import java.util.function.Function; +import java.util.function.UnaryOperator; import java.util.stream.Stream; public class SelCommand extends Command { @@ -72,7 +76,7 @@ public class SelCommand extends Command { float lineWidth = Baritone.settings().selectionLineWidth.value; boolean ignoreDepth = Baritone.settings().renderSelectionIgnoreDepth.value; IRenderer.startLines(color, opacity, lineWidth, ignoreDepth); - IRenderer.drawAABB(new AxisAlignedBB(pos1, pos1.add(1, 1, 1))); + IRenderer.emitAABB(new AxisAlignedBB(pos1, pos1.add(1, 1, 1))); IRenderer.endLines(ignoreDepth); } }); @@ -88,7 +92,7 @@ public class SelCommand extends Command { if (action == Action.POS2 && pos1 == null) { throw new CommandInvalidStateException("Set pos1 first before using pos2"); } - BetterBlockPos playerPos = mc.getRenderViewEntity() != null ? BetterBlockPos.from(new BlockPos(mc.getRenderViewEntity())) : ctx.playerFeet(); + BetterBlockPos playerPos = ctx.viewerPos(); BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, playerPos) : playerPos; args.requireMax(0); if (action == Action.POS1) { @@ -117,11 +121,13 @@ public class SelCommand extends Command { logDirect("Undid pos2"); } } - } else if (action == Action.SET || action == Action.WALLS || action == Action.SHELL || action == Action.CLEARAREA || action == Action.REPLACE) { + } else if (action.isFillAction()) { BlockOptionalMeta type = action == Action.CLEARAREA ? new BlockOptionalMeta(Blocks.AIR) : args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE); - BlockOptionalMetaLookup replaces = null; + + final BlockOptionalMetaLookup replaces; // Action.REPLACE + final Direction.Axis alignment; // Action.(H)CYLINDER if (action == Action.REPLACE) { args.requireMin(1); List replacesList = new ArrayList<>(); @@ -131,8 +137,15 @@ public class SelCommand extends Command { } type = args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE); replaces = new BlockOptionalMetaLookup(replacesList.toArray(new BlockOptionalMeta[0])); + alignment = null; + } else if (action == Action.CYLINDER || action == Action.HCYLINDER) { + args.requireMax(1); + alignment = args.hasAny() ? args.getDatatypeFor(ForAxis.INSTANCE) : Direction.Axis.Y; + replaces = null; } else { args.requireMax(0); + replaces = null; + alignment = null; } ISelection[] selections = manager.getSelections(); if (selections.length == 0) { @@ -151,20 +164,41 @@ public class SelCommand extends Command { for (ISelection selection : selections) { Vec3i size = selection.size(); BetterBlockPos min = selection.min(); - ISchematic schematic = new FillSchematic(size.getX(), size.getY(), size.getZ(), type); - if (action == Action.WALLS) { - schematic = new WallsSchematic(schematic); - } else if (action == Action.SHELL) { - schematic = new ShellSchematic(schematic); - } else if (action == Action.REPLACE) { - schematic = new ReplaceSchematic(schematic, replaces); - } + + // Java 8 so no switch expressions 😿 + UnaryOperator create = fill -> { + final int w = fill.widthX(); + final int h = fill.heightY(); + final int l = fill.lengthZ(); + + switch (action) { + case WALLS: + return new WallsSchematic(fill); + case SHELL: + return new ShellSchematic(fill); + case REPLACE: + return new ReplaceSchematic(fill, replaces); + case SPHERE: + return MaskSchematic.create(fill, new SphereMask(w, h, l, true).compute()); + case HSPHERE: + return MaskSchematic.create(fill, new SphereMask(w, h, l, false).compute()); + case CYLINDER: + return MaskSchematic.create(fill, new CylinderMask(w, h, l, true, alignment).compute()); + case HCYLINDER: + return MaskSchematic.create(fill, new CylinderMask(w, h, l, false, alignment).compute()); + default: + // Silent fail + return fill; + } + }; + + ISchematic schematic = create.apply(new FillSchematic(size.getX(), size.getY(), size.getZ(), type)); composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z); } baritone.getBuilderProcess().build("Fill", composite, origin); logDirect("Filling now"); } else if (action == Action.COPY) { - BetterBlockPos playerPos = mc.getRenderViewEntity() != null ? BetterBlockPos.from(new BlockPos(mc.getRenderViewEntity())) : ctx.playerFeet(); + BetterBlockPos playerPos = ctx.viewerPos(); BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, playerPos) : playerPos; args.requireMax(0); ISelection[] selections = manager.getSelections(); @@ -205,7 +239,7 @@ public class SelCommand extends Command { clipboardOffset = origin.subtract(pos); logDirect("Selection copied"); } else if (action == Action.PASTE) { - BetterBlockPos playerPos = mc.getRenderViewEntity() != null ? BetterBlockPos.from(new BlockPos(mc.getRenderViewEntity())) : ctx.playerFeet(); + BetterBlockPos playerPos = ctx.viewerPos(); BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, playerPos) : playerPos; args.requireMax(0); if (clipboard == null) { @@ -254,12 +288,15 @@ public class SelCommand extends Command { if (args.hasAtMost(3)) { return args.tabCompleteDatatype(RelativeBlockPos.INSTANCE); } - } else if (action == Action.SET || action == Action.WALLS || action == Action.CLEARAREA || action == Action.REPLACE) { + } else if (action.isFillAction()) { if (args.hasExactlyOne() || action == Action.REPLACE) { while (args.has(2)) { args.get(); } return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE); + } else if (args.hasExactly(2) && (action == Action.CYLINDER || action == Action.HCYLINDER)) { + args.get(); + return args.tabCompleteDatatype(ForAxis.INSTANCE); } } else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) { if (args.hasExactlyOne()) { @@ -305,6 +342,10 @@ public class SelCommand extends Command { "> sel set/fill/s/f [block] - Completely fill all selections with a block.", "> sel walls/w [block] - Fill in the walls of the selection with a specified block.", "> sel shell/shl [block] - The same as walls, but fills in a ceiling and floor too.", + "> sel sphere/sph [block] - Fills the selection with a sphere bounded by the sides.", + "> sel hsphere/hsph [block] - The same as sphere, but hollow.", + "> sel cylinder/cyl [block] - Fills the selection with a cylinder bounded by the sides, oriented about the given axis. (default=y)", + "> sel hcylinder/hcyl [block] - The same as cylinder, but hollow.", "> sel cleararea/ca - Basically 'set air'.", "> sel replace/r - Replaces blocks with another block.", "> sel copy/cp - Copy the selected area relative to the specified or your position.", @@ -324,6 +365,10 @@ public class SelCommand extends Command { SET("set", "fill", "s", "f"), WALLS("walls", "w"), SHELL("shell", "shl"), + SPHERE("sphere", "sph"), + HSPHERE("hsphere", "hsph"), + CYLINDER("cylinder", "cyl"), + HCYLINDER("hcylinder", "hcyl"), CLEARAREA("cleararea", "ca"), REPLACE("replace", "r"), EXPAND("expand", "ex"), @@ -355,6 +400,18 @@ public class SelCommand extends Command { } return names.toArray(new String[0]); } + + public final boolean isFillAction() { + return this == SET + || this == WALLS + || this == SHELL + || this == SPHERE + || this == HSPHERE + || this == CYLINDER + || this == HCYLINDER + || this == CLEARAREA + || this == REPLACE; + } } enum TransformTarget { diff --git a/src/main/java/baritone/command/defaults/SetCommand.java b/src/main/java/baritone/command/defaults/SetCommand.java index fe617a0d0..2b322b1eb 100644 --- a/src/main/java/baritone/command/defaults/SetCommand.java +++ b/src/main/java/baritone/command/defaults/SetCommand.java @@ -22,12 +22,14 @@ import baritone.api.IBaritone; import baritone.api.Settings; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; +import baritone.api.command.datatypes.RelativeFile; import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.command.exception.CommandInvalidTypeException; import baritone.api.command.helpers.Paginator; import baritone.api.command.helpers.TabCompleteHelper; import baritone.api.utils.SettingsUtil; +import net.minecraft.client.Minecraft; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; @@ -57,6 +59,18 @@ public class SetCommand extends Command { logDirect("Settings saved"); return; } + if (Arrays.asList("load", "ld").contains(arg)) { + String file = SETTINGS_DEFAULT_NAME; + if (args.hasAny()) { + file = args.getString(); + } + // reset to defaults + SettingsUtil.modifiedSettings(Baritone.settings()).forEach(Settings.Setting::reset); + // then load from disk + SettingsUtil.readAndApply(Baritone.settings(), file); + logDirect("Settings reloaded from " + file); + return; + } boolean viewModified = Arrays.asList("m", "mod", "modified").contains(arg); boolean viewAll = Arrays.asList("all", "l", "list").contains(arg); boolean paginate = viewModified || viewAll; @@ -65,7 +79,7 @@ public class SetCommand extends Command { args.requireMax(1); List toPaginate = (viewModified ? SettingsUtil.modifiedSettings(Baritone.settings()) : Baritone.settings().allSettings).stream() - .filter(s -> !javaOnlySetting(s)) + .filter(s -> !s.isJavaOnly()) .filter(s -> s.getName().toLowerCase(Locale.US).contains(search.toLowerCase(Locale.US))) .sorted((s1, s2) -> String.CASE_INSENSITIVE_ORDER.compare(s1.getName(), s2.getName())) .collect(Collectors.toList()); @@ -129,7 +143,7 @@ public class SetCommand extends Command { if (setting == null) { throw new CommandInvalidTypeException(args.consumed(), "a valid setting"); } - if (javaOnlySetting(setting)) { + if (setting.isJavaOnly()) { // ideally it would act as if the setting didn't exist // but users will see it in Settings.java or its javadoc // so at some point we have to tell them or they will see it as a bug @@ -209,6 +223,9 @@ public class SetCommand extends Command { .addToggleableSettings() .filterPrefix(args.getString()) .stream(); + } else if (Arrays.asList("ld", "load").contains(arg.toLowerCase(Locale.US))) { + // settings always use the directory of the main Minecraft instance + return RelativeFile.tabComplete(args, Minecraft.getInstance().gameDir.toPath().resolve("baritone").toFile()); } Settings.Setting setting = Baritone.settings().byLowerName.get(arg.toLowerCase(Locale.US)); if (setting != null) { @@ -228,7 +245,7 @@ public class SetCommand extends Command { return new TabCompleteHelper() .addSettings() .sortAlphabetically() - .prepend("list", "modified", "reset", "toggle", "save") + .prepend("list", "modified", "reset", "toggle", "save", "load") .filterPrefix(arg) .stream(); } @@ -255,7 +272,9 @@ public class SetCommand extends Command { "> set reset all - Reset ALL SETTINGS to their defaults", "> set reset - Reset a setting to its default", "> set toggle - Toggle a boolean setting", - "> set save - Save all settings (this is automatic tho)" + "> set save - Save all settings (this is automatic tho)", + "> set load - Load settings from settings.txt", + "> set load [filename] - Load settings from another file in your minecraft/baritone" ); } } diff --git a/src/main/java/baritone/command/defaults/SurfaceCommand.java b/src/main/java/baritone/command/defaults/SurfaceCommand.java index 339048dfe..822ff4f25 100644 --- a/src/main/java/baritone/command/defaults/SurfaceCommand.java +++ b/src/main/java/baritone/command/defaults/SurfaceCommand.java @@ -38,13 +38,13 @@ public class SurfaceCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { - final BetterBlockPos playerPos = baritone.getPlayerContext().playerFeet(); - final int surfaceLevel = baritone.getPlayerContext().world().getSeaLevel(); - final int worldHeight = baritone.getPlayerContext().world().getActualHeight(); + final BetterBlockPos playerPos = ctx.playerFeet(); + final int surfaceLevel = ctx.world().getSeaLevel(); + final int worldHeight = ctx.world().getActualHeight(); // Ensure this command will not run if you are above the surface level and the block above you is air // As this would imply that your are already on the open surface - if (playerPos.getY() > surfaceLevel && mc.world.getBlockState(playerPos.up()).getBlock() instanceof AirBlock) { + if (playerPos.getY() > surfaceLevel && ctx.world().getBlockState(playerPos.up()).getBlock() instanceof AirBlock) { logDirect("Already at surface"); return; } @@ -54,7 +54,7 @@ public class SurfaceCommand extends Command { for (int currentIteratedY = startingYPos; currentIteratedY < worldHeight; currentIteratedY++) { final BetterBlockPos newPos = new BetterBlockPos(playerPos.getX(), currentIteratedY, playerPos.getZ()); - if (!(mc.world.getBlockState(newPos).getBlock() instanceof AirBlock) && newPos.getY() > playerPos.getY()) { + if (!(ctx.world().getBlockState(newPos).getBlock() instanceof AirBlock) && newPos.getY() > playerPos.getY()) { Goal goal = new GoalBlock(newPos.up()); logDirect(String.format("Going to: %s", goal.toString())); baritone.getCustomGoalProcess().setGoalAndPath(goal); diff --git a/src/main/java/baritone/command/defaults/WaypointsCommand.java b/src/main/java/baritone/command/defaults/WaypointsCommand.java index 433a8607f..1db7d9b39 100644 --- a/src/main/java/baritone/command/defaults/WaypointsCommand.java +++ b/src/main/java/baritone/command/defaults/WaypointsCommand.java @@ -149,7 +149,11 @@ public class WaypointsCommand extends Command { logDirect(component); } else if (action == Action.CLEAR) { args.requireMax(1); - IWaypoint.Tag tag = IWaypoint.Tag.getByName(args.getString()); + String name = args.getString(); + IWaypoint.Tag tag = IWaypoint.Tag.getByName(name); + if (tag == null) { + throw new CommandInvalidStateException("Invalid tag, \"" + name + "\""); + } IWaypoint[] waypoints = ForWaypoints.getWaypointsByTag(this.baritone, tag); for (IWaypoint waypoint : waypoints) { ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint); diff --git a/src/main/java/baritone/command/manager/CommandManager.java b/src/main/java/baritone/command/manager/CommandManager.java index 4c33226d3..8712165f1 100644 --- a/src/main/java/baritone/command/manager/CommandManager.java +++ b/src/main/java/baritone/command/manager/CommandManager.java @@ -21,6 +21,7 @@ import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.command.ICommand; import baritone.api.command.argument.ICommandArgument; +import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandUnhandledException; import baritone.api.command.exception.ICommandException; import baritone.api.command.helpers.TabCompleteHelper; @@ -153,9 +154,12 @@ public class CommandManager implements ICommandManager { private Stream tabComplete() { try { return this.command.tabComplete(this.label, this.args); + } catch (CommandException ignored) { + // NOP } catch (Throwable t) { - return Stream.empty(); + t.printStackTrace(); } + return Stream.empty(); } } } diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index ba40f1b6e..8e1afcd51 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -115,7 +115,7 @@ public final class GameEventHandler implements IEventBus, Helper { if (event.getState() == EventState.POST) { cache.closeWorld(); if (event.getWorld() != null) { - cache.initWorld(event.getWorld().getDimension().getType()); + cache.initWorld(event.getWorld()); } } diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java index 69952fd9e..683228151 100644 --- a/src/main/java/baritone/pathing/movement/CalculationContext.java +++ b/src/main/java/baritone/pathing/movement/CalculationContext.java @@ -91,8 +91,8 @@ public class CalculationContext { this.baritone = baritone; ClientPlayerEntity player = baritone.getPlayerContext().player(); this.world = baritone.getPlayerContext().world(); - this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld(); - this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread); + this.worldData = (WorldData) baritone.getPlayerContext().worldData(); + this.bsi = new BlockStateInterface(baritone.getPlayerContext(), forUseOnAnotherThread); this.toolSet = new ToolSet(player); this.hasThrowaway = Baritone.settings().allowPlace.value && ((Baritone) baritone).getInventoryBehavior().hasGenericThrowaway(); this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.value && PlayerInventory.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.getDimension().isNether(); diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index 395c2de00..9ffaadd12 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -163,7 +163,7 @@ public abstract class Movement implements IMovement, MovementHelper { if (!MovementHelper.canWalkThrough(ctx, blockPos)) { // can't break air, so don't try somethingInTheWay = true; MovementHelper.switchToBestToolFor(ctx, BlockStateInterface.get(ctx, blockPos)); - Optional reachable = RotationUtils.reachable(ctx.player(), blockPos, ctx.playerController().getBlockReachDistance()); + Optional reachable = RotationUtils.reachable(ctx, blockPos, ctx.playerController().getBlockReachDistance()); if (reachable.isPresent()) { Rotation rotTowardsBlock = reachable.get(); state.setTarget(new MovementState.MovementTarget(rotTowardsBlock, true)); diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 691789ea1..84434d850 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -636,9 +636,9 @@ public interface MovementHelper extends ActionCosts, Helper { static void moveTowards(IPlayerContext ctx, MovementState state, BlockPos pos) { state.setTarget(new MovementTarget( - new Rotation(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), + RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(pos), - ctx.playerRotations()).getYaw(), ctx.player().rotationPitch), + ctx.playerRotations()).withPitch(ctx.playerRotations().getPitch()), false )).setInput(Input.MOVE_FORWARD, true); } @@ -743,7 +743,8 @@ public interface MovementHelper extends ActionCosts, Helper { double faceY = (placeAt.getY() + against1.getY() + 0.5D) * 0.5D; double faceZ = (placeAt.getZ() + against1.getZ() + 1.0D) * 0.5D; Rotation place = RotationUtils.calcRotationFromVec3d(wouldSneak ? RayTraceUtils.inferSneakingEyePosition(ctx.player()) : ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations()); - RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), place, ctx.playerController().getBlockReachDistance(), wouldSneak); + Rotation actual = baritone.getLookBehavior().getAimProcessor().peekRotation(place); + RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), actual, ctx.playerController().getBlockReachDistance(), wouldSneak); if (res != null && res.getType() == RayTraceResult.Type.BLOCK && ((BlockRayTraceResult) res).getPos().equals(against1) && ((BlockRayTraceResult) res).getPos().offset(((BlockRayTraceResult) res).getFace()).equals(placeAt)) { state.setTarget(new MovementState.MovementTarget(place, true)); found = true; diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java index 22055180f..d7db3f9f8 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java @@ -20,7 +20,6 @@ package baritone.pathing.movement.movements; import baritone.api.IBaritone; import baritone.api.pathing.movement.MovementStatus; import baritone.api.utils.BetterBlockPos; -import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; import baritone.api.utils.input.Input; import baritone.pathing.movement.CalculationContext; @@ -31,10 +30,9 @@ import baritone.utils.BlockStateInterface; import baritone.utils.pathing.MutableMoveResult; import com.google.common.collect.ImmutableSet; import net.minecraft.block.Block; -import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.block.BlockState; import net.minecraft.block.FallingBlock; -import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -234,11 +232,10 @@ public class MovementDescend extends Movement { if (safeMode()) { double destX = (src.getX() + 0.5) * 0.17 + (dest.getX() + 0.5) * 0.83; double destZ = (src.getZ() + 0.5) * 0.17 + (dest.getZ() + 0.5) * 0.83; - ClientPlayerEntity player = ctx.player(); state.setTarget(new MovementState.MovementTarget( - new Rotation(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), + RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(destX, dest.getY(), destZ), - new Rotation(player.rotationYaw, player.rotationPitch)).getYaw(), player.rotationPitch), + ctx.playerRotations()).withPitch(ctx.playerRotations().getPitch()), false )).setInput(Input.MOVE_FORWARD, true); return state; diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index 4112dd68f..fa03e66e5 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -188,9 +188,9 @@ public class MovementPillar extends Movement { boolean vine = fromDown.getBlock() == Blocks.VINE; Rotation rotation = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(positionToPlace), - new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch)); + ctx.playerRotations()); if (!ladder) { - state.setTarget(new MovementState.MovementTarget(new Rotation(ctx.player().rotationYaw, rotation.getPitch()), true)); + state.setTarget(new MovementState.MovementTarget(ctx.playerRotations().withPitch(rotation.getPitch()), true)); } boolean blockIsThere = MovementHelper.canWalkOn(ctx, src) || ladder; @@ -249,7 +249,7 @@ public class MovementPillar extends Movement { Block fr = frState.getBlock(); // TODO: Evaluate usage of getMaterial().isReplaceable() if (!(fr instanceof AirBlock || frState.getMaterial().isReplaceable())) { - RotationUtils.reachable(ctx.player(), src, ctx.playerController().getBlockReachDistance()) + RotationUtils.reachable(ctx, src, ctx.playerController().getBlockReachDistance()) .map(rot -> new MovementState.MovementTarget(rot, true)) .ifPresent(state::setTarget); state.setInput(Input.JUMP, false); // breaking is like 5x slower when you're jumping diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index f512e8128..d822d5d48 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -30,10 +30,7 @@ import baritone.api.schematic.ISchematic; import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.SubstituteSchematic; import baritone.api.schematic.format.ISchematicFormat; -import baritone.api.utils.BetterBlockPos; -import baritone.api.utils.RayTraceUtils; -import baritone.api.utils.Rotation; -import baritone.api.utils.RotationUtils; +import baritone.api.utils.*; import baritone.api.utils.input.Input; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; @@ -159,7 +156,6 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!format.isPresent()) { return false; } - ISchematic parsed; try { parsed = format.get().parse(new FileInputStream(schematic)); @@ -167,20 +163,22 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil e.printStackTrace(); return false; } - - if (Baritone.settings().mapArtMode.value) { - parsed = new MapArtSchematic((IStaticSchematic) parsed); - } - - if (Baritone.settings().buildOnlySelection.value) { - parsed = new SelectionSchematic(parsed, origin, baritone.getSelectionManager().getSelections()); - } - - + parsed = applyMapArtAndSelection(origin, (IStaticSchematic) parsed); build(name, parsed, origin); return true; } + private ISchematic applyMapArtAndSelection(Vec3i origin, IStaticSchematic parsed) { + ISchematic schematic = parsed; + if (Baritone.settings().mapArtMode.value) { + schematic = new MapArtSchematic(parsed); + } + if (Baritone.settings().buildOnlySelection.value) { + schematic = new SelectionSchematic(schematic, origin, baritone.getSelectionManager().getSelections()); + } + return schematic; + } + @Override public void buildOpenSchematic() { if (SchematicaHelper.isSchematicaPresent()) { @@ -219,7 +217,8 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil try { LitematicaSchematic schematic1 = new LitematicaSchematic(CompressedStreamTools.readCompressed(Files.newInputStream(LitematicaHelper.getSchematicFile(i).toPath())), false); Vec3i correctedOrigin = LitematicaHelper.getCorrectedOrigin(schematic1, i); - LitematicaSchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i); + ISchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i); + schematic2 = applyMapArtAndSelection(origin, (IStaticSchematic) schematic2); build(name, schematic2, correctedOrigin); } catch (IOException e) { logDirect("Schematic File could not be loaded."); @@ -283,7 +282,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil BlockState curr = bcc.bsi.get0(x, y, z); if (!(curr.getBlock() instanceof AirBlock) && !(curr.getBlock() == Blocks.WATER || curr.getBlock() == Blocks.LAVA) && !valid(curr, desired, false)) { BetterBlockPos pos = new BetterBlockPos(x, y, z); - Optional rot = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance()); + Optional rot = RotationUtils.reachable(ctx, pos, ctx.playerController().getBlockReachDistance()); if (rot.isPresent()) { return Optional.of(new Tuple<>(pos, rot.get())); } @@ -362,9 +361,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil double placeY = placeAgainstPos.y + aabb.minY * placementMultiplier.y + aabb.maxY * (1 - placementMultiplier.y); double placeZ = placeAgainstPos.z + aabb.minZ * placementMultiplier.z + aabb.maxZ * (1 - placementMultiplier.z); Rotation rot = RotationUtils.calcRotationFromVec3d(RayTraceUtils.inferSneakingEyePosition(ctx.player()), new Vec3d(placeX, placeY, placeZ), ctx.playerRotations()); - RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot, ctx.playerController().getBlockReachDistance(), true); + Rotation actualRot = baritone.getLookBehavior().getAimProcessor().peekRotation(rot); + RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), actualRot, ctx.playerController().getBlockReachDistance(), true); if (result != null && result.getType() == RayTraceResult.Type.BLOCK && ((BlockRayTraceResult) result).getPos().equals(placeAgainstPos) && ((BlockRayTraceResult) result).getFace() == against.getOpposite()) { - OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, rot); + OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, actualRot); if (hotbar.isPresent()) { return Optional.of(new Placement(hotbar.getAsInt(), placeAgainstPos, against.getOpposite(), rot)); } @@ -574,7 +574,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil for (int i = 9; i < 36; i++) { for (BlockState desired : noValidHotbarOption) { if (valid(approxPlaceable.get(i), desired, true)) { - baritone.getInventoryBehavior().attemptToPutOnHotbar(i, usefulSlots::contains); + if (!baritone.getInventoryBehavior().attemptToPutOnHotbar(i, usefulSlots::contains)) { + // awaiting inventory move, so pause + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } break outer; } } @@ -700,7 +703,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil incorrectPositions.forEach(pos -> { BlockState state = bcc.bsi.get0(pos); if (state.getBlock() instanceof AirBlock) { - if (approxPlaceable.contains(bcc.getSchematic(pos.x, pos.y, pos.z, state))) { + if (containsBlockState(approxPlaceable, bcc.getSchematic(pos.x, pos.y, pos.z, state))) { placeable.add(pos); } else { BlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state); @@ -773,6 +776,28 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return primary.heuristic(x, y, z); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + JankyGoalComposite goal = (JankyGoalComposite) o; + return Objects.equals(primary, goal.primary) + && Objects.equals(fallback, goal.fallback); + } + + @Override + public int hashCode() { + int hash = -1701079641; + hash = hash * 1196141026 + primary.hashCode(); + hash = hash * -80327868 + fallback.hashCode(); + return hash; + } + @Override public String toString() { return "JankyComposite Primary: " + primary + " Fallback: " + fallback; @@ -794,6 +819,21 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil // but any other adjacent works for breaking, including inside or below return super.isInGoal(x, y, z); } + + @Override + public String toString() { + return String.format( + "GoalBreak{x=%s,y=%s,z=%s}", + SettingsUtil.maybeCensor(x), + SettingsUtil.maybeCensor(y), + SettingsUtil.maybeCensor(z) + ); + } + + @Override + public int hashCode() { + return super.hashCode() * 1636324008; + } } private Goal placementGoal(BlockPos pos, BuilderCalculationContext bcc) { @@ -837,6 +877,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil this.allowSameLevel = allowSameLevel; } + @Override public boolean isInGoal(int x, int y, int z) { if (x == this.x && y == this.y && z == this.z) { return false; @@ -853,10 +894,41 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return super.isInGoal(x, y, z); } + @Override public double heuristic(int x, int y, int z) { // prioritize lower y coordinates return this.y * 100 + super.heuristic(x, y, z); } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + + GoalAdjacent goal = (GoalAdjacent) o; + return allowSameLevel == goal.allowSameLevel + && Objects.equals(no, goal.no); + } + + @Override + public int hashCode() { + int hash = 806368046; + hash = hash * 1412661222 + super.hashCode(); + hash = hash * 1730799370 + (int) BetterBlockPos.longHash(no.getX(), no.getY(), no.getZ()); + hash = hash * 260592149 + (allowSameLevel ? -1314802005 : 1565710265); + return hash; + } + + @Override + public String toString() { + return String.format( + "GoalAdjacent{x=%s,y=%s,z=%s}", + SettingsUtil.maybeCensor(x), + SettingsUtil.maybeCensor(y), + SettingsUtil.maybeCensor(z) + ); + } } public static class GoalPlace extends GoalBlock { @@ -865,10 +937,26 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil super(placeAt.up()); } + @Override public double heuristic(int x, int y, int z) { // prioritize lower y coordinates return this.y * 100 + super.heuristic(x, y, z); } + + @Override + public int hashCode() { + return super.hashCode() * 1910811835; + } + + @Override + public String toString() { + return String.format( + "GoalPlace{x=%s,y=%s,z=%s}", + SettingsUtil.maybeCensor(x), + SettingsUtil.maybeCensor(y), + SettingsUtil.maybeCensor(z) + ); + } } @Override @@ -931,6 +1019,15 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return true; } + private boolean containsBlockState(Collection states, BlockState state) { + for (BlockState testee : states) { + if (sameBlockstate(testee, state)) { + return true; + } + } + return false; + } + private boolean valid(BlockState current, BlockState desired, boolean itemVerify) { if (desired == null) { return true; diff --git a/src/main/java/baritone/process/FarmProcess.java b/src/main/java/baritone/process/FarmProcess.java index e912bb34f..c343576d8 100644 --- a/src/main/java/baritone/process/FarmProcess.java +++ b/src/main/java/baritone/process/FarmProcess.java @@ -18,8 +18,10 @@ package baritone.process; import baritone.Baritone; +import baritone.api.BaritoneAPI; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalBlock; +import baritone.api.pathing.goals.GoalGetToBlock; import baritone.api.pathing.goals.GoalComposite; import baritone.api.process.IFarmProcess; import baritone.api.process.PathingCommand; @@ -28,7 +30,6 @@ import baritone.api.utils.RayTraceUtils; import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; import baritone.api.utils.input.Input; -import baritone.cache.WorldScanner; import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; import net.minecraft.block.*; @@ -82,6 +83,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro Items.POTATO, Items.CARROT, Items.NETHER_WART, + Items.COCOA_BEANS, Blocks.SUGAR_CANE.asItem(), Blocks.CACTUS.asItem() ); @@ -115,6 +117,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro PUMPKIN(Blocks.PUMPKIN, state -> true), MELON(Blocks.MELON, state -> true), NETHERWART(Blocks.NETHER_WART, state -> state.get(NetherWartBlock.AGE) >= 3), + COCOA(Blocks.COCOA, state -> state.get(CocoaBlock.AGE) >= 2), SUGARCANE(Blocks.SUGAR_CANE, null) { @Override public boolean readyToHarvest(World world, BlockPos pos, BlockState state) { @@ -172,6 +175,10 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro return !stack.isEmpty() && stack.getItem().equals(Items.NETHER_WART); } + private boolean isCocoa(ItemStack stack) { + return !stack.isEmpty() && stack.getItem().equals(Items.COCOA_BEANS); + } + @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { ArrayList scan = new ArrayList<>(); @@ -180,13 +187,14 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } if (Baritone.settings().replantCrops.value) { scan.add(Blocks.FARMLAND); + scan.add(Blocks.JUNGLE_LOG); if (Baritone.settings().replantNetherWart.value) { scan.add(Blocks.SOUL_SAND); } } if (Baritone.settings().mineGoalUpdateInterval.value != 0 && tickCount++ % Baritone.settings().mineGoalUpdateInterval.value == 0) { - Baritone.getExecutor().execute(() -> locations = WorldScanner.INSTANCE.scanChunkRadius(ctx, scan, 256, 10, 10)); + Baritone.getExecutor().execute(() -> locations = BaritoneAPI.getProvider().getWorldScanner().scanChunkRadius(ctx, scan, 256, 10, 10)); } if (locations == null) { return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); @@ -195,6 +203,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro List openFarmland = new ArrayList<>(); List bonemealable = new ArrayList<>(); List openSoulsand = new ArrayList<>(); + List openLog = new ArrayList<>(); for (BlockPos pos : locations) { //check if the target block is out of range. if (range != 0 && pos.distanceSq(center) > range * range) { @@ -215,6 +224,15 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } continue; } + if (state.getBlock() == Blocks.JUNGLE_LOG) { + for (Direction direction : Direction.Plane.HORIZONTAL) { + if (ctx.world().getBlockState(pos.offset(direction)).getBlock() instanceof AirBlock) { + openLog.add(pos); + break; + } + } + continue; + } if (readyForHarvest(ctx.world(), pos, state)) { toBreak.add(pos); continue; @@ -243,7 +261,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro both.addAll(openSoulsand); for (BlockPos pos : both) { boolean soulsand = openSoulsand.contains(pos); - Optional rot = RotationUtils.reachableOffset(ctx.player(), pos, new Vec3d(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), ctx.playerController().getBlockReachDistance(), false); + Optional rot = RotationUtils.reachableOffset(ctx, pos, new Vec3d(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), ctx.playerController().getBlockReachDistance(), false); if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, soulsand ? this::isNetherWart : this::isPlantable)) { RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance()); if (result instanceof BlockRayTraceResult && ((BlockRayTraceResult) result).getFace() == Direction.UP) { @@ -255,6 +273,25 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } } } + for (BlockPos pos : openLog) { + for (Direction dir : Direction.Plane.HORIZONTAL) { + if (!(ctx.world().getBlockState(pos.offset(dir)).getBlock() instanceof AirBlock)) { + continue; + } + Vec3d faceCenter = new Vec3d(pos).add(0.5, 0.5, 0.5).add(new Vec3d(dir.getDirectionVec()).scale(0.5)); + Optional rot = RotationUtils.reachableOffset(ctx, pos, faceCenter, ctx.playerController().getBlockReachDistance(), false); + if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isCocoa)) { + RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance()); + if (result instanceof BlockRayTraceResult && ((BlockRayTraceResult) result).getFace() == dir) { + baritone.getLookBehavior().updateTarget(rot.get(), true); + if (ctx.isLookingAt(pos)) { + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); + } + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + } + } for (BlockPos pos : bonemealable) { Optional rot = RotationUtils.reachable(ctx, pos); if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isBoneMeal)) { @@ -289,6 +326,15 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro goalz.add(new GoalBlock(pos.up())); } } + if (baritone.getInventoryBehavior().throwaway(false, this::isCocoa)) { + for (BlockPos pos : openLog) { + for (Direction direction : Direction.Plane.HORIZONTAL) { + if (ctx.world().getBlockState(pos.offset(direction)).getBlock() instanceof AirBlock) { + goalz.add(new GoalGetToBlock(pos.offset(direction))); + } + } + } + } if (baritone.getInventoryBehavior().throwaway(false, this::isBoneMeal)) { for (BlockPos pos : bonemealable) { goalz.add(new GoalBlock(pos)); diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index 5db33fc2d..0a7f7c94d 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -211,7 +211,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG private boolean rightClick() { for (BlockPos pos : knownLocations) { - Optional reachable = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance()); + Optional reachable = RotationUtils.reachable(ctx, pos, ctx.playerController().getBlockReachDistance()); if (reachable.isPresent()) { baritone.getLookBehavior().updateTarget(reachable.get(), true); if (knownLocations.contains(ctx.getSelectedBlock().orElse(null))) { diff --git a/src/main/java/baritone/process/InventoryPauserProcess.java b/src/main/java/baritone/process/InventoryPauserProcess.java new file mode 100644 index 000000000..eff89a498 --- /dev/null +++ b/src/main/java/baritone/process/InventoryPauserProcess.java @@ -0,0 +1,90 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.utils.BaritoneProcessHelper; + +public class InventoryPauserProcess extends BaritoneProcessHelper { + + boolean pauseRequestedLastTick; + boolean safeToCancelLastTick; + int ticksOfStationary; + + public InventoryPauserProcess(Baritone baritone) { + super(baritone); + } + + @Override + public boolean isActive() { + if (ctx.player() == null || ctx.world() == null) { + return false; + } + return true; + } + + private double motion() { + return ctx.player().getMotion().mul(1, 0, 1).length(); + } + + private boolean stationaryNow() { + return motion() < 0.00001; + } + + public boolean stationaryForInventoryMove() { + pauseRequestedLastTick = true; + return safeToCancelLastTick && ticksOfStationary > 1; + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + //logDebug(pauseRequestedLastTick + " " + safeToCancelLastTick + " " + ticksOfStationary); + safeToCancelLastTick = isSafeToCancel; + if (pauseRequestedLastTick) { + pauseRequestedLastTick = false; + if (stationaryNow()) { + ticksOfStationary++; + } + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + ticksOfStationary = 0; + return new PathingCommand(null, PathingCommandType.DEFER); + } + + @Override + public void onLostControl() { + + } + + @Override + public String displayName0() { + return "inventory pauser"; + } + + @Override + public double priority() { + return 5.1; // slightly higher than backfill + } + + @Override + public boolean isTemporary() { + return true; + } +} diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 3db1064e1..58c74ae01 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -18,6 +18,7 @@ package baritone.process; import baritone.Baritone; +import baritone.api.BaritoneAPI; import baritone.api.pathing.goals.*; import baritone.api.process.IMineProcess; import baritone.api.process.PathingCommand; @@ -25,7 +26,6 @@ import baritone.api.process.PathingCommandType; import baritone.api.utils.*; import baritone.api.utils.input.Input; import baritone.cache.CachedChunk; -import baritone.cache.WorldScanner; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; @@ -320,6 +320,26 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro int zDiff = z - this.z; return GoalBlock.calculate(xDiff, yDiff < -1 ? yDiff + 2 : yDiff == -1 ? 0 : yDiff, zDiff); } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + public int hashCode() { + return super.hashCode() * 393857768; + } + + @Override + public String toString() { + return String.format( + "GoalThreeBlocks{x=%s,y=%s,z=%s}", + SettingsUtil.maybeCensor(x), + SettingsUtil.maybeCensor(y), + SettingsUtil.maybeCensor(z) + ); + } } public List droppedItemsScan() { @@ -363,7 +383,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro locs = prune(ctx, locs, filter, max, blacklist, dropped); if (!untracked.isEmpty() || (Baritone.settings().extendCacheOnThreshold.value && locs.size() < max)) { - locs.addAll(WorldScanner.INSTANCE.scanChunkRadius( + locs.addAll(BaritoneAPI.getProvider().getWorldScanner().scanChunkRadius( ctx.getBaritone().getPlayerContext(), filter, max, @@ -398,7 +418,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro // is an x-ray and it'll get caught if (filter.has(bsi.get0(x, y, z))) { BlockPos pos = new BlockPos(x, y, z); - if ((Baritone.settings().legitMineIncludeDiagonals.value && knownOreLocations.stream().anyMatch(ore -> ore.distanceSq(pos) <= 2 /* sq means this is pytha dist <= sqrt(2) */)) || RotationUtils.reachable(ctx.player(), pos, fakedBlockReachDistance).isPresent()) { + if ((Baritone.settings().legitMineIncludeDiagonals.value && knownOreLocations.stream().anyMatch(ore -> ore.distanceSq(pos) <= 2 /* sq means this is pytha dist <= sqrt(2) */)) || RotationUtils.reachable(ctx, pos, fakedBlockReachDistance).isPresent()) { knownOreLocations.add(pos); } } @@ -438,6 +458,8 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro .filter(pos -> pos.getY() >= Baritone.settings().minYLevelWhileMining.value) + .filter(pos -> pos.getY() <= Baritone.settings().maxYLevelWhileMining.value) + .filter(pos -> !blacklist.contains(pos)) .sorted(Comparator.comparingDouble(new BlockPos(ctx.getBaritone().getPlayerContext().player())::distanceSq)) diff --git a/src/main/java/baritone/selection/SelectionRenderer.java b/src/main/java/baritone/selection/SelectionRenderer.java index 89104d030..b688e9670 100644 --- a/src/main/java/baritone/selection/SelectionRenderer.java +++ b/src/main/java/baritone/selection/SelectionRenderer.java @@ -23,27 +23,27 @@ public class SelectionRenderer implements IRenderer, AbstractGameEventListener { boolean ignoreDepth = settings.renderSelectionIgnoreDepth.value; float lineWidth = settings.selectionLineWidth.value; - if (!settings.renderSelection.value) { + if (!settings.renderSelection.value || selections.length == 0) { return; } IRenderer.startLines(settings.colorSelection.value, opacity, lineWidth, ignoreDepth); for (ISelection selection : selections) { - IRenderer.drawAABB(selection.aabb(), SELECTION_BOX_EXPANSION); + IRenderer.emitAABB(selection.aabb(), SELECTION_BOX_EXPANSION); } if (settings.renderSelectionCorners.value) { IRenderer.glColor(settings.colorSelectionPos1.value, opacity); for (ISelection selection : selections) { - IRenderer.drawAABB(new AxisAlignedBB(selection.pos1(), selection.pos1().add(1, 1, 1))); + IRenderer.emitAABB(new AxisAlignedBB(selection.pos1(), selection.pos1().add(1, 1, 1))); } IRenderer.glColor(settings.colorSelectionPos2.value, opacity); for (ISelection selection : selections) { - IRenderer.drawAABB(new AxisAlignedBB(selection.pos2(), selection.pos2().add(1, 1, 1))); + IRenderer.emitAABB(new AxisAlignedBB(selection.pos2(), selection.pos2().add(1, 1, 1))); } } diff --git a/src/main/java/baritone/utils/BlockBreakHelper.java b/src/main/java/baritone/utils/BlockBreakHelper.java index ad3deda07..5e11912fe 100644 --- a/src/main/java/baritone/utils/BlockBreakHelper.java +++ b/src/main/java/baritone/utils/BlockBreakHelper.java @@ -17,7 +17,6 @@ package baritone.utils; -import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockRayTraceResult; @@ -27,7 +26,7 @@ import net.minecraft.util.math.RayTraceResult; * @author Brady * @since 8/25/2018 */ -public final class BlockBreakHelper implements Helper { +public final class BlockBreakHelper { private final IPlayerContext ctx; private boolean didBreakLastTick; diff --git a/src/main/java/baritone/utils/BlockPlaceHelper.java b/src/main/java/baritone/utils/BlockPlaceHelper.java index a0cc2d2d7..0ce42b01f 100644 --- a/src/main/java/baritone/utils/BlockPlaceHelper.java +++ b/src/main/java/baritone/utils/BlockPlaceHelper.java @@ -18,14 +18,13 @@ package baritone.utils; import baritone.Baritone; -import baritone.api.utils.Helper; import baritone.api.utils.IPlayerContext; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; -public class BlockPlaceHelper implements Helper { +public class BlockPlaceHelper { private final IPlayerContext ctx; private int rightClickTimer; diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java index 48062cf8f..6a3607a3f 100644 --- a/src/main/java/baritone/utils/BlockStateInterface.java +++ b/src/main/java/baritone/utils/BlockStateInterface.java @@ -28,7 +28,6 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientChunkProvider; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; @@ -46,7 +45,6 @@ public class BlockStateInterface { private final ClientChunkProvider provider; private final WorldData worldData; - protected final IBlockReader world; public final BlockPos.MutableBlockPos isPassableBlockPos; public final IBlockReader access; public final BetterWorldBorder worldBorder; @@ -63,20 +61,16 @@ public class BlockStateInterface { } public BlockStateInterface(IPlayerContext ctx, boolean copyLoadedChunks) { - this(ctx.world(), (WorldData) ctx.worldData(), copyLoadedChunks); - } - - public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) { - this.world = world; + final World world = ctx.world(); this.worldBorder = new BetterWorldBorder(world.getWorldBorder()); - this.worldData = worldData; + this.worldData = (WorldData) ctx.worldData(); if (copyLoadedChunks) { this.provider = ((IClientChunkProvider) world.getChunkProvider()).createThreadSafeCopy(); } else { this.provider = (ClientChunkProvider) world.getChunkProvider(); } this.useTheRealWorld = !Baritone.settings().pathThroughCachedOnly.value; - if (!Minecraft.getInstance().isOnExecutionThread()) { + if (!ctx.minecraft().isOnExecutionThread()) { throw new IllegalStateException(); } this.isPassableBlockPos = new BlockPos.MutableBlockPos(); diff --git a/src/main/java/baritone/utils/GuiClick.java b/src/main/java/baritone/utils/GuiClick.java index c6d9cb35f..44ecf48b9 100644 --- a/src/main/java/baritone/utils/GuiClick.java +++ b/src/main/java/baritone/utils/GuiClick.java @@ -125,21 +125,11 @@ public class GuiClick extends Screen implements Helper { // drawSingleSelectionBox WHEN? PathRenderer.drawManySelectionBoxes(e, Collections.singletonList(currentMouseOver), Color.CYAN); if (clickStart != null && !clickStart.equals(currentMouseOver)) { - GlStateManager.enableBlend(); - GlStateManager.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); - GlStateManager.color4f(Color.RED.getColorComponents(null)[0], Color.RED.getColorComponents(null)[1], Color.RED.getColorComponents(null)[2], 0.4F); - GlStateManager.lineWidth(Baritone.settings().pathRenderLineWidthPixels.value); - GlStateManager.disableTexture(); - GlStateManager.depthMask(false); - GlStateManager.disableDepthTest(); + IRenderer.startLines(Color.RED, Baritone.settings().pathRenderLineWidthPixels.value, true); BetterBlockPos a = new BetterBlockPos(currentMouseOver); BetterBlockPos b = new BetterBlockPos(clickStart); - IRenderer.drawAABB(new AxisAlignedBB(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.min(a.z, b.z), Math.max(a.x, b.x) + 1, Math.max(a.y, b.y) + 1, Math.max(a.z, b.z) + 1)); - GlStateManager.enableDepthTest(); - - GlStateManager.depthMask(true); - GlStateManager.enableTexture(); - GlStateManager.disableBlend(); + IRenderer.emitAABB(new AxisAlignedBB(Math.min(a.x, b.x), Math.min(a.y, b.y), Math.min(a.z, b.z), Math.max(a.x, b.x) + 1, Math.max(a.y, b.y) + 1, Math.max(a.z, b.z) + 1)); + IRenderer.endLines(true); } } } diff --git a/src/main/java/baritone/utils/IRenderer.java b/src/main/java/baritone/utils/IRenderer.java index e8c753e66..97931b55b 100644 --- a/src/main/java/baritone/utils/IRenderer.java +++ b/src/main/java/baritone/utils/IRenderer.java @@ -19,11 +19,12 @@ package baritone.utils; import baritone.api.BaritoneAPI; import baritone.api.Settings; -import baritone.api.utils.Helper; import baritone.utils.accessor.IEntityRenderManager; import com.mojang.blaze3d.platform.GlStateManager; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.math.AxisAlignedBB; @@ -35,12 +36,18 @@ public interface IRenderer { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); - IEntityRenderManager renderManager = (IEntityRenderManager) Helper.mc.getRenderManager(); + IEntityRenderManager renderManager = (IEntityRenderManager) Minecraft.getInstance().getRenderManager(); + TextureManager textureManager = Minecraft.getInstance().getTextureManager(); Settings settings = BaritoneAPI.getSettings(); + float[] color = new float[] {1.0F, 1.0F, 1.0F, 255.0F}; + static void glColor(Color color, float alpha) { float[] colorComponents = color.getColorComponents(null); - GlStateManager.color4f(colorComponents[0], colorComponents[1], colorComponents[2], alpha); + IRenderer.color[0] = colorComponents[0]; + IRenderer.color[1] = colorComponents[1]; + IRenderer.color[2] = colorComponents[2]; + IRenderer.color[3] = alpha; } static void startLines(Color color, float alpha, float lineWidth, boolean ignoreDepth) { @@ -54,6 +61,7 @@ public interface IRenderer { if (ignoreDepth) { GlStateManager.disableDepthTest(); } + buffer.begin(GL_LINES, DefaultVertexFormats.POSITION_COLOR); } static void startLines(Color color, float lineWidth, boolean ignoreDepth) { @@ -61,6 +69,7 @@ public interface IRenderer { } static void endLines(boolean ignoredDepth) { + tessellator.draw(); if (ignoredDepth) { GlStateManager.enableDepthTest(); } @@ -70,41 +79,45 @@ public interface IRenderer { GlStateManager.disableBlend(); } - static void drawAABB(AxisAlignedBB aabb) { + static void emitAABB(AxisAlignedBB aabb) { AxisAlignedBB toDraw = aabb.offset(-renderManager.renderPosX(), -renderManager.renderPosY(), -renderManager.renderPosZ()); - buffer.begin(GL_LINES, DefaultVertexFormats.POSITION); // bottom - buffer.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex(); + buffer.pos(toDraw.minX, toDraw.minY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.minY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); // top - buffer.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex(); + buffer.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); // corners - buffer.pos(toDraw.minX, toDraw.minY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).endVertex(); - buffer.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).endVertex(); - tessellator.draw(); + buffer.pos(toDraw.minX, toDraw.minY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.maxY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.minY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.minY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.maxX, toDraw.maxY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.minY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(toDraw.minX, toDraw.maxY, toDraw.maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); } - static void drawAABB(AxisAlignedBB aabb, double expand) { - drawAABB(aabb.grow(expand, expand, expand)); + static void emitAABB(AxisAlignedBB aabb, double expand) { + emitAABB(aabb.grow(expand, expand, expand)); + } + + static void drawAABB(AxisAlignedBB aabb) { + buffer.begin(GL_LINES, DefaultVertexFormats.POSITION_COLOR); + emitAABB(aabb); + tessellator.draw(); } } diff --git a/src/main/java/baritone/utils/InputOverrideHandler.java b/src/main/java/baritone/utils/InputOverrideHandler.java index a043b0ac6..f110b9ce1 100755 --- a/src/main/java/baritone/utils/InputOverrideHandler.java +++ b/src/main/java/baritone/utils/InputOverrideHandler.java @@ -23,7 +23,6 @@ import baritone.api.event.events.TickEvent; import baritone.api.utils.IInputOverrideHandler; import baritone.api.utils.input.Input; import baritone.behavior.Behavior; -import net.minecraft.client.Minecraft; import net.minecraft.util.MovementInputFromOptions; import java.util.HashMap; @@ -100,7 +99,7 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri } } else { if (ctx.player().movementInput.getClass() == PlayerMovementInput.class) { // allow other movement inputs that aren't this one, e.g. for a freecam - ctx.player().movementInput = new MovementInputFromOptions(Minecraft.getInstance().gameSettings); + ctx.player().movementInput = new MovementInputFromOptions(ctx.minecraft().gameSettings); } } // only set it if it was previously incorrect diff --git a/src/main/java/baritone/utils/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index 1572e492b..c2dc6966b 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -22,14 +22,13 @@ import baritone.api.event.events.RenderEvent; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.*; import baritone.api.utils.BetterBlockPos; -import baritone.api.utils.Helper; +import baritone.api.utils.IPlayerContext; import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.behavior.PathingBehavior; import baritone.pathing.path.PathExecutor; import com.mojang.blaze3d.platform.GlStateManager; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.tileentity.BeaconTileEntityRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; @@ -39,6 +38,7 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; import java.awt.*; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -49,7 +49,7 @@ import static org.lwjgl.opengl.GL11.*; * @author Brady * @since 8/9/2018 */ -public final class PathRenderer implements IRenderer, Helper { +public final class PathRenderer implements IRenderer { private static final ResourceLocation TEXTURE_BEACON_BEAM = new ResourceLocation("textures/entity/beacon_beam.png"); @@ -69,31 +69,27 @@ public final class PathRenderer implements IRenderer, Helper { } public static void render(RenderEvent event, PathingBehavior behavior) { - float partialTicks = event.getPartialTicks(); - Goal goal = behavior.getGoal(); - if (Helper.mc.currentScreen instanceof GuiClick) { - ((GuiClick) Helper.mc.currentScreen).onRender(); + final IPlayerContext ctx = behavior.ctx; + if (ctx.world() == null) { + return; + } + if (ctx.minecraft().currentScreen instanceof GuiClick) { + ((GuiClick) ctx.minecraft().currentScreen).onRender(); } - int thisPlayerDimension = behavior.baritone.getPlayerContext().world().getDimension().getType().getId(); - int currentRenderViewDimension = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().world().getDimension().getType().getId(); + final float partialTicks = event.getPartialTicks(); + final Goal goal = behavior.getGoal(); + + final int thisPlayerDimension = ctx.world().getDimension().getType().getId(); + final int currentRenderViewDimension = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().world().getDimension().getType().getId(); if (thisPlayerDimension != currentRenderViewDimension) { // this is a path for a bot in a different dimension, don't render it return; } - Entity renderView = Helper.mc.getRenderViewEntity(); - - if (renderView.world != BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().world()) { - System.out.println("I have no idea what's going on"); - System.out.println("The primary baritone is in a different world than the render view entity"); - System.out.println("Not rendering the path"); - return; - } - if (goal != null && settings.renderGoal.value) { - drawDankLitGoalBox(renderView, goal, partialTicks, settings.colorGoalBox.value); + drawGoal(ctx.player(), goal, partialTicks, settings.colorGoalBox.value); } if (!settings.renderPath.value) { @@ -103,9 +99,9 @@ public final class PathRenderer implements IRenderer, Helper { PathExecutor current = behavior.getCurrent(); // this should prevent most race conditions? PathExecutor next = behavior.getNext(); // like, now it's not possible for current!=null to be true, then suddenly false because of another thread if (current != null && settings.renderSelectionBoxes.value) { - drawManySelectionBoxes(renderView, current.toBreak(), settings.colorBlocksToBreak.value); - drawManySelectionBoxes(renderView, current.toPlace(), settings.colorBlocksToPlace.value); - drawManySelectionBoxes(renderView, current.toWalkInto(), settings.colorBlocksToWalkInto.value); + drawManySelectionBoxes(ctx.player(), current.toBreak(), settings.colorBlocksToBreak.value); + drawManySelectionBoxes(ctx.player(), current.toPlace(), settings.colorBlocksToPlace.value); + drawManySelectionBoxes(ctx.player(), current.toWalkInto(), settings.colorBlocksToWalkInto.value); } //drawManySelectionBoxes(player, Collections.singletonList(behavior.pathStart()), partialTicks, Color.WHITE); @@ -128,12 +124,12 @@ public final class PathRenderer implements IRenderer, Helper { currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> { drawPath(mr, 0, settings.colorMostRecentConsidered.value, settings.fadePath.value, 10, 20); - drawManySelectionBoxes(renderView, Collections.singletonList(mr.getDest()), settings.colorMostRecentConsidered.value); + drawManySelectionBoxes(ctx.player(), Collections.singletonList(mr.getDest()), settings.colorMostRecentConsidered.value); }); }); } - public static void drawPath(IPath path, int startIndex, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0) { + private static void drawPath(IPath path, int startIndex, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0) { IRenderer.startLines(color, settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value); int fadeStart = fadeStart0 + startIndex; @@ -169,29 +165,30 @@ public final class PathRenderer implements IRenderer, Helper { IRenderer.glColor(color, alpha); } - drawLine(start.x, start.y, start.z, end.x, end.y, end.z); - - tessellator.draw(); + emitLine(start.x, start.y, start.z, end.x, end.y, end.z); } IRenderer.endLines(settings.renderPathIgnoreDepth.value); } - - public static void drawLine(double x1, double y1, double z1, double x2, double y2, double z2) { + private static void emitLine(double x1, double y1, double z1, double x2, double y2, double z2) { double vpX = posX(); double vpY = posY(); double vpZ = posZ(); boolean renderPathAsFrickinThingy = !settings.renderPathAsLine.value; - buffer.begin(renderPathAsFrickinThingy ? GL_LINE_STRIP : GL_LINES, DefaultVertexFormats.POSITION); - buffer.pos(x1 + 0.5D - vpX, y1 + 0.5D - vpY, z1 + 0.5D - vpZ).endVertex(); - buffer.pos(x2 + 0.5D - vpX, y2 + 0.5D - vpY, z2 + 0.5D - vpZ).endVertex(); + buffer.pos(x1 + 0.5D - vpX, y1 + 0.5D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(x2 + 0.5D - vpX, y2 + 0.5D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); if (renderPathAsFrickinThingy) { - buffer.pos(x2 + 0.5D - vpX, y2 + 0.53D - vpY, z2 + 0.5D - vpZ).endVertex(); - buffer.pos(x1 + 0.5D - vpX, y1 + 0.53D - vpY, z1 + 0.5D - vpZ).endVertex(); - buffer.pos(x1 + 0.5D - vpX, y1 + 0.5D - vpY, z1 + 0.5D - vpZ).endVertex(); + buffer.pos(x2 + 0.5D - vpX, y2 + 0.5D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(x2 + 0.5D - vpX, y2 + 0.53D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); + + buffer.pos(x2 + 0.5D - vpX, y2 + 0.53D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(x1 + 0.5D - vpX, y1 + 0.53D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); + + buffer.pos(x1 + 0.5D - vpX, y1 + 0.53D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(x1 + 0.5D - vpX, y1 + 0.5D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex(); } } @@ -206,13 +203,17 @@ public final class PathRenderer implements IRenderer, Helper { VoxelShape shape = state.getShape(player.world, pos); AxisAlignedBB toDraw = shape.isEmpty() ? VoxelShapes.fullCube().getBoundingBox() : shape.getBoundingBox(); toDraw = toDraw.offset(pos); - IRenderer.drawAABB(toDraw, .002D); + IRenderer.emitAABB(toDraw, .002D); }); IRenderer.endLines(settings.renderSelectionBoxesIgnoreDepth.value); } - public static void drawDankLitGoalBox(Entity player, Goal goal, float partialTicks, Color color) { + private static void drawGoal(Entity player, Goal goal, float partialTicks, Color color) { + drawGoal(player, goal, partialTicks, color, true); + } + + private static void drawGoal(Entity player, Goal goal, float partialTicks, Color color, boolean setupRender) { double renderPosX = posX(); double renderPosY = posY(); double renderPosZ = posZ(); @@ -244,13 +245,14 @@ public final class PathRenderer implements IRenderer, Helper { y2 -= 0.5; maxY--; } + drawDankLitGoalBox(color, minX, maxX, minZ, maxZ, minY, maxY, y1, y2, setupRender); } else if (goal instanceof GoalXZ) { GoalXZ goalPos = (GoalXZ) goal; if (settings.renderGoalXZBeacon.value) { glPushAttrib(GL_LIGHTING_BIT); - Helper.mc.getTextureManager().bindTexture(TEXTURE_BEACON_BEAM); + textureManager.bindTexture(TEXTURE_BEACON_BEAM); if (settings.renderGoalIgnoreDepth.value) { GlStateManager.disableDepthTest(); } @@ -288,14 +290,22 @@ public final class PathRenderer implements IRenderer, Helper { y2 = 0; minY = 0 - renderPosY; maxY = 256 - renderPosY; + drawDankLitGoalBox(color, minX, maxX, minZ, maxZ, minY, maxY, y1, y2, setupRender); } else if (goal instanceof GoalComposite) { - for (Goal g : ((GoalComposite) goal).goals()) { - drawDankLitGoalBox(player, g, partialTicks, color); + // Simple way to determine if goals can be batched, without having some sort of GoalRenderer + boolean batch = Arrays.stream(((GoalComposite) goal).goals()).allMatch(IGoalRenderPos.class::isInstance); + + if (batch) { + IRenderer.startLines(color, settings.goalRenderLineWidthPixels.value, settings.renderGoalIgnoreDepth.value); + } + for (Goal g : ((GoalComposite) goal).goals()) { + drawGoal(player, g, partialTicks, color, !batch); + } + if (batch) { + IRenderer.endLines(settings.renderGoalIgnoreDepth.value); } - return; } else if (goal instanceof GoalInverted) { - drawDankLitGoalBox(player, ((GoalInverted) goal).origin, partialTicks, settings.colorInvertedGoalBox.value); - return; + drawGoal(player, ((GoalInverted) goal).origin, partialTicks, settings.colorInvertedGoalBox.value); } else if (goal instanceof GoalYLevel) { GoalYLevel goalpos = (GoalYLevel) goal; minX = player.posX - settings.yLevelBoxSize.value - renderPosX; @@ -306,38 +316,45 @@ public final class PathRenderer implements IRenderer, Helper { maxY = minY + 2; y1 = 1 + y + goalpos.level - renderPosY; y2 = 1 - y + goalpos.level - renderPosY; - } else { - return; + drawDankLitGoalBox(color, minX, maxX, minZ, maxZ, minY, maxY, y1, y2, setupRender); } + } - IRenderer.startLines(color, settings.goalRenderLineWidthPixels.value, settings.renderGoalIgnoreDepth.value); + private static void drawDankLitGoalBox(Color colorIn, double minX, double maxX, double minZ, double maxZ, double minY, double maxY, double y1, double y2, boolean setupRender) { + if (setupRender) { + IRenderer.startLines(colorIn, settings.goalRenderLineWidthPixels.value, settings.renderGoalIgnoreDepth.value); + } renderHorizontalQuad(minX, maxX, minZ, maxZ, y1); renderHorizontalQuad(minX, maxX, minZ, maxZ, y2); + buffer.pos(minX, minY, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(minX, maxY, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(maxX, minY, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(maxX, maxY, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(maxX, minY, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(maxX, maxY, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(minX, minY, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(minX, maxY, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); - buffer.begin(GL_LINES, DefaultVertexFormats.POSITION); - buffer.pos(minX, minY, minZ).endVertex(); - buffer.pos(minX, maxY, minZ).endVertex(); - buffer.pos(maxX, minY, minZ).endVertex(); - buffer.pos(maxX, maxY, minZ).endVertex(); - buffer.pos(maxX, minY, maxZ).endVertex(); - buffer.pos(maxX, maxY, maxZ).endVertex(); - buffer.pos(minX, minY, maxZ).endVertex(); - buffer.pos(minX, maxY, maxZ).endVertex(); - tessellator.draw(); - - IRenderer.endLines(settings.renderGoalIgnoreDepth.value); + if (setupRender) { + IRenderer.endLines(settings.renderGoalIgnoreDepth.value); + } } private static void renderHorizontalQuad(double minX, double maxX, double minZ, double maxZ, double y) { if (y != 0) { - buffer.begin(GL_LINE_LOOP, DefaultVertexFormats.POSITION); - buffer.pos(minX, y, minZ).endVertex(); - buffer.pos(maxX, y, minZ).endVertex(); - buffer.pos(maxX, y, maxZ).endVertex(); - buffer.pos(minX, y, maxZ).endVertex(); - tessellator.draw(); + buffer.pos(minX, y, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(maxX, y, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + + buffer.pos(maxX, y, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(maxX, y, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + + buffer.pos(maxX, y, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(minX, y, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + + buffer.pos(minX, y, maxZ).color(color[0], color[1], color[2], color[3]).endVertex(); + buffer.pos(minX, y, minZ).color(color[0], color[1], color[2], color[3]).endVertex(); } } } diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index a83e53a1e..236e41cc6 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -160,7 +160,7 @@ public class PathingControlManager implements IPathingControlManager { if (newGoal.isInGoal(current.getPath().getDest())) { return false; } - return !newGoal.toString().equals(current.getPath().getGoal().toString()); + return !newGoal.equals(current.getPath().getGoal()); } return false; } diff --git a/src/main/java/baritone/utils/accessor/IBitArray.java b/src/main/java/baritone/utils/accessor/IBitArray.java index baea5c1da..15f5f7c36 100644 --- a/src/main/java/baritone/utils/accessor/IBitArray.java +++ b/src/main/java/baritone/utils/accessor/IBitArray.java @@ -3,4 +3,6 @@ package baritone.utils.accessor; public interface IBitArray { int[] toArray(); + + long getMaxEntryValue(); } diff --git a/src/main/java/baritone/utils/accessor/IBlockStateContainer.java b/src/main/java/baritone/utils/accessor/IBlockStateContainer.java index 1ca642ae3..ea951ca2b 100644 --- a/src/main/java/baritone/utils/accessor/IBlockStateContainer.java +++ b/src/main/java/baritone/utils/accessor/IBlockStateContainer.java @@ -17,11 +17,16 @@ package baritone.utils.accessor; -import net.minecraft.block.BlockState; +import net.minecraft.util.BitArray; +import net.minecraft.world.chunk.IBlockStatePalette; -public interface IBlockStateContainer { +public interface IBlockStateContainer { - BlockState getAtPalette(int index); + IBlockStatePalette getPalette(); + + BitArray getStorage(); + + T getAtPalette(int index); int[] storageArray(); } diff --git a/src/main/java/baritone/utils/player/PrimaryPlayerContext.java b/src/main/java/baritone/utils/player/BaritonePlayerContext.java similarity index 55% rename from src/main/java/baritone/utils/player/PrimaryPlayerContext.java rename to src/main/java/baritone/utils/player/BaritonePlayerContext.java index c1bfb3948..f72f87e85 100644 --- a/src/main/java/baritone/utils/player/PrimaryPlayerContext.java +++ b/src/main/java/baritone/utils/player/BaritonePlayerContext.java @@ -17,13 +17,13 @@ package baritone.utils.player; -import baritone.api.BaritoneAPI; +import baritone.Baritone; import baritone.api.cache.IWorldData; -import baritone.api.utils.Helper; -import baritone.api.utils.IPlayerContext; -import baritone.api.utils.IPlayerController; -import baritone.api.utils.RayTraceUtils; +import baritone.api.utils.*; import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; @@ -33,28 +33,52 @@ import net.minecraft.world.World; * @author Brady * @since 11/12/2018 */ -public enum PrimaryPlayerContext implements IPlayerContext, Helper { +public final class BaritonePlayerContext implements IPlayerContext { - INSTANCE; + private final Baritone baritone; + private final Minecraft mc; + private final IPlayerController playerController; + + public BaritonePlayerContext(Baritone baritone, Minecraft mc) { + this.baritone = baritone; + this.mc = mc; + this.playerController = new BaritonePlayerController(mc); + } + + @Override + public Minecraft minecraft() { + return this.mc; + } @Override public ClientPlayerEntity player() { - return mc.player; + return this.mc.player; } @Override public IPlayerController playerController() { - return PrimaryPlayerController.INSTANCE; + return this.playerController; } @Override public World world() { - return mc.world; + return this.mc.world; } @Override public IWorldData worldData() { - return BaritoneAPI.getProvider().getPrimaryBaritone().getWorldProvider().getCurrentWorld(); + return this.baritone.getWorldProvider().getCurrentWorld(); + } + + @Override + public BetterBlockPos viewerPos() { + final Entity entity = this.mc.getRenderViewEntity(); + return entity == null ? this.playerFeet() : BetterBlockPos.from(new BlockPos(entity)); + } + + @Override + public Rotation playerRotations() { + return this.baritone.getLookBehavior().getEffectiveRotation().orElseGet(IPlayerContext.super::playerRotations); } @Override diff --git a/src/main/java/baritone/utils/player/PrimaryPlayerController.java b/src/main/java/baritone/utils/player/BaritonePlayerController.java similarity index 93% rename from src/main/java/baritone/utils/player/PrimaryPlayerController.java rename to src/main/java/baritone/utils/player/BaritonePlayerController.java index d3b53c54e..dea27b022 100644 --- a/src/main/java/baritone/utils/player/PrimaryPlayerController.java +++ b/src/main/java/baritone/utils/player/BaritonePlayerController.java @@ -17,9 +17,9 @@ package baritone.utils.player; -import baritone.api.utils.Helper; import baritone.api.utils.IPlayerController; import baritone.utils.accessor.IPlayerControllerMP; +import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.player.PlayerEntity; @@ -40,9 +40,13 @@ import net.minecraft.world.World; * @author Brady * @since 12/14/2018 */ -public enum PrimaryPlayerController implements IPlayerController, Helper { +public final class BaritonePlayerController implements IPlayerController { - INSTANCE; + private final Minecraft mc; + + public BaritonePlayerController(Minecraft mc) { + this.mc = mc; + } @Override public void syncHeldItem() {