diff --git a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/AICommandParameter.java b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/AICommandParameter.java index 1bee18c8..9f3e96b6 100644 --- a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/AICommandParameter.java +++ b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/AICommandParameter.java @@ -21,6 +21,9 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import net.famzangl.minecraft.minebot.ai.path.world.BlockSet; +import net.minecraft.init.Blocks; + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface AICommandParameter { @@ -40,6 +43,15 @@ public boolean matches(BlockWithDataOrDontcare b) { } } + public static class SurvivalBlockFilter extends BlockFilter { + private static final BlockSet NON_SURVIVAL_BLOCKS = new BlockSet(Blocks.air, Blocks.command_block); + + @Override + public boolean matches(BlockWithDataOrDontcare b) { + return !NON_SURVIVAL_BLOCKS.contains(b); + } + } + ParameterType type(); String description(); @@ -48,7 +60,7 @@ public boolean matches(BlockWithDataOrDontcare b) { boolean optional() default false; - Class blockFilter() default AnyBlockFilter.class; + Class blockFilter() default SurvivalBlockFilter.class; String relativeToSettingsFile() default ""; } diff --git a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockNameBuilder.java b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockNameBuilder.java index 6db3ccba..1176bb2c 100644 --- a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockNameBuilder.java +++ b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockNameBuilder.java @@ -22,6 +22,7 @@ import net.famzangl.minecraft.minebot.ai.AIHelper; import net.famzangl.minecraft.minebot.ai.command.AICommandParameter.AnyBlockFilter; import net.famzangl.minecraft.minebot.ai.command.AICommandParameter.BlockFilter; +import net.famzangl.minecraft.minebot.ai.command.BlockWithDataOrDontcare.IllegalBlockNameException; import net.minecraft.util.ResourceLocation; public class BlockNameBuilder extends ParameterBuilder { @@ -53,14 +54,26 @@ public BlockArgumentDefinition(String description, @Override public boolean couldEvaluateAgainst(String string) { - BlockWithDataOrDontcare block = BlockWithDataOrDontcare.getFromString(string); - return block != null && blockFilter.matches(block); + try { + BlockWithDataOrDontcare block = BlockWithDataOrDontcare.getFromString(string); + return blockFilter.matches(block); + } catch (IllegalBlockNameException e) { + return false; + } } @Override public void getTabCompleteOptions(String currentStart, Collection addTo) { super.getTabCompleteOptions(currentStart, addTo); + + for (String s : BlockWithDataOrDontcare.getAllStrings()) { + String noPrefix = s.replaceFirst("^minecraft:", ""); + if (s.startsWith(currentStart) || noPrefix.startsWith(currentStart)) { + addTo.add(noPrefix); + } + } + // @SuppressWarnings("unchecked") // BIG TODO: Get a list of all blocks for tab complete. // final Set keys = Block.blockRegistry.getKeys(); diff --git a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithData.java b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithData.java index 710966b3..c307cad7 100644 --- a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithData.java +++ b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithData.java @@ -113,7 +113,7 @@ public String toBlockString() { return getBlockString() + ":" + getMetaString(); } - private String getMetaString() { + protected String getMetaString() { int value = getMetaValue(); int blockId = getBlockId(); for (NicerMetaValue n : nicerMeta) { diff --git a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithDataOrDontcare.java b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithDataOrDontcare.java index da7781f6..7e35bf2b 100644 --- a/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithDataOrDontcare.java +++ b/Minebot/src/net/famzangl/minecraft/minebot/ai/command/BlockWithDataOrDontcare.java @@ -1,40 +1,90 @@ package net.famzangl.minecraft.minebot.ai.command; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.famzangl.minecraft.minebot.ai.path.world.BlockSet; import net.famzangl.minecraft.minebot.ai.task.inventory.ItemWithSubtype; import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation; public abstract class BlockWithDataOrDontcare { + public static class IllegalBlockNameException extends + IllegalArgumentException { + + public IllegalBlockNameException() { + super(); + } + + public IllegalBlockNameException(String message, Throwable cause) { + super(message, cause); + } + + public IllegalBlockNameException(String s) { + super(s); + } + + public IllegalBlockNameException(Throwable cause) { + super(cause); + } + + @Override + public String toString() { + return "IllegalBlockNameException []"; + } + + } + + private static final BlockWithDataOrDontcare AIR = new BlockWithDontcare(0); protected final int blockIdWithMeta; public BlockWithDataOrDontcare(int blockWithMeta) { blockIdWithMeta = blockWithMeta; } + /** + * Convers a string to a block with data. Also accepts the blocktype:meta + * for specifying subtypes and prefixes. + * + * @param blockWithMeta + * The string to look up + * @return The BlockWithData object + * @throws IllegalBlockNameException + * For illegal input. + */ public static BlockWithDataOrDontcare getFromString(String blockWithMeta) { // Works on minecraft:dirt:1 - Matcher matcher = Pattern.compile("^(.+?)(?:\\:(.+))?$").matcher(blockWithMeta); + Matcher matcher = Pattern.compile("^([\\w\\:]+?)(?:\\:(\\w+))?$").matcher( + blockWithMeta); if (!matcher.matches()) { - throw new IllegalArgumentException( - "Illegal block name: " + blockWithMeta); + throw new IllegalBlockNameException("Illegal block name: " + + blockWithMeta); } + // Air handled specially. Minecraft returns it on invalid names. + if (Pattern.compile("^(minecraft\\:)air$").matcher(blockWithMeta) + .matches()) { + return AIR; + } + Block block = (Block) Block.blockRegistry.getObject(matcher.group(1)); - if (block == null) { + if (block == null || block == Blocks.air) { // minecraft:dirt case block = (Block) Block.blockRegistry.getObject(blockWithMeta); matcher = null; } - if (block == null) { - throw new IllegalArgumentException( + if (block == null || block == Blocks.air) { + throw new IllegalBlockNameException( "Could not understand block name: " + blockWithMeta); - } else if (matcher == null || matcher.group(2) == null || matcher.group(2).matches("\\*?")) { + } else if (matcher == null || matcher.group(2) == null + || matcher.group(2).matches("\\*?")) { return new BlockWithDontcare(block); - } else if (matcher.group(2).matches("(1[0-5]|\\d)")) { + } else if (matcher.group(2).matches("^(1[0-5]|\\d)$")) { int meta = Integer.parseInt(matcher.group(2)); return new BlockWithData(block, meta); } else { @@ -42,6 +92,36 @@ public static BlockWithDataOrDontcare getFromString(String blockWithMeta) { } } + public static ArrayList getAllStrings() { + Set keys = Block.blockRegistry.getKeys(); + ArrayList strings = new ArrayList<>(); + for (ResourceLocation k : keys) { + // candidate found + strings.add(k.toString()); + + Block b = (Block) Block.blockRegistry.getObject(k); + HashSet states = new HashSet(); + for (int i = 0; i < 16; i++) { + try { + IBlockState state = b.getStateFromMeta(i); + if (!states.contains(state)) { + states.add(state); + } + } catch (IllegalArgumentException e) { + // ignored + } + } + if (states.size() > 1) { + for (IBlockState state : states) { + BlockWithData withData = new BlockWithData(b, + b.getMetaFromState(state)); + strings.add(k + ":" + withData.getMetaString()); + } + } + } + return strings; + } + public Block getBlock() { return Block.getBlockById(getBlockId()); } @@ -72,4 +152,5 @@ protected String getBlockString() { public abstract boolean containedIn(BlockSet blockSet); public abstract ItemWithSubtype getItemType(); + }