Skip to content

Commit

Permalink
Fixed block name autocomplete / name checking. Fixes #52
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Zangl committed Jan 12, 2016
1 parent 4c3aa2f commit 9057cf2
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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();
Expand All @@ -48,7 +60,7 @@ public boolean matches(BlockWithDataOrDontcare b) {

boolean optional() default false;

Class<? extends BlockFilter> blockFilter() default AnyBlockFilter.class;
Class<? extends BlockFilter> blockFilter() default SurvivalBlockFilter.class;

String relativeToSettingsFile() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<String> 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<ResourceLocation> keys = Block.blockRegistry.getKeys();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,127 @@
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 {
return BlockWithData.fromNiceMeta(block, matcher.group(2));
}
}

public static ArrayList<String> getAllStrings() {
Set<ResourceLocation> keys = Block.blockRegistry.getKeys();
ArrayList<String> strings = new ArrayList<>();
for (ResourceLocation k : keys) {
// candidate found
strings.add(k.toString());

Block b = (Block) Block.blockRegistry.getObject(k);
HashSet<IBlockState> states = new HashSet<IBlockState>();
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());
}
Expand Down Expand Up @@ -72,4 +152,5 @@ protected String getBlockString() {
public abstract boolean containedIn(BlockSet blockSet);

public abstract ItemWithSubtype getItemType();

}

1 comment on commit 9057cf2

@iAmRinzler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured this was the case since I noticed it was allowing things like 'Pepsi' as a block name which would begin a bad loop.

Nice fix.

Please sign in to comment.