diff --git a/src/api/java/baritone/api/cache/IWorldScanner.java b/src/api/java/baritone/api/cache/IWorldScanner.java index 6f4349ace..009268fbc 100644 --- a/src/api/java/baritone/api/cache/IWorldScanner.java +++ b/src/api/java/baritone/api/cache/IWorldScanner.java @@ -17,7 +17,7 @@ package baritone.api.cache; -import baritone.api.utils.IBlockFilter; +import baritone.api.utils.BlockOptionalMetaLookup; import baritone.api.utils.IPlayerContext; import net.minecraft.block.Block; import net.minecraft.util.math.BlockPos; @@ -36,26 +36,30 @@ public interface IWorldScanner { * * @param ctx The {@link IPlayerContext} containing player and world info that the * scan is based upon - * @param filter The block filter to scan for + * @param filter The blocks to scan for * @param max The maximum number of blocks to scan before cutoff * @param yLevelThreshold If a block is found within this Y level, the current result will be * returned, if the value is negative, then this condition doesn't apply. * @param maxSearchRadius The maximum chunk search radius * @return The matching block positions */ - List scanChunkRadius(IPlayerContext ctx, IBlockFilter filter, int max, int yLevelThreshold, int maxSearchRadius); + List scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius); + + default List scanChunkRadius(IPlayerContext ctx, List filter, int max, int yLevelThreshold, int maxSearchRadius) { + return scanChunkRadius(ctx, new BlockOptionalMetaLookup(filter.toArray(new Block[0])), max, yLevelThreshold, maxSearchRadius); + } /** * Scans a single chunk for the specified blocks. * * @param ctx The {@link IPlayerContext} containing player and world info that the * scan is based upon - * @param filter The block filter to scan for + * @param filter The blocks to scan for * @param pos The position of the target chunk * @param max The maximum number of blocks to scan before cutoff * @param yLevelThreshold If a block is found within this Y level, the current result will be * returned, if the value is negative, then this condition doesn't apply. * @return The matching block positions */ - List scanChunk(IPlayerContext ctx, IBlockFilter filter, ChunkPos pos, int max, int yLevelThreshold); + List scanChunk(IPlayerContext ctx, BlockOptionalMetaLookup filter, ChunkPos pos, int max, int yLevelThreshold); } diff --git a/src/api/java/baritone/api/process/IMineProcess.java b/src/api/java/baritone/api/process/IMineProcess.java index 4885e32f9..aa01aa5ae 100644 --- a/src/api/java/baritone/api/process/IMineProcess.java +++ b/src/api/java/baritone/api/process/IMineProcess.java @@ -17,10 +17,12 @@ package baritone.api.process; -import baritone.api.utils.BlockListFilter; -import baritone.api.utils.IBlockFilter; +import baritone.api.utils.BlockOptionalMeta; +import baritone.api.utils.BlockOptionalMetaLookup; import net.minecraft.block.Block; +import java.util.Arrays; + /** * @author Brady * @since 9/23/2018 @@ -42,16 +44,16 @@ public interface IMineProcess extends IBaritoneProcess { * are mined. This is based on the first target block to mine. * * @param quantity The number of items to get from blocks mined - * @param filter The filter to run blocks through + * @param filter The blocks to mine */ - void mine(int quantity, IBlockFilter filter); + void mine(int quantity, BlockOptionalMetaLookup filter); /** * Begin to search for and mine the specified blocks. * - * @param filter The filter to run blocks through + * @param filter The blocks to mine */ - default void mine(IBlockFilter filter) { + default void mine(BlockOptionalMetaLookup filter) { mine(0, filter); } @@ -64,6 +66,24 @@ public interface IMineProcess extends IBaritoneProcess { mineByName(0, blocks); } + /** + * Begin to search for and mine the specified blocks. + * + * @param boms The blocks to mine + */ + default void mine(int quantity, BlockOptionalMeta... boms) { + mine(quantity, new BlockOptionalMetaLookup(boms)); + } + + /** + * Begin to search for and mine the specified blocks. + * + * @param boms The blocks to mine + */ + default void mine(BlockOptionalMeta... boms) { + mine(0, boms); + } + /** * Begin to search for and mine the specified blocks. * @@ -71,7 +91,11 @@ public interface IMineProcess extends IBaritoneProcess { * @param blocks The blocks to mine */ default void mine(int quantity, Block... blocks) { - mine(quantity, new BlockListFilter(blocks)); + mine(quantity, new BlockOptionalMetaLookup( + Arrays.stream(blocks) + .map(BlockOptionalMeta::new) + .toArray(BlockOptionalMeta[]::new) + )); } /** diff --git a/src/api/java/baritone/api/utils/BlockListFilter.java b/src/api/java/baritone/api/utils/BlockListFilter.java deleted file mode 100644 index 6116f22b9..000000000 --- a/src/api/java/baritone/api/utils/BlockListFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -package baritone.api.utils; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class BlockListFilter implements IBlockFilter { - private final List blocks = new ArrayList<>(); - - public BlockListFilter(List blocks) { - this.blocks.addAll(blocks); - } - - public BlockListFilter(Block... blocks) { - this.blocks.addAll(Arrays.asList(blocks)); - } - - @Override - public boolean selected(@Nonnull IBlockState blockstate) { - return blocks.contains(blockstate.getBlock()); - } - - @Override - public List blocks() { - return blocks; - } - - @Override - public String toString() { - return String.format( - "BlockListFilter{%s}", - String.join( - ",", - blocks.stream() - .map(Block.REGISTRY::getNameForObject) - .map(ResourceLocation::toString) - .toArray(String[]::new) - ) - ); - } -} diff --git a/src/api/java/baritone/api/utils/BlockOptionalMeta.java b/src/api/java/baritone/api/utils/BlockOptionalMeta.java new file mode 100644 index 000000000..b77bf541e --- /dev/null +++ b/src/api/java/baritone/api/utils/BlockOptionalMeta.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.api.utils; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.util.Objects.isNull; + +public final class BlockOptionalMeta { + private final Block block; + private final int meta; + private final boolean noMeta; + private static final Pattern pattern = Pattern.compile("^(.+?)(?::(\\d+))?$"); + + public BlockOptionalMeta(@Nonnull Block block, @Nullable Integer meta) { + this.block = block; + this.noMeta = isNull(meta); + this.meta = noMeta ? 0 : meta; + } + + public BlockOptionalMeta(@Nonnull Block block) { + this(block, null); + } + + public BlockOptionalMeta(@Nonnull String selector) { + Matcher matcher = pattern.matcher(selector); + + if (!matcher.find()) { + throw new IllegalArgumentException("invalid block selector"); + } + + MatchResult matchResult = matcher.toMatchResult(); + noMeta = matchResult.groupCount() < 2; + + ResourceLocation id = new ResourceLocation(matchResult.group(1)); + + if (!Block.REGISTRY.containsKey(id)) { + throw new IllegalArgumentException("Invalid block ID"); + } + + block = Block.REGISTRY.getObject(id); + meta = noMeta ? 0 : Integer.parseInt(matchResult.group(2)); + } + + public Block getBlock() { + return block; + } + + public Integer getMeta() { + return meta; + } + + public boolean matches(@Nonnull Block block, int meta) { + // & instead of && is intentional + return block == this.block & (noMeta || meta == this.meta); + } + + public boolean matches(@Nonnull IBlockState blockstate) { + return matches(blockstate.getBlock(), block.damageDropped(blockstate)); + } + + @Override + public String toString() { + return String.format("BlockOptionalMeta{block=%s,meta=%s}", block, meta); + } + + public static IBlockState blockStateFromStack(ItemStack stack) { + //noinspection deprecation + return Block.getBlockFromItem(stack.getItem()).getStateFromMeta(stack.getMetadata()); + } +} diff --git a/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java new file mode 100644 index 000000000..eafe49e16 --- /dev/null +++ b/src/api/java/baritone/api/utils/BlockOptionalMetaLookup.java @@ -0,0 +1,78 @@ +package baritone.api.utils; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class BlockOptionalMetaLookup { + private final Map lookup = new HashMap<>(); + + public BlockOptionalMetaLookup() { + } + + public BlockOptionalMetaLookup(BlockOptionalMeta... boms) { + put(boms); + } + + public BlockOptionalMetaLookup(Block... blocks) { + put(blocks); + } + + public BlockOptionalMetaLookup(List blocks) { + put(blocks); + } + + public void put(BlockOptionalMeta bom) { + final int[] metaArr = new int[] {bom.getMeta()}; + lookup.compute(bom.getBlock(), (__, arr) -> arr == null ? metaArr : ArrayUtils.addAll(arr, metaArr)); + } + + public void put(BlockOptionalMeta... boms) { + for (BlockOptionalMeta bom : boms) { + put(bom); + } + } + + public void put(Block... blocks) { + for (Block block : blocks) { + put(new BlockOptionalMeta(block)); + } + } + + public void put(List blocks) { + for (Block block : blocks) { + put(new BlockOptionalMeta(block)); + } + } + + public boolean has(Block block) { + return lookup.containsKey(block); + } + + public boolean has(IBlockState state) { + Block block = state.getBlock(); + int[] arr = lookup.get(block); + + if (arr == null) { + return false; + } + + int meta = block.damageDropped(state); + for (int value : arr) { + if (value == meta) { + return true; + } + } + + return false; + } + + public Set blocks() { + return lookup.keySet(); + } +} diff --git a/src/api/java/baritone/api/utils/BlockSelector.java b/src/api/java/baritone/api/utils/BlockSelector.java deleted file mode 100644 index 54f85ecd9..000000000 --- a/src/api/java/baritone/api/utils/BlockSelector.java +++ /dev/null @@ -1,64 +0,0 @@ -package baritone.api.utils; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.List; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static java.util.Objects.isNull; - -public class BlockSelector implements IBlockFilter { - private final Block block; - private final IBlockState blockstate; - private final int damage; - private static final Pattern pattern = Pattern.compile("^(.+?)(?::(\\d+))?$"); - - public BlockSelector(@Nonnull String selector) { - Matcher matcher = pattern.matcher(selector); - - if (!matcher.find()) { - throw new RuntimeException("invalid block selector"); - } - - MatchResult matchResult = matcher.toMatchResult(); - boolean hasData = matchResult.groupCount() > 1; - - ResourceLocation id = new ResourceLocation(matchResult.group(1)); - - if (!Block.REGISTRY.containsKey(id)) { - throw new IllegalArgumentException("Invalid block ID"); - } - - block = Block.REGISTRY.getObject(id); - //noinspection deprecation - blockstate = hasData ? block.getStateFromMeta(Integer.parseInt(matchResult.group(2))) : null; - damage = block.damageDropped(blockstate); - } - - @Override - public boolean selected(@Nonnull IBlockState blockstate) { - return blockstate.getBlock() == block && (isNull(this.blockstate) || block.damageDropped(blockstate) == damage); - } - - @Override - public List blocks() { - return Collections.singletonList(block); - } - - @Override - public String toString() { - return String.format("BlockSelector{block=%s,blockstate=%s}", block, blockstate); - } - - public static IBlockState stateFromItem(ItemStack stack) { - //noinspection deprecation - return Block.getBlockFromItem(stack.getItem()).getStateFromMeta(stack.getMetadata()); - } -} diff --git a/src/api/java/baritone/api/utils/CompositeBlockFilter.java b/src/api/java/baritone/api/utils/CompositeBlockFilter.java deleted file mode 100644 index d2297d3b8..000000000 --- a/src/api/java/baritone/api/utils/CompositeBlockFilter.java +++ /dev/null @@ -1,50 +0,0 @@ -package baritone.api.utils; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -public class CompositeBlockFilter implements IBlockFilter { - private IBlockFilter[] filters; - - public CompositeBlockFilter(List filters) { - this.filters = filters.toArray(new IBlockFilter[0]); - } - - public CompositeBlockFilter(IBlockFilter... filters) { - this.filters = filters; - } - - @Override - public boolean selected(@Nonnull IBlockState blockstate) { - for (IBlockFilter filter : filters) { - if (filter.selected(blockstate)) { - return true; - } - } - - return false; - } - - @Override - public List blocks() { - return Arrays.stream(filters) - .map(IBlockFilter::blocks) - .flatMap(Collection::stream) - .collect(Collectors.toCollection(ArrayList::new)); - } - - @Override - public String toString() { - return String.format( - "CompositeBlockFilter{%s}", - String.join(",", Arrays.stream(filters).map(Object::toString).toArray(String[]::new)) - ); - } -} diff --git a/src/api/java/baritone/api/utils/IBlockFilter.java b/src/api/java/baritone/api/utils/IBlockFilter.java deleted file mode 100644 index 2ad44823d..000000000 --- a/src/api/java/baritone/api/utils/IBlockFilter.java +++ /dev/null @@ -1,22 +0,0 @@ -package baritone.api.utils; - -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; - -import javax.annotation.Nonnull; -import java.util.List; - -public interface IBlockFilter { - /** - * @param blockstate The blockstate of the block to test. - * @return If that blockstate passes this filter. - */ - boolean selected(@Nonnull IBlockState blockstate); - - /** - * @return A possibly incomplete list of blocks this filter selects. Not all states of each block may be selected, - * and this may not contain all selected blocks, but every block on this list is guaranteed to have a selected - * state. - */ - List blocks(); -} diff --git a/src/api/java/baritone/api/utils/command/datatypes/ForBlockSelector.java b/src/api/java/baritone/api/utils/command/datatypes/ForBlockOptionalMeta.java similarity index 51% rename from src/api/java/baritone/api/utils/command/datatypes/ForBlockSelector.java rename to src/api/java/baritone/api/utils/command/datatypes/ForBlockOptionalMeta.java index eb4047dc8..7226d0cb3 100644 --- a/src/api/java/baritone/api/utils/command/datatypes/ForBlockSelector.java +++ b/src/api/java/baritone/api/utils/command/datatypes/ForBlockOptionalMeta.java @@ -1,23 +1,23 @@ package baritone.api.utils.command.datatypes; -import baritone.api.utils.BlockSelector; +import baritone.api.utils.BlockOptionalMeta; import baritone.api.utils.command.helpers.arguments.ArgConsumer; import java.util.stream.Stream; -public class ForBlockSelector implements IDatatypeFor { - public final BlockSelector selector; +public class ForBlockOptionalMeta implements IDatatypeFor { + public final BlockOptionalMeta selector; - public ForBlockSelector() { + public ForBlockOptionalMeta() { selector = null; } - public ForBlockSelector(ArgConsumer consumer) { - selector = new BlockSelector(consumer.getString()); + public ForBlockOptionalMeta(ArgConsumer consumer) { + selector = new BlockOptionalMeta(consumer.getString()); } @Override - public BlockSelector get() { + public BlockOptionalMeta get() { return selector; } diff --git a/src/api/java/baritone/api/utils/command/defaults/MineCommand.java b/src/api/java/baritone/api/utils/command/defaults/MineCommand.java index ec87dd753..1cd869d8e 100644 --- a/src/api/java/baritone/api/utils/command/defaults/MineCommand.java +++ b/src/api/java/baritone/api/utils/command/defaults/MineCommand.java @@ -18,12 +18,10 @@ package baritone.api.utils.command.defaults; import baritone.api.Settings; -import baritone.api.utils.BlockSelector; -import baritone.api.utils.CompositeBlockFilter; -import baritone.api.utils.IBlockFilter; +import baritone.api.utils.BlockOptionalMeta; import baritone.api.utils.command.Command; import baritone.api.utils.command.datatypes.BlockById; -import baritone.api.utils.command.datatypes.ForBlockSelector; +import baritone.api.utils.command.datatypes.ForBlockOptionalMeta; import baritone.api.utils.command.helpers.arguments.ArgConsumer; import java.util.ArrayList; @@ -41,15 +39,14 @@ public class MineCommand extends Command { protected void executed(String label, ArgConsumer args, Settings settings) { int quantity = args.getAsOrDefault(Integer.class, 0); args.requireMin(1); - List selectors = new ArrayList<>(); + List boms = new ArrayList<>(); while (args.has()) { - selectors.add(args.getDatatypeFor(ForBlockSelector.class)); + boms.add(args.getDatatypeFor(ForBlockOptionalMeta.class)); } - IBlockFilter filter = new CompositeBlockFilter(selectors); - baritone.getMineProcess().mine(quantity, filter); - logDirect(String.format("Mining %s", filter.toString())); + baritone.getMineProcess().mine(quantity, boms.toArray(new BlockOptionalMeta[0])); + logDirect(String.format("Mining %s", boms.toString())); } @Override diff --git a/src/api/java/baritone/api/utils/command/defaults/PauseResumeCommands.java b/src/api/java/baritone/api/utils/command/defaults/PauseResumeCommands.java index d7746623c..b0d2e1b58 100644 --- a/src/api/java/baritone/api/utils/command/defaults/PauseResumeCommands.java +++ b/src/api/java/baritone/api/utils/command/defaults/PauseResumeCommands.java @@ -28,6 +28,7 @@ public class PauseResumeCommands { public static Command pausedCommand; static { + // array for mutability, non-field so reflection can't touch it final boolean[] paused = {false}; BaritoneAPI.getProvider().getPrimaryBaritone().getPathingControlManager().registerProcess( diff --git a/src/launch/java/baritone/launch/mixins/MixinBitArray.java b/src/launch/java/baritone/launch/mixins/MixinBitArray.java new file mode 100644 index 000000000..54ead39a7 --- /dev/null +++ b/src/launch/java/baritone/launch/mixins/MixinBitArray.java @@ -0,0 +1,62 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.launch.mixins; + +import net.minecraft.util.BitArray; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(BitArray.class) +public abstract class MixinBitArray { + @Shadow + @Final + private long[] longArray; + + @Shadow + @Final + private int bitsPerEntry; + + @Shadow + @Final + private long maxEntryValue; + + /** + * why did mojang divide by 64 instead of shifting right by 6 (2^6=64)? + * why did mojang modulo by 64 instead of ANDing with 63? + * also removed validation check + * + * @author LoganDark + */ + @Overwrite + public int getAt(int index) { + final int b = bitsPerEntry; + final int i = index * b; + final int j = i >> 6; + final int l = i & 63; + final int k = ((index + 1) * b - 1) >> 6; + + if (j == k) { + return (int) (this.longArray[j] >>> l & maxEntryValue); + } else { + int i1 = 64 - l; + return (int) ((this.longArray[j] >>> l | longArray[k] << i1) & maxEntryValue); + } + } +} diff --git a/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java b/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java new file mode 100644 index 000000000..b419952dc --- /dev/null +++ b/src/launch/java/baritone/launch/mixins/MixinBlockStateContainer.java @@ -0,0 +1,42 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.launch.mixins; + +import baritone.utils.accessor.IBlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.BitArray; +import net.minecraft.world.chunk.BlockStateContainer; +import net.minecraft.world.chunk.IBlockStatePalette; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(BlockStateContainer.class) +public abstract class MixinBlockStateContainer implements IBlockStateContainer { + @Accessor + public abstract IBlockStatePalette getPalette(); + + @Accessor + public abstract BitArray getStorage(); + + @Override + @Unique + public IBlockState getFast(int x, int y, int z) { + return getPalette().getBlockState(getStorage().getAt(y << 8 | z << 4 | x)); + } +} diff --git a/src/launch/resources/mixins.baritone.json b/src/launch/resources/mixins.baritone.json index 1d1c356ba..c11162794 100644 --- a/src/launch/resources/mixins.baritone.json +++ b/src/launch/resources/mixins.baritone.json @@ -9,7 +9,9 @@ }, "client": [ "MixinAnvilChunkLoader", + "MixinBitArray", "MixinBlockPos", + "MixinBlockStateContainer", "MixinChatTabCompleter", "MixinChunkProviderClient", "MixinChunkProviderServer", diff --git a/src/main/java/baritone/cache/WorldScanner.java b/src/main/java/baritone/cache/WorldScanner.java index 22c042f77..365c8bf76 100644 --- a/src/main/java/baritone/cache/WorldScanner.java +++ b/src/main/java/baritone/cache/WorldScanner.java @@ -18,18 +18,21 @@ package baritone.cache; import baritone.api.cache.IWorldScanner; -import baritone.api.utils.IBlockFilter; +import baritone.api.utils.BlockOptionalMetaLookup; import baritone.api.utils.IPlayerContext; -import net.minecraft.block.Block; +import baritone.utils.accessor.IBlockStateContainer; import net.minecraft.block.state.IBlockState; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.chunk.BlockStateContainer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import java.util.stream.IntStream; public enum WorldScanner implements IWorldScanner { @@ -39,7 +42,7 @@ public enum WorldScanner implements IWorldScanner { private static final int[] DEFAULT_COORDINATE_ITERATION_ORDER = IntStream.range(0, 16).toArray(); @Override - public List scanChunkRadius(IPlayerContext ctx, IBlockFilter filter, int max, int yLevelThreshold, int maxSearchRadius) { + public List scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius) { ArrayList res = new ArrayList<>(); ChunkProviderClient chunkProvider = (ChunkProviderClient) ctx.world().getChunkProvider(); @@ -86,7 +89,7 @@ public enum WorldScanner implements IWorldScanner { } @Override - public List scanChunk(IPlayerContext ctx, IBlockFilter filter, ChunkPos pos, int max, int yLevelThreshold) { + public List scanChunk(IPlayerContext ctx, BlockOptionalMetaLookup filter, ChunkPos pos, int max, int yLevelThreshold) { ChunkProviderClient chunkProvider = (ChunkProviderClient) ctx.world().getChunkProvider(); Chunk chunk = chunkProvider.getLoadedChunk(pos.x, pos.z); int playerY = ctx.playerFeet().getY(); @@ -100,7 +103,7 @@ public enum WorldScanner implements IWorldScanner { return res; } - private boolean scanChunkInto(int chunkX, int chunkZ, Chunk chunk, IBlockFilter filter, Collection result, int max, int yLevelThreshold, int playerY, int[] coordinateIterationOrder) { + private boolean scanChunkInto(int chunkX, int chunkZ, Chunk chunk, BlockOptionalMetaLookup filter, Collection result, int max, int yLevelThreshold, int playerY, int[] coordinateIterationOrder) { ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray(); boolean foundWithinY = false; for (int yIndex = 0; yIndex < 16; yIndex++) { @@ -110,14 +113,14 @@ public enum WorldScanner implements IWorldScanner { continue; } int yReal = y0 << 4; - BlockStateContainer bsc = extendedblockstorage.getData(); + IBlockStateContainer bsc = (IBlockStateContainer) extendedblockstorage.getData(); // the mapping of BlockStateContainer.getIndex from xyz to index is y << 8 | z << 4 | x; // for better cache locality, iterate in that order for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - IBlockState state = bsc.get(x, y, z); - if (filter.selected(state)) { + IBlockState state = bsc.getFast(x, y, z); + if (filter.has(state)) { int yy = yReal | y; if (result.size() >= max) { if (Math.abs(yy - playerY) < yLevelThreshold) { diff --git a/src/main/java/baritone/process/FarmProcess.java b/src/main/java/baritone/process/FarmProcess.java index e78c0ce1f..00273a9f4 100644 --- a/src/main/java/baritone/process/FarmProcess.java +++ b/src/main/java/baritone/process/FarmProcess.java @@ -24,7 +24,6 @@ import baritone.api.pathing.goals.GoalComposite; import baritone.api.process.IFarmProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; -import baritone.api.utils.BlockListFilter; import baritone.api.utils.RayTraceUtils; import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; @@ -181,7 +180,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } if (Baritone.settings().mineGoalUpdateInterval.value != 0 && tickCount++ % Baritone.settings().mineGoalUpdateInterval.value == 0) { - Baritone.getExecutor().execute(() -> locations = WorldScanner.INSTANCE.scanChunkRadius(ctx, new BlockListFilter(scan), 256, 10, 10)); + Baritone.getExecutor().execute(() -> locations = WorldScanner.INSTANCE.scanChunkRadius(ctx, scan, 256, 10, 10)); } if (locations == null) { return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index 755f27c2a..c891f1098 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -22,7 +22,7 @@ import baritone.api.pathing.goals.*; import baritone.api.process.IGetToBlockProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; -import baritone.api.utils.BlockListFilter; +import baritone.api.utils.BlockOptionalMetaLookup; import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; import baritone.api.utils.input.Input; @@ -172,7 +172,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG } private synchronized void rescan(List known, CalculationContext context) { - List positions = MineProcess.searchWorld(context, new BlockListFilter(gettingTo), 64, known, blacklist); + List positions = MineProcess.searchWorld(context, new BlockOptionalMetaLookup(gettingTo), 64, known, blacklist); positions.removeIf(blacklist::contains); knownLocations = positions; } diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 1b3ef0f14..7e59bc926 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -18,37 +18,42 @@ package baritone.process; import baritone.Baritone; -import baritone.api.pathing.goals.*; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalBlock; +import baritone.api.pathing.goals.GoalComposite; +import baritone.api.pathing.goals.GoalRunAway; +import baritone.api.pathing.goals.GoalTwoBlocks; import baritone.api.process.IMineProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; -import baritone.api.utils.BlockSelector; -import baritone.api.utils.BlockUtils; -import baritone.api.utils.CompositeBlockFilter; -import baritone.api.utils.IBlockFilter; +import baritone.api.utils.BlockOptionalMeta; +import baritone.api.utils.BlockOptionalMetaLookup; import baritone.api.utils.IPlayerContext; import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; 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; import baritone.utils.BlockStateInterface; -import net.minecraft.block.Block; import net.minecraft.block.BlockAir; import net.minecraft.block.BlockFalling; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import static baritone.api.pathing.movement.ActionCosts.COST_INF; @@ -59,10 +64,9 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF; * @author leijurv */ public final class MineProcess extends BaritoneProcessHelper implements IMineProcess { - private static final int ORE_LOCATIONS_COUNT = 64; - private IBlockFilter filter; + private BlockOptionalMetaLookup filter; private List knownOreLocations; private List blacklist; // inaccessible private BlockPos branchPoint; @@ -83,7 +87,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (desiredQuantity > 0) { int curr = ctx.player().inventory.mainInventory.stream() - .filter(stack -> filter.selected(BlockSelector.stateFromItem(stack))) + .filter(stack -> filter.has(BlockOptionalMeta.blockStateFromStack(stack))) .mapToInt(ItemStack::getCount).sum(); System.out.println("Currently have " + curr + " valid items"); if (curr >= desiredQuantity) { @@ -150,7 +154,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro @Override public void onLostControl() { - mine(0, (IBlockFilter) null); + mine(0, (BlockOptionalMetaLookup) null); } @Override @@ -223,7 +227,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro if (Baritone.settings().internalMiningAirException.value && state.getBlock() instanceof BlockAir) { return true; } - return filter.selected(state); + return filter.has(state); } private Goal coalesce(BlockPos loc, List locs) { @@ -288,7 +292,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } } - public static List droppedItemsScan(IBlockFilter filter, World world) { + public static List droppedItemsScan(BlockOptionalMetaLookup filter, World world) { if (!Baritone.settings().mineScanDroppedItems.value) { return Collections.emptyList(); } @@ -297,9 +301,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro if (entity instanceof EntityItem) { EntityItem ei = (EntityItem) entity; ItemStack stack = ei.getItem(); - Item item = stack.getItem(); - //noinspection deprecation - if (filter.selected(Block.getBlockFromItem(item).getStateFromMeta(stack.getItemDamage()))) { + if (filter.has(BlockOptionalMeta.blockStateFromStack(stack))) { ret.add(new BlockPos(entity)); } } @@ -307,7 +309,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return ret; } - public static List searchWorld(CalculationContext ctx, IBlockFilter filter, int max, List alreadyKnown, List blacklist) { + public static List searchWorld(CalculationContext ctx, BlockOptionalMetaLookup filter, int max, List alreadyKnown, List blacklist) { List locs = new ArrayList<>(); locs = prune(ctx, locs, filter, max, blacklist); locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(ctx.getBaritone().getPlayerContext(), filter, max, 10, 32)); // maxSearchRadius is NOT sq @@ -326,7 +328,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro for (int z = playerFeet.getZ() - searchDist; z <= playerFeet.getZ() + searchDist; z++) { // crucial to only add blocks we can see because otherwise this // is an x-ray and it'll get caught - if (filter.selected(bsi.get0(x, y, z))) { + if (filter.has(bsi.get0(x, y, z))) { BlockPos pos = new BlockPos(x, y, z); if ((Baritone.settings().legitMineIncludeDiagonals.value && knownOreLocations.stream().anyMatch(ore -> ore.distanceSq(pos) <= 2 /* sq means this is pytha dist <= sqrt(2) */)) || RotationUtils.reachable(ctx.player(), pos, fakedBlockReachDistance).isPresent()) { knownOreLocations.add(pos); @@ -338,30 +340,30 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist); } - private static List prune(CalculationContext ctx, List locs2, IBlockFilter filter, int max, List blacklist) { + private static List prune(CalculationContext ctx, List locs2, BlockOptionalMetaLookup filter, int max, List blacklist) { List dropped = droppedItemsScan(filter, ctx.world); dropped.removeIf(drop -> { for (BlockPos pos : locs2) { - if (pos.distanceSq(drop) <= 9 && filter.selected(ctx.get(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx, pos)) { // TODO maybe drop also has to be supported? no lava below? + if (pos.distanceSq(drop) <= 9 && filter.has(ctx.get(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx, pos)) { // TODO maybe drop also has to be supported? no lava below? return true; } } return false; }); List locs = locs2 - .stream() - .distinct() + .stream() + .distinct() - // remove any that are within loaded chunks that aren't actually what we want - .filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || filter.selected(ctx.get(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos)) + // remove any that are within loaded chunks that aren't actually what we want + .filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || filter.has(ctx.get(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos)) - // remove any that are implausible to mine (encased in bedrock, or touching lava) - .filter(pos -> MineProcess.plausibleToBreak(ctx, pos)) + // remove any that are implausible to mine (encased in bedrock, or touching lava) + .filter(pos -> MineProcess.plausibleToBreak(ctx, pos)) - .filter(pos -> !blacklist.contains(pos)) + .filter(pos -> !blacklist.contains(pos)) - .sorted(Comparator.comparingDouble(ctx.getBaritone().getPlayerContext().player()::getDistanceSq)) - .collect(Collectors.toList()); + .sorted(Comparator.comparingDouble(ctx.getBaritone().getPlayerContext().player()::getDistanceSq)) + .collect(Collectors.toList()); if (locs.size() > max) { return locs.subList(0, max); @@ -380,15 +382,15 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro @Override public void mineByName(int quantity, String... blocks) { - mine(quantity, new CompositeBlockFilter( + mine(quantity, new BlockOptionalMetaLookup( Arrays.stream(Objects.requireNonNull(blocks)) - .map(BlockSelector::new) - .toArray(IBlockFilter[]::new) + .map(BlockOptionalMeta::new) + .toArray(BlockOptionalMeta[]::new) )); } @Override - public void mine(int quantity, IBlockFilter filter) { + public void mine(int quantity, BlockOptionalMetaLookup filter) { this.filter = filter; if (filter != null && !Baritone.settings().allowBreak.value) { logDirect("Unable to mine when allowBreak is false!"); diff --git a/src/main/java/baritone/utils/accessor/IBlockStateContainer.java b/src/main/java/baritone/utils/accessor/IBlockStateContainer.java new file mode 100644 index 000000000..735e183a8 --- /dev/null +++ b/src/main/java/baritone/utils/accessor/IBlockStateContainer.java @@ -0,0 +1,13 @@ +package baritone.utils.accessor; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.util.BitArray; +import net.minecraft.world.chunk.IBlockStatePalette; + +public interface IBlockStateContainer { + IBlockStatePalette getPalette(); + + BitArray getStorage(); + + IBlockState getFast(int x, int y, int z); +}