diff --git a/README.md b/README.md index 19ec0e879..043aed085 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ ![Lines of Code](https://tokei.rs/b1/github/cabaletta/baritone?category=code) [![GitHub contributors](https://img.shields.io/github/contributors/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/graphs/contributors/) [![GitHub commits](https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg)](https://github.com/cabaletta/baritone/commit/) -[![Impact integration](https://img.shields.io/badge/Impact%20integration-v1.2.8%20/%20v1.3.4%20/%20v1.4.1-brightgreen.svg)](https://impactclient.net/) +[![Impact integration](https://img.shields.io/badge/Impact%20integration-v1.2.10%20/%20v1.3.5%20/%20v1.4.3-brightgreen.svg)](https://impactclient.net/) [![ForgeHax integration](https://img.shields.io/badge/ForgeHax%20%22integration%22-scuffed-yellow.svg)](https://github.com/fr1kin/ForgeHax/) [![Aristois add-on integration](https://img.shields.io/badge/Aristois%20add--on%20integration-v1.3.4%20/%20v1.4.1-green.svg)](https://gitlab.com/emc-mods-indrit/baritone_api) [![WWE integration](https://img.shields.io/badge/WWE%20%22integration%22-master%3F-green.svg)](https://wweclient.com/) diff --git a/USAGE.md b/USAGE.md index 25fef11e8..0f911efaa 100644 --- a/USAGE.md +++ b/USAGE.md @@ -8,11 +8,23 @@ Baritone commands can also by default be typed in the chatbox. However if you ma To disable direct chat control (with no prefix), turn off the `chatControl` setting. To disable chat control with the `#` prefix, turn off the `prefixControl` setting. In Impact, `.b` cannot be disabled. Be careful that you don't leave yourself with all control methods disabled (if you do, reset your settings by deleting the file `minecraft/baritone/settings.txt` and relaunching). +# For Baritone 1.2.10+, 1.3.5+, 1.4.2+ + +Lots of the commands have changed, BUT `#help` is improved vastly (its clickable! commands have tab completion! oh my!). + +Try `#help` I promise it won't just send you back here =) + +"wtf where is cleararea" -> look at `#help sel` + +"wtf where is goto death, goto waypoint" -> look at `#help wp` (a "tag" is like "home" (created automatically on right clicking a bed) or "death" (created automatically on death) or "user" (has to be created manually)). So you might want `#wp save user coolbiome` then, to set the goal `#wp goal coolbiome` then `#path` to path to it. For death, `#wp goal death` (remember stuff is clickable!). + +just look at `#help` lmao + # Commands **All** of these commands may need a prefix before them, as above ^. -`help` for (rudimentary) help. You can see what it says [here](https://github.com/cabaletta/baritone/blob/master/src/api/java/baritone/api/utils/ExampleBaritoneControl.java#L47). +`help` To toggle a boolean setting, just say its name in chat (for example saying `allowBreak` toggles whether Baritone will consider breaking blocks). For a numeric setting, say its name then the new value (like `primaryTimeoutMS 250`). It's case insensitive. To reset a setting to its default value, say `acceptableThrowawayItems reset`. To reset all settings, say `reset`. To see all settings that have been modified from their default values, say `modified`. @@ -38,12 +50,6 @@ Some common examples: - `version` to get the version of Baritone you're running - `damn` daniel - -New commands: -- `sel` to manage selections -- some others - - For the rest of the commands, you can take a look at the code [here](https://github.com/cabaletta/baritone/blob/master/src/api/java/baritone/api/utils/ExampleBaritoneControl.java). All the settings and documentation are here. If you find HTML easier to read than Javadoc, you can look here. diff --git a/build.gradle b/build.gradle index f3844ab91..c74538e35 100755 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,6 @@ version '1.4.3' buildscript { repositories { - jcenter() maven { name = 'forge' url = 'http://files.minecraftforge.net/maven' @@ -29,6 +28,7 @@ buildscript { name = 'impactdevelopment-repo' url = 'https://impactdevelopment.github.io/maven/' } + jcenter() } dependencies { diff --git a/src/api/java/baritone/api/IBaritoneProvider.java b/src/api/java/baritone/api/IBaritoneProvider.java index d6e3d93ba..697f25dc6 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 net.minecraft.client.entity.player.ClientPlayerEntity; +import baritone.api.schematic.ISchematicSystem; import java.util.List; import java.util.Objects; @@ -82,4 +83,9 @@ public interface IBaritoneProvider { * @return The {@link ICommandSystem} instance. */ ICommandSystem getCommandSystem(); + + /** + * @return The {@link ISchematicSystem} instance. + */ + ISchematicSystem getSchematicSystem(); } diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index b6a8770f0..7fb9c53b9 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -181,6 +181,20 @@ public final class Settings { Blocks.TRAPPED_CHEST ))); + /** + * A list of blocks to be treated as if they're air. + *

+ * If a schematic asks for air at a certain position, and that position currently contains a block on this list, it will be treated as correct. + */ + public final Setting> buildIgnoreBlocks = new Setting<>(new ArrayList<>(Arrays.asList( + + ))); + + /** + * If this is true, the builder will treat all non-air blocks as correct. It will only place new blocks. + */ + public final Setting buildIgnoreExisting = new Setting<>(false); + /** * If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block. *

@@ -231,7 +245,7 @@ public final class Settings { /** * If we overshoot a traverse and end up one block beyond the destination, mark it as successful anyway. *

- * This helps with speed at >=20m/s + * This helps with speed exceeding 20m/s */ public final Setting overshootTraverse = new Setting<>(true); @@ -250,6 +264,11 @@ public final class Settings { */ public final Setting randomLooking113 = new Setting<>(2d); + /** + * Block reach distance + */ + public final Setting blockReachDistance = new Setting<>(4.5f); + /** * How many degrees to randomize the pitch and yaw every tick. Set to 0 to disable */ @@ -740,6 +759,11 @@ public final class Settings { */ public final Setting buildRepeat = new Setting<>(new Vec3i(0, 0, 0)); + /** + * How many times to buildrepeat. -1 for infinite. + */ + public final Setting buildRepeatCount = new Setting<>(-1); + /** * Allow standing above a block while mining it, in BuilderProcess *

@@ -789,6 +813,12 @@ public final class Settings { */ public final Setting schematicOrientationZ = new Setting<>(false); + /** + * The fallback used by the build command when no extension is specified. This may be useful if schematics of a + * particular format are used often, and the user does not wish to have to specify the extension with every usage. + */ + public final Setting schematicFallbackExtension = new Setting<>("schematic"); + /** * Distance to scan every tick for updates. Expanding this beyond player reach distance (i.e. setting it to 6 or above) * is only necessary in very large schematics where rescanning the whole thing is costly. diff --git a/src/api/java/baritone/api/cache/ICachedWorld.java b/src/api/java/baritone/api/cache/ICachedWorld.java index 837ae076c..e681ce51c 100644 --- a/src/api/java/baritone/api/cache/ICachedWorld.java +++ b/src/api/java/baritone/api/cache/ICachedWorld.java @@ -81,6 +81,4 @@ public interface ICachedWorld { * in a new thread by default. */ void save(); - - } diff --git a/src/api/java/baritone/api/cache/IWorldScanner.java b/src/api/java/baritone/api/cache/IWorldScanner.java index 325d4bd0e..224f64c76 100644 --- a/src/api/java/baritone/api/cache/IWorldScanner.java +++ b/src/api/java/baritone/api/cache/IWorldScanner.java @@ -77,10 +77,20 @@ public interface IWorldScanner { } /** - * Repacks 40 chunks around the player. + * Overload of {@link #repack(IPlayerContext, int)} where the value of the {@code range} parameter is {@code 40}. * - * @param ctx The player context for that player. - * @return The number of chunks queued for repacking. + * @param ctx The player, describing the origin + * @return The amount of chunks successfully queued for repacking */ int repack(IPlayerContext ctx); + + /** + * Queues the chunks in a square formation around the specified player, using the specified + * range, which represents 1/2 the square's dimensions, where the player is in the center. + * + * @param ctx The player, describing the origin + * @param range The range to repack + * @return The amount of chunks successfully queued for repacking + */ + int repack(IPlayerContext ctx, int range); } diff --git a/src/api/java/baritone/api/command/datatypes/RelativeGoal.java b/src/api/java/baritone/api/command/datatypes/RelativeGoal.java index cda0ad665..19312907e 100644 --- a/src/api/java/baritone/api/command/datatypes/RelativeGoal.java +++ b/src/api/java/baritone/api/command/datatypes/RelativeGoal.java @@ -38,38 +38,26 @@ public enum RelativeGoal implements IDatatypePost { if (origin == null) { origin = BetterBlockPos.ORIGIN; } + final IArgConsumer consumer = ctx.getConsumer(); - List> coords = new ArrayList<>(); - final IArgConsumer copy = consumer.copy(); // This is a hack and should be fixed in the future probably - for (int i = 0; i < 3; i++) { - if (copy.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) { - coords.add(o -> consumer.getDatatypePost(RelativeCoordinate.INSTANCE, o)); - copy.get(); // Consume so we actually decrement the remaining arguments - } + GoalBlock goalBlock = consumer.peekDatatypePostOrNull(RelativeGoalBlock.INSTANCE, origin); + if (goalBlock != null) { + return goalBlock; } - switch (coords.size()) { - case 0: - return new GoalBlock(origin); - case 1: - return new GoalYLevel( - MathHelper.floor(coords.get(0).apply((double) origin.y)) - ); - case 2: - return new GoalXZ( - MathHelper.floor(coords.get(0).apply((double) origin.x)), - MathHelper.floor(coords.get(1).apply((double) origin.z)) - ); - case 3: - return new GoalBlock( - MathHelper.floor(coords.get(0).apply((double) origin.x)), - MathHelper.floor(coords.get(1).apply((double) origin.y)), - MathHelper.floor(coords.get(2).apply((double) origin.z)) - ); - default: - throw new IllegalStateException("Unexpected coords size: " + coords.size()); + GoalXZ goalXZ = consumer.peekDatatypePostOrNull(RelativeGoalXZ.INSTANCE, origin); + if (goalXZ != null) { + return goalXZ; } + + GoalYLevel goalYLevel = consumer.peekDatatypePostOrNull(RelativeGoalYLevel.INSTANCE, origin); + if (goalYLevel != null) { + return goalYLevel; + } + + // when the user doesn't input anything, default to the origin + return new GoalBlock(origin); } @Override diff --git a/src/api/java/baritone/api/command/exception/CommandErrorMessageException.java b/src/api/java/baritone/api/command/exception/CommandErrorMessageException.java index 4a21bede7..b31615163 100644 --- a/src/api/java/baritone/api/command/exception/CommandErrorMessageException.java +++ b/src/api/java/baritone/api/command/exception/CommandErrorMessageException.java @@ -22,4 +22,8 @@ public abstract class CommandErrorMessageException extends CommandException { protected CommandErrorMessageException(String reason) { super(reason); } + + protected CommandErrorMessageException(String reason, Throwable cause) { + super(reason, cause); + } } diff --git a/src/api/java/baritone/api/command/exception/CommandException.java b/src/api/java/baritone/api/command/exception/CommandException.java index b8962c159..53b8e6023 100644 --- a/src/api/java/baritone/api/command/exception/CommandException.java +++ b/src/api/java/baritone/api/command/exception/CommandException.java @@ -22,4 +22,8 @@ public abstract class CommandException extends Exception implements ICommandExce protected CommandException(String reason) { super(reason); } + + protected CommandException(String reason, Throwable cause) { + super(reason, cause); + } } diff --git a/src/api/java/baritone/api/command/exception/CommandInvalidArgumentException.java b/src/api/java/baritone/api/command/exception/CommandInvalidArgumentException.java index 1902d7355..6997d6d69 100644 --- a/src/api/java/baritone/api/command/exception/CommandInvalidArgumentException.java +++ b/src/api/java/baritone/api/command/exception/CommandInvalidArgumentException.java @@ -23,12 +23,21 @@ public abstract class CommandInvalidArgumentException extends CommandErrorMessag public final ICommandArgument arg; - protected CommandInvalidArgumentException(ICommandArgument arg, String reason) { - super(String.format( - "Error at argument #%s: %s", - arg.getIndex() == -1 ? "" : Integer.toString(arg.getIndex() + 1), - reason - )); + protected CommandInvalidArgumentException(ICommandArgument arg, String message) { + super(formatMessage(arg, message)); this.arg = arg; } + + protected CommandInvalidArgumentException(ICommandArgument arg, String message, Throwable cause) { + super(formatMessage(arg, message), cause); + this.arg = arg; + } + + private static String formatMessage(ICommandArgument arg, String message) { + return String.format( + "Error at argument #%s: %s", + arg.getIndex() == -1 ? "" : Integer.toString(arg.getIndex() + 1), + message + ); + } } diff --git a/src/api/java/baritone/api/command/exception/CommandInvalidTypeException.java b/src/api/java/baritone/api/command/exception/CommandInvalidTypeException.java index 516fd308f..06658c3a0 100644 --- a/src/api/java/baritone/api/command/exception/CommandInvalidTypeException.java +++ b/src/api/java/baritone/api/command/exception/CommandInvalidTypeException.java @@ -26,7 +26,7 @@ public class CommandInvalidTypeException extends CommandInvalidArgumentException } public CommandInvalidTypeException(ICommandArgument arg, String expected, Throwable cause) { - super(arg, String.format("Expected %s.\nMore details: %s", expected, cause.getMessage())); + super(arg, String.format("Expected %s", expected), cause); } public CommandInvalidTypeException(ICommandArgument arg, String expected, String got) { @@ -34,6 +34,6 @@ public class CommandInvalidTypeException extends CommandInvalidArgumentException } public CommandInvalidTypeException(ICommandArgument arg, String expected, String got, Throwable cause) { - super(arg, String.format("Expected %s, but got %s instead.\nMore details: %s", expected, got, cause.getMessage())); + super(arg, String.format("Expected %s, but got %s instead", expected, got), cause); } } diff --git a/src/api/java/baritone/api/command/exception/CommandUnhandledException.java b/src/api/java/baritone/api/command/exception/CommandUnhandledException.java index fe0b09fad..02987d4ee 100644 --- a/src/api/java/baritone/api/command/exception/CommandUnhandledException.java +++ b/src/api/java/baritone/api/command/exception/CommandUnhandledException.java @@ -37,7 +37,7 @@ public class CommandUnhandledException extends RuntimeException implements IComm @Override public void handle(ICommand command, List args) { - HELPER.logDirect("An unhandled exception occurred." + + HELPER.logDirect("An unhandled exception occurred. " + "The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues", TextFormatting.RED); diff --git a/src/api/java/baritone/api/event/events/TickEvent.java b/src/api/java/baritone/api/event/events/TickEvent.java index da8f8878a..5c484ae49 100644 --- a/src/api/java/baritone/api/event/events/TickEvent.java +++ b/src/api/java/baritone/api/event/events/TickEvent.java @@ -19,22 +19,20 @@ package baritone.api.event.events; import baritone.api.event.events.type.EventState; +import java.util.function.BiFunction; + public final class TickEvent { + private static int overallTickCount; + private final EventState state; private final Type type; private final int count; - private static int overallTickCount; - - public TickEvent(EventState state, Type type) { + public TickEvent(EventState state, Type type, int count) { this.state = state; this.type = type; - this.count = incrementCount(); - } - - private static synchronized int incrementCount() { - return overallTickCount++; + this.count = count; } public int getCount() { @@ -49,6 +47,10 @@ public final class TickEvent { return state; } + public static synchronized BiFunction createNextProvider() { + final int count = overallTickCount++; + return (state, type) -> new TickEvent(state, type, count); + } public enum Type { /** diff --git a/src/api/java/baritone/api/schematic/AbstractSchematic.java b/src/api/java/baritone/api/schematic/AbstractSchematic.java index 3cd14747d..cca6bc966 100644 --- a/src/api/java/baritone/api/schematic/AbstractSchematic.java +++ b/src/api/java/baritone/api/schematic/AbstractSchematic.java @@ -23,6 +23,10 @@ public abstract class AbstractSchematic implements ISchematic { protected int y; protected int z; + public AbstractSchematic() { + this(0, 0, 0); + } + public AbstractSchematic(int x, int y, int z) { this.x = x; this.y = y; diff --git a/src/api/java/baritone/api/schematic/FillSchematic.java b/src/api/java/baritone/api/schematic/FillSchematic.java index 2adcbbfc0..e43ddb93c 100644 --- a/src/api/java/baritone/api/schematic/FillSchematic.java +++ b/src/api/java/baritone/api/schematic/FillSchematic.java @@ -32,6 +32,10 @@ public class FillSchematic extends AbstractSchematic { this.bom = bom; } + public FillSchematic(int x, int y, int z, BlockState state) { + this(x, y, z, new BlockOptionalMeta(state.getBlock())); + } + public BlockOptionalMeta getBom() { return bom; } diff --git a/src/api/java/baritone/api/schematic/ISchematicSystem.java b/src/api/java/baritone/api/schematic/ISchematicSystem.java new file mode 100644 index 000000000..c8f039070 --- /dev/null +++ b/src/api/java/baritone/api/schematic/ISchematicSystem.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; + +import baritone.api.command.registry.Registry; +import baritone.api.schematic.format.ISchematicFormat; + +import java.io.File; +import java.util.Optional; + +/** + * @author Brady + * @since 12/23/2019 + */ +public interface ISchematicSystem { + + /** + * @return The registry of supported schematic formats + */ + Registry getRegistry(); + + /** + * Attempts to find an {@link ISchematicFormat} that supports the specified schematic file. + * + * @param file A schematic file + * @return The corresponding format for the file, {@link Optional#empty()} if no candidates were found. + */ + Optional getByFile(File file); +} diff --git a/src/api/java/baritone/api/schematic/IStaticSchematic.java b/src/api/java/baritone/api/schematic/IStaticSchematic.java new file mode 100644 index 000000000..e0872ede3 --- /dev/null +++ b/src/api/java/baritone/api/schematic/IStaticSchematic.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; + +import net.minecraft.block.BlockState; + +/** + * A static schematic is capable of providing the desired state at a given position without + * additional context. Schematics of this type are expected to have non-varying contents. + * + * @see #getDirect(int, int, int) + * + * @author Brady + * @since 12/24/2019 + */ +public interface IStaticSchematic extends ISchematic { + + /** + * Gets the {@link BlockState} for a given position in this schematic. It should be guaranteed + * that the return value of this method will not change given that the parameters are the same. + * + * @param x The X block position + * @param y The Y block position + * @param z The Z block position + * @return The desired state at the specified position. + */ + BlockState getDirect(int x, int y, int z); + + /** + * Returns an {@link BlockState} array of size {@link #heightY()} which contains all + * desired block states in the specified vertical column. The index of {@link BlockState}s + * in the array are equivalent to their Y position in the schematic. + * + * @param x The X column position + * @param z The Z column position + * @return An {@link BlockState} array + */ + default BlockState[] getColumn(int x, int z) { + BlockState[] column = new BlockState[this.heightY()]; + for (int i = 0; i < this.heightY(); i++) { + column[i] = getDirect(x, i, z); + } + return column; + } +} diff --git a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java new file mode 100644 index 000000000..3fe045bcf --- /dev/null +++ b/src/api/java/baritone/api/schematic/format/ISchematicFormat.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.schematic.format; + +import baritone.api.schematic.ISchematic; +import baritone.api.schematic.IStaticSchematic; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * The base of a {@link ISchematic} file format + * + * @author Brady + * @since 12/23/2019 + */ +public interface ISchematicFormat { + + /** + * @return The parser for creating schematics of this format + */ + IStaticSchematic parse(InputStream input) throws IOException; + + /** + * @param file The file to check against + * @return Whether or not the specified file matches this schematic format + */ + boolean isFileType(File file); +} diff --git a/src/api/java/baritone/api/utils/BlockOptionalMeta.java b/src/api/java/baritone/api/utils/BlockOptionalMeta.java index 85408ac95..a1b38cca1 100644 --- a/src/api/java/baritone/api/utils/BlockOptionalMeta.java +++ b/src/api/java/baritone/api/utils/BlockOptionalMeta.java @@ -24,9 +24,6 @@ import net.minecraft.block.*; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.resources.*; -import net.minecraft.state.IProperty; -import net.minecraft.state.properties.*; -import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Unit; import net.minecraft.util.math.BlockPos; @@ -36,7 +33,6 @@ import net.minecraft.world.storage.loot.*; import javax.annotation.Nonnull; import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,7 +45,6 @@ public final class BlockOptionalMeta { private final ImmutableSet stateHashes; private final ImmutableSet stackHashes; private static final Pattern pattern = Pattern.compile("^(.+?)(?::(\\d+))?$"); - private static final Map normalizations; private static LootTableManager manager; private static Map> drops = new HashMap<>(); @@ -81,142 +76,6 @@ public final class BlockOptionalMeta { stackHashes = getStackHashes(blockstates); } - static { - Map _normalizations = new HashMap<>(); - Consumer put = instance -> _normalizations.put(instance.getClass(), instance); - put.accept(Direction.NORTH); - put.accept(Direction.Axis.Y); - put.accept(Half.BOTTOM); - put.accept(StairsShape.STRAIGHT); - put.accept(AttachFace.FLOOR); - put.accept(DoubleBlockHalf.UPPER); - put.accept(SlabType.BOTTOM); - put.accept(DoorHingeSide.LEFT); - put.accept(BedPart.HEAD); - put.accept(RailShape.NORTH_SOUTH); - _normalizations.put(BannerBlock.ROTATION, 0); - _normalizations.put(BedBlock.OCCUPIED, false); - _normalizations.put(BrewingStandBlock.HAS_BOTTLE[0], false); - _normalizations.put(BrewingStandBlock.HAS_BOTTLE[1], false); - _normalizations.put(BrewingStandBlock.HAS_BOTTLE[2], false); - _normalizations.put(AbstractButtonBlock.POWERED, false); - // _normalizations.put(BlockCactus.AGE, 0); - // _normalizations.put(BlockCauldron.LEVEL, 0); - // _normalizations.put(BlockChorusFlower.AGE, 0); - _normalizations.put(ChorusPlantBlock.NORTH, false); - _normalizations.put(ChorusPlantBlock.EAST, false); - _normalizations.put(ChorusPlantBlock.SOUTH, false); - _normalizations.put(ChorusPlantBlock.WEST, false); - _normalizations.put(ChorusPlantBlock.UP, false); - _normalizations.put(ChorusPlantBlock.DOWN, false); - // _normalizations.put(BlockCocoa.AGE, 0); - // _normalizations.put(BlockCrops.AGE, 0); - _normalizations.put(SnowyDirtBlock.SNOWY, false); - _normalizations.put(DoorBlock.OPEN, false); - _normalizations.put(DoorBlock.POWERED, false); - // _normalizations.put(BlockFarmland.MOISTURE, 0); - _normalizations.put(FenceBlock.NORTH, false); - _normalizations.put(FenceBlock.EAST, false); - _normalizations.put(FenceBlock.WEST, false); - _normalizations.put(FenceBlock.SOUTH, false); - // _normalizations.put(BlockFenceGate.POWERED, false); - // _normalizations.put(BlockFenceGate.IN_WALL, false); - _normalizations.put(FireBlock.AGE, 0); - _normalizations.put(FireBlock.NORTH, false); - _normalizations.put(FireBlock.EAST, false); - _normalizations.put(FireBlock.SOUTH, false); - _normalizations.put(FireBlock.WEST, false); - _normalizations.put(FireBlock.UP, false); - // _normalizations.put(BlockFrostedIce.AGE, 0); - _normalizations.put(GrassBlock.SNOWY, false); - // _normalizations.put(BlockHopper.ENABLED, true); - // _normalizations.put(BlockLever.POWERED, false); - // _normalizations.put(BlockLiquid.LEVEL, 0); - // _normalizations.put(BlockMycelium.SNOWY, false); - // _normalizations.put(BlockNetherWart.AGE, false); - _normalizations.put(LeavesBlock.DISTANCE, false); - // _normalizations.put(BlockLeaves.DECAYABLE, false); - // _normalizations.put(BlockObserver.POWERED, false); - _normalizations.put(PaneBlock.NORTH, false); - _normalizations.put(PaneBlock.EAST, false); - _normalizations.put(PaneBlock.WEST, false); - _normalizations.put(PaneBlock.SOUTH, false); - // _normalizations.put(BlockPistonBase.EXTENDED, false); - // _normalizations.put(BlockPressurePlate.POWERED, false); - // _normalizations.put(BlockPressurePlateWeighted.POWER, false); - // _normalizations.put(BlockRailDetector.POWERED, false); - // _normalizations.put(BlockRailPowered.POWERED, false); - _normalizations.put(RedstoneWireBlock.NORTH, false); - _normalizations.put(RedstoneWireBlock.EAST, false); - _normalizations.put(RedstoneWireBlock.SOUTH, false); - _normalizations.put(RedstoneWireBlock.WEST, false); - // _normalizations.put(BlockReed.AGE, false); - _normalizations.put(SaplingBlock.STAGE, 0); - _normalizations.put(StandingSignBlock.ROTATION, 0); - _normalizations.put(StemBlock.AGE, 0); - _normalizations.put(TripWireBlock.NORTH, false); - _normalizations.put(TripWireBlock.EAST, false); - _normalizations.put(TripWireBlock.WEST, false); - _normalizations.put(TripWireBlock.SOUTH, false); - _normalizations.put(VineBlock.NORTH, false); - _normalizations.put(VineBlock.EAST, false); - _normalizations.put(VineBlock.SOUTH, false); - _normalizations.put(VineBlock.WEST, false); - _normalizations.put(VineBlock.UP, false); - _normalizations.put(WallBlock.UP, false); - _normalizations.put(WallBlock.NORTH, false); - _normalizations.put(WallBlock.EAST, false); - _normalizations.put(WallBlock.WEST, false); - _normalizations.put(WallBlock.SOUTH, false); - normalizations = Collections.unmodifiableMap(_normalizations); - } - - private static , P extends IProperty> P castToIProperty(Object value) { - //noinspection unchecked - return (P) value; - } - - private static , P extends IProperty> C castToIPropertyValue(P iproperty, Object value) { - //noinspection unchecked - return (C) value; - } - - public static BlockState normalize(BlockState state) { - BlockState newState = state; - - for (IProperty property : state.getProperties()) { - Class valueClass = property.getValueClass(); - if (normalizations.containsKey(property)) { - try { - newState = newState.with( - castToIProperty(property), - castToIPropertyValue(property, normalizations.get(property)) - ); - } catch (IllegalArgumentException ignored) {} - } else if (normalizations.containsKey(state.get(property))) { - try { - newState = newState.with( - castToIProperty(property), - castToIPropertyValue(property, normalizations.get(state.get(property))) - ); - } catch (IllegalArgumentException ignored) {} - } else if (normalizations.containsKey(valueClass)) { - try { - newState = newState.with( - castToIProperty(property), - castToIPropertyValue(property, normalizations.get(valueClass)) - ); - } catch (IllegalArgumentException ignored) {} - } - } - - return newState; - } - - public static int stateMeta(BlockState state) { - return state.hashCode(); - } - private static Set getStates(@Nonnull Block block) { return new HashSet<>(block.getStateContainer().getValidStates()); } diff --git a/src/api/java/baritone/api/utils/IPlayerController.java b/src/api/java/baritone/api/utils/IPlayerController.java index 91f71f51d..06e031327 100644 --- a/src/api/java/baritone/api/utils/IPlayerController.java +++ b/src/api/java/baritone/api/utils/IPlayerController.java @@ -20,6 +20,7 @@ package baritone.api.utils; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.ClickType; +import baritone.api.BaritoneAPI; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; @@ -56,6 +57,6 @@ public interface IPlayerController { void setHittingBlock(boolean hittingBlock); default double getBlockReachDistance() { - return this.getGameType().isCreative() ? 5.0F : 4.5F; + return this.getGameType().isCreative() ? 5.0F : BaritoneAPI.getSettings().blockReachDistance.value; } } diff --git a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java index 477687554..12f64bf21 100644 --- a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java +++ b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java @@ -41,6 +41,8 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.util.function.BiFunction; + /** * @author Brady * @since 7/31/2018 @@ -84,13 +86,15 @@ public class MixinMinecraft { ) ) private void runTick(CallbackInfo ci) { - for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) { + final BiFunction tickProvider = TickEvent.createNextProvider(); - TickEvent.Type type = ibaritone.getPlayerContext().player() != null && ibaritone.getPlayerContext().world() != null + for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) { + + TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null ? TickEvent.Type.IN : TickEvent.Type.OUT; - ibaritone.getGameEventHandler().onTick(new TickEvent(EventState.PRE, type)); + baritone.getGameEventHandler().onTick(tickProvider.apply(EventState.PRE, type)); } } diff --git a/src/main/java/baritone/BaritoneProvider.java b/src/main/java/baritone/BaritoneProvider.java index cb24dfe21..84034ef33 100644 --- a/src/main/java/baritone/BaritoneProvider.java +++ b/src/main/java/baritone/BaritoneProvider.java @@ -21,9 +21,11 @@ import baritone.api.IBaritone; import baritone.api.IBaritoneProvider; import baritone.api.cache.IWorldScanner; import baritone.api.command.ICommandSystem; +import baritone.api.schematic.ISchematicSystem; import baritone.command.BaritoneChatControl; import baritone.cache.WorldScanner; import baritone.command.CommandSystem; +import baritone.utils.schematic.SchematicSystem; import java.util.Collections; import java.util.List; @@ -64,4 +66,9 @@ public final class BaritoneProvider implements IBaritoneProvider { public ICommandSystem getCommandSystem() { return CommandSystem.INSTANCE; } + + @Override + public ISchematicSystem getSchematicSystem() { + return SchematicSystem.INSTANCE; + } } diff --git a/src/main/java/baritone/cache/WorldScanner.java b/src/main/java/baritone/cache/WorldScanner.java index a88792255..35297a470 100644 --- a/src/main/java/baritone/cache/WorldScanner.java +++ b/src/main/java/baritone/cache/WorldScanner.java @@ -27,8 +27,10 @@ import net.minecraft.block.BlockState; import net.minecraft.client.multiplayer.ClientChunkProvider; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.chunk.AbstractChunkProvider; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.IChunk; import java.util.*; import java.util.stream.IntStream; @@ -109,6 +111,41 @@ public enum WorldScanner implements IWorldScanner { return res; } + @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; + } + private boolean scanChunkInto(int chunkX, int chunkZ, Chunk chunk, BlockOptionalMetaLookup filter, Collection result, int max, int yLevelThreshold, int playerY, int[] coordinateIterationOrder) { ChunkSection[] chunkInternalStorageArray = chunk.getSections(); boolean foundWithinY = false; @@ -145,26 +182,4 @@ public enum WorldScanner implements IWorldScanner { } return foundWithinY; } - - public int repack(IPlayerContext ctx) { - ClientChunkProvider chunkProvider = (ClientChunkProvider) ctx.world().getChunkProvider(); - ICachedWorld cachedWorld = ctx.worldData().getCachedWorld(); - - BetterBlockPos playerPos = ctx.playerFeet(); - int playerChunkX = playerPos.getX() >> 4; - int playerChunkZ = playerPos.getZ() >> 4; - int queued = 0; - for (int x = playerChunkX - 40; x <= playerChunkX + 40; x++) { - for (int z = playerChunkZ - 40; z <= playerChunkZ + 40; z++) { - Chunk chunk = chunkProvider.getChunk(x, z, null, false); - - if (chunk != null && !chunk.isEmpty()) { - queued++; - cachedWorld.queueForPacking(chunk); - } - } - } - - return queued; - } } diff --git a/src/main/java/baritone/command/argument/ArgConsumer.java b/src/main/java/baritone/command/argument/ArgConsumer.java index 651ca50bc..f4e7dd524 100644 --- a/src/main/java/baritone/command/argument/ArgConsumer.java +++ b/src/main/java/baritone/command/argument/ArgConsumer.java @@ -316,8 +316,7 @@ public class ArgConsumer implements IArgConsumer { try { return datatype.apply(this.context, original); } catch (Exception e) { - e.printStackTrace(); - throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName()); + throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName(), e); } } @@ -346,7 +345,7 @@ public class ArgConsumer implements IArgConsumer { try { return datatype.get(this.context); } catch (Exception e) { - throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName()); + throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName(), e); } } diff --git a/src/main/java/baritone/command/defaults/BuildCommand.java b/src/main/java/baritone/command/defaults/BuildCommand.java index 6ff90e1db..e7c4a36e1 100644 --- a/src/main/java/baritone/command/defaults/BuildCommand.java +++ b/src/main/java/baritone/command/defaults/BuildCommand.java @@ -17,6 +17,7 @@ package baritone.command.defaults; +import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.utils.BetterBlockPos; import baritone.api.command.Command; @@ -26,11 +27,11 @@ import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.command.argument.IArgConsumer; import net.minecraft.client.Minecraft; +import org.apache.commons.io.FilenameUtils; import java.io.File; import java.util.Arrays; import java.util.List; -import java.util.Locale; import java.util.stream.Stream; public class BuildCommand extends Command { @@ -44,8 +45,8 @@ public class BuildCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { File file = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile(); - if (!file.getName().toLowerCase(Locale.US).endsWith(".schematic")) { - file = new File(file.getAbsolutePath() + ".schematic"); + if (FilenameUtils.getExtension(file.getAbsolutePath()).isEmpty()) { + file = new File(file.getAbsolutePath() + "." + Baritone.settings().schematicFallbackExtension); } BetterBlockPos origin = ctx.playerFeet(); BetterBlockPos buildOrigin; diff --git a/src/main/java/baritone/command/defaults/CancelCommand.java b/src/main/java/baritone/command/defaults/CancelCommand.java deleted file mode 100644 index 3b4c63670..000000000 --- a/src/main/java/baritone/command/defaults/CancelCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of Baritone. - * - * Baritone is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Baritone is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Baritone. If not, see . - */ - -package baritone.command.defaults; - -import baritone.api.IBaritone; -import baritone.api.command.Command; -import baritone.api.command.exception.CommandException; -import baritone.api.command.argument.IArgConsumer; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - -public class CancelCommand extends Command { - - public CancelCommand(IBaritone baritone) { - super(baritone, "cancel", "stop"); - } - - @Override - public void execute(String label, IArgConsumer args) throws CommandException { - args.requireMax(0); - baritone.getPathingBehavior().cancelEverything(); - logDirect("ok canceled"); - } - - @Override - public Stream tabComplete(String label, IArgConsumer args) { - return Stream.empty(); - } - - @Override - public String getShortDesc() { - return "Cancel what Baritone is currently doing"; - } - - @Override - public List getLongDesc() { - return Arrays.asList( - "The cancel command tells Baritone to stop whatever it's currently doing.", - "", - "Usage:", - "> cancel" - ); - } -} diff --git a/src/main/java/baritone/command/defaults/DefaultCommands.java b/src/main/java/baritone/command/defaults/DefaultCommands.java index c48644e3b..67555ed51 100644 --- a/src/main/java/baritone/command/defaults/DefaultCommands.java +++ b/src/main/java/baritone/command/defaults/DefaultCommands.java @@ -24,52 +24,53 @@ import java.util.*; public final class DefaultCommands { - private DefaultCommands() {} + private DefaultCommands() { + } public static List createAll(IBaritone baritone) { Objects.requireNonNull(baritone); List commands = new ArrayList<>(Arrays.asList( - new HelpCommand(baritone), - new SetCommand(baritone), - new CommandAlias(baritone, Arrays.asList("modified", "mod", "baritone", "modifiedsettings"), "List modified settings", "set modified"), - new CommandAlias(baritone, "reset", "Reset all settings or just one", "set reset"), - new GoalCommand(baritone), - new GotoCommand(baritone), - new PathCommand(baritone), - new ProcCommand(baritone), - new VersionCommand(baritone), - new RepackCommand(baritone), - new BuildCommand(baritone), - new SchematicaCommand(baritone), - new ComeCommand(baritone), - new AxisCommand(baritone), - new CancelCommand(baritone), - new ForceCancelCommand(baritone), - new GcCommand(baritone), - new InvertCommand(baritone), - new TunnelCommand(baritone), - new RenderCommand(baritone), - new FarmCommand(baritone), - new ChestsCommand(baritone), - new FollowCommand(baritone), - new ExploreFilterCommand(baritone), - new ReloadAllCommand(baritone), - new SaveAllCommand(baritone), - new ExploreCommand(baritone), - new BlacklistCommand(baritone), - new FindCommand(baritone), - new MineCommand(baritone), - new ClickCommand(baritone), - new ThisWayCommand(baritone), - new WaypointsCommand(baritone), - new CommandAlias(baritone, "sethome", "Sets your home waypoint", "waypoints save home"), - new CommandAlias(baritone, "home", "Set goal to your home waypoint", "waypoints goal home"), - new SelCommand(baritone) + new HelpCommand(baritone), + new SetCommand(baritone), + new CommandAlias(baritone, Arrays.asList("modified", "mod", "baritone", "modifiedsettings"), "List modified settings", "set modified"), + new CommandAlias(baritone, "reset", "Reset all settings or just one", "set reset"), + new GoalCommand(baritone), + new GotoCommand(baritone), + new PathCommand(baritone), + new ProcCommand(baritone), + new VersionCommand(baritone), + new RepackCommand(baritone), + new BuildCommand(baritone), + new SchematicaCommand(baritone), + new ComeCommand(baritone), + new AxisCommand(baritone), + new ForceCancelCommand(baritone), + new GcCommand(baritone), + new InvertCommand(baritone), + new TunnelCommand(baritone), + new RenderCommand(baritone), + new FarmCommand(baritone), + new ChestsCommand(baritone), + new FollowCommand(baritone), + new ExploreFilterCommand(baritone), + new ReloadAllCommand(baritone), + new SaveAllCommand(baritone), + new ExploreCommand(baritone), + new BlacklistCommand(baritone), + new FindCommand(baritone), + new MineCommand(baritone), + new ClickCommand(baritone), + new ThisWayCommand(baritone), + new WaypointsCommand(baritone), + new CommandAlias(baritone, "sethome", "Sets your home waypoint", "waypoints save home"), + new CommandAlias(baritone, "home", "Set goal to your home waypoint", "waypoints goal home"), + new SelCommand(baritone) )); - PauseResumeCommands prc = new PauseResumeCommands(baritone); + ExecutionControlCommands prc = new ExecutionControlCommands(baritone); commands.add(prc.pauseCommand); commands.add(prc.resumeCommand); commands.add(prc.pausedCommand); + commands.add(prc.cancelCommand); return Collections.unmodifiableList(commands); } } diff --git a/src/main/java/baritone/command/defaults/PauseResumeCommands.java b/src/main/java/baritone/command/defaults/ExecutionControlCommands.java similarity index 82% rename from src/main/java/baritone/command/defaults/PauseResumeCommands.java rename to src/main/java/baritone/command/defaults/ExecutionControlCommands.java index 54718e9b7..4a04b9e09 100644 --- a/src/main/java/baritone/command/defaults/PauseResumeCommands.java +++ b/src/main/java/baritone/command/defaults/ExecutionControlCommands.java @@ -18,13 +18,13 @@ package baritone.command.defaults; 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.process.IBaritoneProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; -import baritone.api.command.Command; -import baritone.api.command.exception.CommandException; -import baritone.api.command.exception.CommandInvalidStateException; -import baritone.api.command.argument.IArgConsumer; import java.util.Arrays; import java.util.List; @@ -37,13 +37,14 @@ import java.util.stream.Stream; * TO USE THIS to pause and resume Baritone. Make your own process that returns {@link PathingCommandType#REQUEST_PAUSE * REQUEST_PAUSE} as needed. */ -public class PauseResumeCommands { +public class ExecutionControlCommands { Command pauseCommand; Command resumeCommand; Command pausedCommand; + Command cancelCommand; - public PauseResumeCommands(IBaritone baritone) { + public ExecutionControlCommands(IBaritone baritone) { // array for mutability, non-field so reflection can't touch it final boolean[] paused = {false}; baritone.getPathingControlManager().registerProcess( @@ -64,7 +65,8 @@ public class PauseResumeCommands { } @Override - public void onLostControl() {} + public void onLostControl() { + } @Override public double priority() { @@ -169,5 +171,36 @@ public class PauseResumeCommands { ); } }; + cancelCommand = new Command(baritone, "cancel", "stop") { + @Override + public void execute(String label, IArgConsumer args) throws CommandException { + args.requireMax(0); + if (paused[0]) { + paused[0] = false; + } + baritone.getPathingBehavior().cancelEverything(); + logDirect("ok canceled"); + } + + @Override + public Stream tabComplete(String label, IArgConsumer args) { + return Stream.empty(); + } + + @Override + public String getShortDesc() { + return "Cancel what Baritone is currently doing"; + } + + @Override + public List getLongDesc() { + return Arrays.asList( + "The cancel command tells Baritone to stop whatever it's currently doing.", + "", + "Usage:", + "> cancel" + ); + } + }; } } diff --git a/src/main/java/baritone/command/defaults/GotoCommand.java b/src/main/java/baritone/command/defaults/GotoCommand.java index 427e67b2a..28e768296 100644 --- a/src/main/java/baritone/command/defaults/GotoCommand.java +++ b/src/main/java/baritone/command/defaults/GotoCommand.java @@ -41,9 +41,13 @@ public class GotoCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { - if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) { // if we have a numeric first argument... + // If we have a numeric first argument, then parse arguments as coordinates. + // Note: There is no reason to want to go where you're already at so there + // is no need to handle the case of empty arguments. + if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) { + args.requireMax(3); BetterBlockPos origin = baritone.getPlayerContext().playerFeet(); - Goal goal = args.getDatatypePostOrNull(RelativeGoal.INSTANCE, origin); + Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin); logDirect(String.format("Going to: %s", goal.toString())); baritone.getCustomGoalProcess().setGoalAndPath(goal); return; diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index e798eeebf..08a46139e 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -37,6 +37,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockReader; import java.util.Optional; @@ -138,7 +139,7 @@ public interface MovementHelper extends ActionCosts, Helper { // every block that overrides isPassable with anything more complicated than a "return true;" or "return false;" // has already been accounted for above // therefore it's safe to not construct a blockpos from our x, y, z ints and instead just pass null - return state.allowsMovement(null, BlockPos.ZERO, PathType.LAND); // workaround for future compatibility =P + return state.allowsMovement(bsi.access, BlockPos.ZERO, PathType.LAND); // workaround for future compatibility =P } /** @@ -152,10 +153,18 @@ public interface MovementHelper extends ActionCosts, Helper { * @return Whether or not the block at the specified position */ static boolean fullyPassable(CalculationContext context, int x, int y, int z) { - return fullyPassable(context.get(x, y, z)); + return fullyPassable( + context.bsi.access, + context.bsi.isPassableBlockPos.setPos(x, y, z), + context.bsi.get0(x, y, z) + ); } - static boolean fullyPassable(BlockState state) { + static boolean fullyPassable(IPlayerContext ctx, BlockPos pos) { + return fullyPassable(ctx.world(), pos, ctx.world().getBlockState(pos)); + } + + static boolean fullyPassable(IBlockReader access, BlockPos pos, BlockState state) { Block block = state.getBlock(); if (block instanceof AirBlock) { // early return for most common case return true; @@ -178,7 +187,7 @@ public interface MovementHelper extends ActionCosts, Helper { return false; } // door, fence gate, liquid, trapdoor have been accounted for, nothing else uses the world or pos parameters - return state.allowsMovement(null, null, PathType.LAND); + return state.allowsMovement(access, pos, PathType.LAND); } static boolean isReplaceable(int x, int y, int z, BlockState state, BlockStateInterface bsi) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 4ac57ed8b..dcbede8d8 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -115,7 +115,7 @@ public class MovementParkour extends Movement { return; } BlockState destInto = context.bsi.get0(destX, y, destZ); - if (!MovementHelper.fullyPassable(destInto)) { + if (!MovementHelper.fullyPassable(context.bsi.access, context.bsi.isPassableBlockPos.setPos(destX, y, destZ), destInto)) { if (i <= 3 && context.allowParkourAscend && context.canSprint && MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) { res.x = destX; res.y = y + 1; diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index f4175e289..451b0bdc1 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -466,7 +466,7 @@ public class PathExecutor implements IPathExecutor, Helper { } for (int y = next.getDest().y; y <= movement.getSrc().y + 1; y++) { BlockPos chk = new BlockPos(next.getDest().x, y, next.getDest().z); - if (!MovementHelper.fullyPassable(ctx.world().getBlockState(chk))) { + if (!MovementHelper.fullyPassable(ctx, chk)) { break outer; } } @@ -491,7 +491,7 @@ public class PathExecutor implements IPathExecutor, Helper { } // we are centered BlockPos headBonk = current.getSrc().subtract(current.getDirection()).up(2); - if (MovementHelper.fullyPassable(ctx.world().getBlockState(headBonk))) { + if (MovementHelper.fullyPassable(ctx, headBonk)) { return true; } // wait 0.3 @@ -524,7 +524,7 @@ public class PathExecutor implements IPathExecutor, Helper { if (x == 1) { chk = chk.add(current.getDirection()); } - if (!MovementHelper.fullyPassable(ctx.world().getBlockState(chk))) { + if (!MovementHelper.fullyPassable(ctx, chk)) { return false; } } diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 43fdaf4f4..f63df6cd5 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -25,8 +25,14 @@ import baritone.api.pathing.goals.GoalGetToBlock; import baritone.api.process.IBuilderProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; +import baritone.api.schematic.FillSchematic; import baritone.api.schematic.ISchematic; -import baritone.api.utils.*; +import baritone.api.schematic.IStaticSchematic; +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.input.Input; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; @@ -34,9 +40,8 @@ import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; import baritone.utils.PathingCommandContext; -import baritone.utils.schematic.FillSchematic; import baritone.utils.schematic.MapArtSchematic; -import baritone.utils.schematic.Schematic; +import baritone.utils.schematic.SchematicSystem; import baritone.utils.schematic.schematica.SchematicaHelper; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.block.AirBlock; @@ -57,7 +62,6 @@ import net.minecraft.util.math.shapes.VoxelShape; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.util.*; import static baritone.api.pathing.movement.ActionCosts.COST_INF; @@ -73,6 +77,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil private int ticks; private boolean paused; private int layer; + private int numRepeats; private List approxPlaceable; public BuilderProcess(Baritone baritone) { @@ -99,6 +104,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil this.origin = new Vec3i(x, y, z); this.paused = false; this.layer = 0; + this.numRepeats = 0; this.observedCompleted = new LongOpenHashSet(); } @@ -117,27 +123,38 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil @Override public boolean build(String name, File schematic, Vec3i origin) { - CompoundNBT tag; - try (FileInputStream fileIn = new FileInputStream(schematic)) { - tag = CompressedStreamTools.readCompressed(fileIn); - } catch (IOException e) { + Optional format = SchematicSystem.INSTANCE.getByFile(schematic); + if (!format.isPresent()) { + return false; + } + + ISchematic parsed; + try { + parsed = format.get().parse(new FileInputStream(schematic)); + } catch (Exception e) { e.printStackTrace(); return false; } - //noinspection ConstantConditions - if (tag == null) { - return false; + + if (Baritone.settings().mapArtMode.value) { + parsed = new MapArtSchematic((IStaticSchematic) parsed); } - build(name, parse(tag), origin); + + build(name, parsed, origin); return true; } @Override public void buildOpenSchematic() { if (SchematicaHelper.isSchematicaPresent()) { - Optional> schematic = SchematicaHelper.getOpenSchematic(); + Optional> schematic = SchematicaHelper.getOpenSchematic(); if (schematic.isPresent()) { - this.build(schematic.get().getA().toString(), schematic.get().getA(), schematic.get().getB()); + IStaticSchematic s = schematic.get().getA(); + this.build( + schematic.get().getA().toString(), + Baritone.settings().mapArtMode.value ? new MapArtSchematic(s) : s, + schematic.get().getB() + ); } else { logDirect("No schematic currently open"); } @@ -159,10 +176,6 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return new ArrayList<>(approxPlaceable); } - private static ISchematic parse(CompoundNBT schematic) { - return Baritone.settings().mapArtMode.value ? new MapArtSchematic(schematic) : new Schematic(schematic); - } - @Override public boolean isActive() { return schematic != null; @@ -407,7 +420,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return onTick(calcFailed, isSafeToCancel); } Vec3i repeat = Baritone.settings().buildRepeat.value; - if (repeat.equals(new Vec3i(0, 0, 0))) { + int max = Baritone.settings().buildRepeatCount.value; + numRepeats++; + if (repeat.equals(new Vec3i(0, 0, 0)) || (max != -1 && numRepeats >= max)) { logDirect("Done building"); onLostControl(); return null; @@ -747,6 +762,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil schematic = null; realSchematic = null; layer = 0; + numRepeats = 0; paused = false; observedCompleted = null; } @@ -782,6 +798,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return true; } // TODO more complicated comparison logic I guess + if (desired.getBlock() instanceof AirBlock && Baritone.settings().buildIgnoreBlocks.value.contains(current.getBlock())) { + return true; + } + if (!(current.getBlock() instanceof AirBlock) && Baritone.settings().buildIgnoreExisting.value) { + return true; + } return current.equals(desired); } diff --git a/src/main/java/baritone/utils/BaritoneAutoTest.java b/src/main/java/baritone/utils/BaritoneAutoTest.java index e17764243..f0a29dfda 100644 --- a/src/main/java/baritone/utils/BaritoneAutoTest.java +++ b/src/main/java/baritone/utils/BaritoneAutoTest.java @@ -31,13 +31,13 @@ import net.minecraft.client.settings.AmbientOcclusionStatus; import net.minecraft.client.settings.CloudOption; import net.minecraft.client.settings.ParticleStatus; import net.minecraft.client.tutorial.TutorialSteps; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.HTTPUtil; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.GameType; -import net.minecraft.world.WorldSettings; -import net.minecraft.world.WorldType; +import net.minecraft.world.*; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.server.ServerWorld; import java.io.File; import java.io.IOException; @@ -95,7 +95,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { if (mc.currentScreen instanceof MainMenuScreen) { System.out.println("Beginning Baritone automatic test routine"); mc.displayGuiScreen(null); - WorldSettings worldsettings = new WorldSettings(TEST_SEED, GameType.getByName("survival"), true, false, WorldType.DEFAULT); + WorldSettings worldsettings = new WorldSettings(TEST_SEED, GameType.SURVIVAL, true, false, WorldType.DEFAULT); mc.launchIntegratedServer("BaritoneAutoTest", "BaritoneAutoTest", worldsettings); } @@ -104,6 +104,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { // If the integrated server is launched and the world has initialized, set the spawn point // to our defined starting position if (server != null && server.getWorld(DimensionType.OVERWORLD) != null) { + server.setDifficultyForAllWorlds(Difficulty.PEACEFUL, true); if (mc.player == null) { server.execute(() -> { server.getWorld(DimensionType.OVERWORLD).setSpawnPoint(STARTING_POSITION); @@ -113,6 +114,17 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { throw new IllegalStateException(result + ""); } }); + for (final ServerWorld world : mc.getIntegratedServer().getWorlds()) { + // If the world has initialized, set the spawn point to our defined starting position + if (world != null) { + // I would rather do this than try to mess with poz + CompoundNBT nbt = world.getGameRules().write(); + nbt.putString("spawnRadius", "0"); + world.getGameRules().read(nbt); + + world.setSpawnPoint(STARTING_POSITION); + } + } } } @@ -121,7 +133,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { // Force the integrated server to share the world to LAN so that // the ingame pause menu gui doesn't actually pause our game if (mc.isSingleplayer() && !mc.getIntegratedServer().getPublic()) { - mc.getIntegratedServer().shareToLAN(GameType.getByName("survival"), false, HTTPUtil.getSuitableLanPort()); + mc.getIntegratedServer().shareToLAN(GameType.SURVIVAL, false, HTTPUtil.getSuitableLanPort()); } // For the first 200 ticks, wait for the world to generate @@ -163,5 +175,6 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { } } - private BaritoneAutoTest() {} + private BaritoneAutoTest() { + } } diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java index 5fd1a5909..6e4e36e23 100644 --- a/src/main/java/baritone/utils/BlockStateInterface.java +++ b/src/main/java/baritone/utils/BlockStateInterface.java @@ -28,6 +28,7 @@ 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; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; @@ -42,6 +43,9 @@ public class BlockStateInterface { private final ClientChunkProvider provider; private final WorldData worldData; + protected final IBlockReader world; + public final BlockPos.MutableBlockPos isPassableBlockPos; + public final IBlockReader access; private Chunk prev = null; private CachedRegion prevCached = null; @@ -59,6 +63,7 @@ public class BlockStateInterface { } public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) { + this.world = world; this.worldData = worldData; if (copyLoadedChunks) { this.provider = ((IClientChunkProvider) world.getChunkProvider()).createThreadSafeCopy(); @@ -69,6 +74,8 @@ public class BlockStateInterface { if (!Minecraft.getInstance().isOnExecutionThread()) { throw new IllegalStateException(); } + this.isPassableBlockPos = new BlockPos.MutableBlockPos(); + this.access = new BlockStateInterfaceAccessWrapper(this); } public boolean worldContainsLoadedChunk(int blockX, int blockZ) { diff --git a/src/main/java/baritone/utils/BlockStateInterfaceAccessWrapper.java b/src/main/java/baritone/utils/BlockStateInterfaceAccessWrapper.java new file mode 100644 index 000000000..06206eecd --- /dev/null +++ b/src/main/java/baritone/utils/BlockStateInterfaceAccessWrapper.java @@ -0,0 +1,57 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.utils; + +import net.minecraft.block.BlockState; +import net.minecraft.fluid.IFluidState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; + +import javax.annotation.Nullable; + +/** + * @author Brady + * @since 11/5/2019 + */ +@SuppressWarnings("NullableProblems") +public final class BlockStateInterfaceAccessWrapper implements IBlockReader { + + private final BlockStateInterface bsi; + + BlockStateInterfaceAccessWrapper(BlockStateInterface bsi) { + this.bsi = bsi; + } + + @Nullable + @Override + public TileEntity getTileEntity(BlockPos pos) { + throw new UnsupportedOperationException("getTileEntity not supported by BlockStateInterfaceAccessWrapper"); + } + + @Override + public BlockState getBlockState(BlockPos pos) { + // BlockStateInterface#get0(BlockPos) btfo! + return this.bsi.get0(pos.getX(), pos.getY(), pos.getZ()); + } + + @Override + public IFluidState getFluidState(BlockPos blockPos) { + return getBlockState(blockPos).getFluidState(); + } +} diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index 5fb1f861e..c14ddc5ac 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -19,23 +19,32 @@ package baritone.utils.schematic; import net.minecraft.block.AirBlock; import net.minecraft.block.BlockState; -import net.minecraft.nbt.CompoundNBT; +import baritone.api.schematic.IStaticSchematic; +import baritone.api.schematic.MaskSchematic; import java.util.OptionalInt; import java.util.function.Predicate; -public class MapArtSchematic extends Schematic { +public class MapArtSchematic extends MaskSchematic { private final int[][] heightMap; - public MapArtSchematic(CompoundNBT schematic) { + public MapArtSchematic(IStaticSchematic schematic) { super(schematic); - heightMap = new int[widthX][lengthZ]; + this.heightMap = generateHeightMap(schematic); + } - for (int x = 0; x < widthX; x++) { - for (int z = 0; z < lengthZ; z++) { - BlockState[] column = states[x][z]; + @Override + protected boolean partOfMask(int x, int y, int z, BlockState currentState) { + return y >= this.heightMap[x][z]; + } + private static int[][] generateHeightMap(IStaticSchematic schematic) { + int[][] heightMap = new int[schematic.widthX()][schematic.lengthZ()]; + + for (int x = 0; x < schematic.widthX(); x++) { + for (int z = 0; z < schematic.lengthZ(); z++) { + BlockState[] column = schematic.getColumn(x, z); OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof AirBlock)); if (lowestBlockY.isPresent()) { heightMap[x][z] = lowestBlockY.getAsInt(); @@ -44,9 +53,9 @@ public class MapArtSchematic extends Schematic { System.out.println("Letting it be whatever"); heightMap[x][z] = 256; } - } } + return heightMap; } private static OptionalInt lastIndexMatching(T[] arr, Predicate predicate) { @@ -57,10 +66,4 @@ public class MapArtSchematic extends Schematic { } return OptionalInt.empty(); } - - @Override - public boolean inSchematic(int x, int y, int z, BlockState currentState) { - // in map art, we only care about coordinates in or above the art - return super.inSchematic(x, y, z, currentState) && y >= heightMap[x][z]; - } } diff --git a/src/main/java/baritone/utils/schematic/SchematicSystem.java b/src/main/java/baritone/utils/schematic/SchematicSystem.java new file mode 100644 index 000000000..8afafa8c3 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/SchematicSystem.java @@ -0,0 +1,51 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.utils.schematic; + +import baritone.api.command.registry.Registry; +import baritone.api.schematic.ISchematicSystem; +import baritone.api.schematic.format.ISchematicFormat; +import baritone.utils.schematic.format.DefaultSchematicFormats; + +import java.io.File; +import java.util.Arrays; +import java.util.Optional; + +/** + * @author Brady + * @since 12/24/2019 + */ +public enum SchematicSystem implements ISchematicSystem { + INSTANCE; + + private final Registry registry = new Registry<>(); + + SchematicSystem() { + Arrays.stream(DefaultSchematicFormats.values()).forEach(this.registry::register); + } + + @Override + public Registry getRegistry() { + return this.registry; + } + + @Override + public Optional getByFile(File file) { + return this.registry.stream().filter(format -> format.isFileType(file)).findFirst(); + } +} diff --git a/src/main/java/baritone/utils/schematic/FillSchematic.java b/src/main/java/baritone/utils/schematic/StaticSchematic.java similarity index 60% rename from src/main/java/baritone/utils/schematic/FillSchematic.java rename to src/main/java/baritone/utils/schematic/StaticSchematic.java index 6eddbcc25..37da08a8d 100644 --- a/src/main/java/baritone/utils/schematic/FillSchematic.java +++ b/src/main/java/baritone/utils/schematic/StaticSchematic.java @@ -17,42 +17,34 @@ package baritone.utils.schematic; -import baritone.api.schematic.ISchematic; +import baritone.api.schematic.AbstractSchematic; +import baritone.api.schematic.IStaticSchematic; import net.minecraft.block.BlockState; import java.util.List; -public class FillSchematic implements ISchematic { +/** + * Default implementation of {@link IStaticSchematic} + * + * @author Brady + * @since 12/23/2019 + */ +public class StaticSchematic extends AbstractSchematic implements IStaticSchematic { - private final int widthX; - private final int heightY; - private final int lengthZ; - private final BlockState state; - - public FillSchematic(int widthX, int heightY, int lengthZ, BlockState state) { - this.widthX = widthX; - this.heightY = heightY; - this.lengthZ = lengthZ; - this.state = state; - } + protected BlockState[][][] states; @Override public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { - return state; + return this.states[x][z][y]; } @Override - public int widthX() { - return widthX; + public BlockState getDirect(int x, int y, int z) { + return this.states[x][z][y]; } @Override - public int heightY() { - return heightY; - } - - @Override - public int lengthZ() { - return lengthZ; + public BlockState[] getColumn(int x, int z) { + return this.states[x][z]; } } diff --git a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java new file mode 100644 index 000000000..693e90af3 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.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.utils.schematic.format; + +import baritone.api.schematic.IStaticSchematic; +import baritone.api.schematic.format.ISchematicFormat; +import baritone.utils.schematic.format.defaults.MCEditSchematic; +import baritone.utils.schematic.format.defaults.SpongeSchematic; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.CompressedStreamTools; +import org.apache.commons.io.FilenameUtils; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +/** + * Default implementations of {@link ISchematicFormat} + * + * @author Brady + * @since 12/13/2019 + */ +public enum DefaultSchematicFormats implements ISchematicFormat { + + /** + * The MCEdit schematic specification. Commonly denoted by the ".schematic" file extension. + */ + MCEDIT("schematic") { + + @Override + public IStaticSchematic parse(InputStream input) throws IOException { + return new MCEditSchematic(CompressedStreamTools.readCompressed(input)); + } + }, + + /** + * The SpongePowered Schematic Specification. Commonly denoted by the ".schem" file extension. + * + * @see Sponge Schematic Specification + */ + SPONGE("schem") { + + @Override + public IStaticSchematic parse(InputStream input) throws IOException { + CompoundNBT nbt = CompressedStreamTools.readCompressed(input); + int version = nbt.getInt("Version"); + switch (version) { + case 1: + case 2: + return new SpongeSchematic(nbt); + default: + throw new UnsupportedOperationException("Unsupported Version of a Sponge Schematic"); + } + } + }; + + private final String extension; + + DefaultSchematicFormats(String extension) { + this.extension = extension; + } + + @Override + public boolean isFileType(File file) { + return this.extension.equalsIgnoreCase(FilenameUtils.getExtension(file.getAbsolutePath())); + } +} diff --git a/src/main/java/baritone/utils/schematic/Schematic.java b/src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java similarity index 51% rename from src/main/java/baritone/utils/schematic/Schematic.java rename to src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java index bf1a18a76..e62c25493 100644 --- a/src/main/java/baritone/utils/schematic/Schematic.java +++ b/src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java @@ -15,34 +15,35 @@ * along with Baritone. If not, see . */ -package baritone.utils.schematic; +package baritone.utils.schematic.format.defaults; -import baritone.api.schematic.ISchematic; +import baritone.utils.schematic.StaticSchematic; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.datafix.fixes.ItemIntIDToString; +import net.minecraft.util.registry.Registry; -import java.util.List; +/** + * @author Brady + * @since 12/27/2019 + */ +public final class MCEditSchematic extends StaticSchematic { -public class Schematic implements ISchematic { - - public final int widthX; - public final int heightY; - public final int lengthZ; - protected final BlockState[][][] states; - - public Schematic(CompoundNBT schematic) { - /*String type = schematic.getString("Materials"); + public MCEditSchematic(CompoundNBT schematic) { + String type = schematic.getString("Materials"); if (!type.equals("Alpha")) { throw new IllegalStateException("bad schematic " + type); } - widthX = schematic.getInteger("Width"); - heightY = schematic.getInteger("Height"); - lengthZ = schematic.getInteger("Length"); + this.x = schematic.getInt("Width"); + this.y = schematic.getInt("Height"); + this.z = schematic.getInt("Length"); byte[] blocks = schematic.getByteArray("Blocks"); - byte[] metadata = schematic.getByteArray("Data"); +// byte[] metadata = schematic.getByteArray("Data"); byte[] additional = null; - if (schematic.hasKey("AddBlocks")) { + if (schematic.contains("AddBlocks")) { byte[] addBlocks = schematic.getByteArray("AddBlocks"); additional = new byte[addBlocks.length * 2]; for (int i = 0; i < addBlocks.length; i++) { @@ -50,43 +51,23 @@ public class Schematic implements ISchematic { additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble } } - states = new BlockState[widthX][lengthZ][heightY]; - for (int y = 0; y < heightY; y++) { - for (int z = 0; z < lengthZ; z++) { - for (int x = 0; x < widthX; x++) { - int blockInd = (y * lengthZ + z) * widthX + x; + this.states = new BlockState[this.x][this.z][this.y]; + for (int y = 0; y < this.y; y++) { + for (int z = 0; z < this.z; z++) { + for (int x = 0; x < this.x; x++) { + int blockInd = (y * this.z + z) * this.x + x; int blockID = blocks[blockInd] & 0xFF; if (additional != null) { // additional is 0 through 15 inclusive since it's & 0xF above blockID |= additional[blockInd] << 8; } - Block block = Block.REGISTRY.getObjectById(blockID); - int meta = metadata[blockInd] & 0xFF; - states[x][z][y] = block.getStateFromMeta(meta); + Block block = Registry.BLOCK.getOrDefault(ResourceLocation.tryCreate(ItemIntIDToString.getItem(blockID))); +// int meta = metadata[blockInd] & 0xFF; +// this.states[x][z][y] = block.getStateFromMeta(meta); + this.states[x][z][y] = block.getDefaultState(); } } - }*/ - throw new UnsupportedOperationException("1.13 be like: numeric IDs btfo"); + } } - - @Override - public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { - return states[x][z][y]; - } - - @Override - public int widthX() { - return widthX; - } - - @Override - public int heightY() { - return heightY; - } - - @Override - public int lengthZ() { - return lengthZ; - } -} +} \ No newline at end of file diff --git a/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java b/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java new file mode 100644 index 000000000..3ba3798c1 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java @@ -0,0 +1,158 @@ +/* + * 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.utils.schematic.format.defaults; + +import baritone.utils.schematic.StaticSchematic; +import baritone.utils.type.VarInt; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.IProperty; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Brady + * @since 12/27/2019 + */ +public final class SpongeSchematic extends StaticSchematic { + + public SpongeSchematic(CompoundNBT nbt) { + this.x = nbt.getInt("Width"); + this.y = nbt.getInt("Height"); + this.z = nbt.getInt("Length"); + this.states = new BlockState[this.x][this.z][this.y]; + + Int2ObjectArrayMap palette = new Int2ObjectArrayMap<>(); + CompoundNBT paletteTag = nbt.getCompound("Palette"); + for (String tag : paletteTag.keySet()) { + int index = paletteTag.getInt(tag); + + SerializedBlockState serializedState = SerializedBlockState.getFromString(tag); + if (serializedState == null) { + throw new IllegalArgumentException("Unable to parse palette tag"); + } + + BlockState state = serializedState.deserialize(); + if (state == null) { + throw new IllegalArgumentException("Unable to deserialize palette tag"); + } + + palette.put(index, state); + } + + // BlockData is stored as an NBT byte[], however, the actual data that is represented is a varint[] + byte[] rawBlockData = nbt.getByteArray("BlockData"); + int[] blockData = new int[this.x * this.y * this.z]; + int offset = 0; + for (int i = 0; i < blockData.length; i++) { + if (offset >= rawBlockData.length) { + throw new IllegalArgumentException("No remaining bytes in BlockData for complete schematic"); + } + + VarInt varInt = VarInt.read(rawBlockData, offset); + blockData[i] = varInt.getValue(); + offset += varInt.getSize(); + } + + for (int y = 0; y < this.y; y++) { + for (int z = 0; z < this.z; z++) { + for (int x = 0; x < this.x; x++) { + int index = (y * this.z + z) * this.x + x; + BlockState state = palette.get(blockData[index]); + if (state == null) { + throw new IllegalArgumentException("Invalid Palette Index " + index); + } + + this.states[x][z][y] = state; + } + } + } + } + + private static final class SerializedBlockState { + + private static final Pattern REGEX = Pattern.compile("(?(\\w+:)?\\w+)(\\[(?(\\w+=\\w+,?)+)])?"); + + private final ResourceLocation resourceLocation; + private final Map properties; + private BlockState blockState; + + private SerializedBlockState(ResourceLocation resourceLocation, Map properties) { + this.resourceLocation = resourceLocation; + this.properties = properties; + } + + private BlockState deserialize() { + if (this.blockState == null) { + Block block = Registry.BLOCK.getOrDefault(this.resourceLocation); + this.blockState = block.getDefaultState(); + + this.properties.keySet().stream().sorted(String::compareTo).forEachOrdered(key -> { + IProperty property = block.getStateContainer().getProperty(key); + if (property != null) { + this.blockState = setPropertyValue(this.blockState, property, this.properties.get(key)); + } + }); + } + return this.blockState; + } + + private static SerializedBlockState getFromString(String s) { + Matcher m = REGEX.matcher(s); + if (!m.matches()) { + return null; + } + + try { + String location = m.group("location"); + String properties = m.group("properties"); + + ResourceLocation resourceLocation = new ResourceLocation(location); + Map propertiesMap = new HashMap<>(); + if (properties != null) { + for (String property : properties.split(",")) { + String[] split = property.split("="); + propertiesMap.put(split[0], split[1]); + } + } + + return new SerializedBlockState(resourceLocation, propertiesMap); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static > BlockState setPropertyValue(BlockState state, IProperty property, String value) { + Optional parsed = property.parseValue(value); + if (parsed.isPresent()) { + return state.with(property, parsed.get()); + } else { + throw new IllegalArgumentException("Invalid value for property " + property); + } + } + } +} diff --git a/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java b/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java index 168e64c40..6a885dec0 100644 --- a/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java +++ b/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java @@ -17,14 +17,14 @@ package baritone.utils.schematic.schematica; -import baritone.api.schematic.ISchematic; +import baritone.api.schematic.IStaticSchematic; import com.github.lunatrius.schematica.client.world.SchematicWorld; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; import java.util.List; -public final class SchematicAdapter implements ISchematic { +public final class SchematicAdapter implements IStaticSchematic { private final SchematicWorld schematic; @@ -34,7 +34,12 @@ public final class SchematicAdapter implements ISchematic { @Override public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { - return schematic.getSchematic().getBlockState(new BlockPos(x, y, z)); + return this.getDirect(x, y, z); + } + + @Override + public BlockState getDirect(int x, int y, int z) { + return this.schematic.getSchematic().getBlockState(new BlockPos(x, y, z)); } @Override diff --git a/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java b/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java index 85b3967f5..fab688455 100644 --- a/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java +++ b/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java @@ -17,7 +17,7 @@ package baritone.utils.schematic.schematica; -import baritone.api.schematic.ISchematic; +import baritone.api.schematic.IStaticSchematic; import com.github.lunatrius.schematica.Schematica; import com.github.lunatrius.schematica.proxy.ClientProxy; import net.minecraft.util.Tuple; @@ -37,7 +37,7 @@ public enum SchematicaHelper { } } - public static Optional> getOpenSchematic() { + public static Optional> getOpenSchematic() { return Optional.ofNullable(ClientProxy.schematic) .map(world -> new Tuple<>(new SchematicAdapter(world), world.position)); } diff --git a/src/main/java/baritone/utils/type/VarInt.java b/src/main/java/baritone/utils/type/VarInt.java new file mode 100644 index 000000000..7cc005bdb --- /dev/null +++ b/src/main/java/baritone/utils/type/VarInt.java @@ -0,0 +1,95 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.utils.type; + +import it.unimi.dsi.fastutil.bytes.ByteArrayList; +import it.unimi.dsi.fastutil.bytes.ByteList; + +/** + * @author Brady + * @since 12/19/2019 + */ +public final class VarInt { + + private final int value; + private final byte[] serialized; + private final int size; + + public VarInt(int value) { + this.value = value; + this.serialized = serialize0(this.value); + this.size = this.serialized.length; + } + + /** + * @return The integer value that is represented by this {@link VarInt}. + */ + public final int getValue() { + return this.value; + } + + /** + * @return The size of this {@link VarInt}, in bytes, once serialized. + */ + public final int getSize() { + return this.size; + } + + public final byte[] serialize() { + return this.serialized; + } + + private static byte[] serialize0(int valueIn) { + ByteList bytes = new ByteArrayList(); + + int value = valueIn; + while ((value & 0x80) != 0) { + bytes.add((byte) (value & 0x7F | 0x80)); + value >>>= 7; + } + bytes.add((byte) (value & 0xFF)); + + return bytes.toByteArray(); + } + + public static VarInt read(byte[] bytes) { + return read(bytes, 0); + } + + public static VarInt read(byte[] bytes, int start) { + int value = 0; + int size = 0; + int index = start; + + while (true) { + byte b = bytes[index++]; + value |= (b & 0x7F) << size++ * 7; + + if (size > 5) { + throw new IllegalArgumentException("VarInt size cannot exceed 5 bytes"); + } + + // Most significant bit denotes another byte is to be read. + if ((b & 0x80) == 0) { + break; + } + } + + return new VarInt(value); + } +}