diff --git a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlock.java b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlock.java
index 5006ac0..46ea103 100644
--- a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlock.java
+++ b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlock.java
@@ -4,6 +4,8 @@
import org.bukkit.Bukkit;
import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Tag;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -69,9 +71,7 @@ public default int compareTo(@Nullable VeinMinerBlock other) {
}
/**
- * Get a {@link VeinMinerBlock} from a string.
- *
- * Example states:
+ * Get a {@link VeinMinerBlock} from a string. Example states:
*
* chest
* minecraft:chest
@@ -79,6 +79,7 @@ public default int compareTo(@Nullable VeinMinerBlock other) {
* minecraft:chest[facing=north,waterlogged=true]
* * // The wildcard state
*
+ * This method will also support a tag key such as {@code #minecraft:leaves}.
*
* @param string the string from which to parse a VeinMinerBlock instance
*
@@ -90,6 +91,21 @@ public static VeinMinerBlock fromString(@NotNull String string) {
return WILDCARD;
}
+ if (string.startsWith("#")) {
+ // TODO: Use the new tag system
+ NamespacedKey tagKey = NamespacedKey.fromString(string.substring(1));
+ if (tagKey == null) {
+ return null;
+ }
+
+ Tag tag = Bukkit.getTag("blocks", tagKey, Material.class);
+ if (tag == null) {
+ return null;
+ }
+
+ return new VeinMinerBlockTag(tag);
+ }
+
Matcher matcher = VeinMiner.PATTERN_BLOCK_STATE.matcher(string);
if (!matcher.find()) {
return null;
diff --git a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlockTag.java b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlockTag.java
new file mode 100644
index 0000000..7ade230
--- /dev/null
+++ b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/block/VeinMinerBlockTag.java
@@ -0,0 +1,59 @@
+package wtf.choco.veinminer.block;
+
+import org.bukkit.Material;
+import org.bukkit.Tag;
+import org.bukkit.block.data.BlockData;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A type of {@link VeinMinerBlock} backed by a block {@link Tag}.
+ */
+public final class VeinMinerBlockTag implements VeinMinerBlock {
+
+ private final Tag tag;
+
+ /**
+ * Construct a new {@link VeinMinerBlockTag}.
+ *
+ * @param tag the block tag
+ */
+ public VeinMinerBlockTag(Tag tag) {
+ this.tag = tag;
+ }
+
+ public Tag getTag() {
+ return tag;
+ }
+
+ @Override
+ public boolean matchesType(@NotNull Material type) {
+ return tag.isTagged(type);
+ }
+
+ @Override
+ public boolean matchesState(@NotNull BlockData state, boolean exact) {
+ return matchesType(state.getMaterial());
+ }
+
+ @NotNull
+ @Override
+ public String toStateString() {
+ return "#" + tag.getKey().toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return tag.getKey().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this || (obj instanceof VeinMinerBlockTag other && tag.getKey().equals(other.tag.getKey()));
+ }
+
+ @Override
+ public String toString() {
+ return String.format("VeinMinerBlockTag[type=\"%s\"]", tag.getKey().toString());
+ }
+
+}
diff --git a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/command/CommandBlocklist.java b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/command/CommandBlocklist.java
index 4aa726c..1609ee6 100644
--- a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/command/CommandBlocklist.java
+++ b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/command/CommandBlocklist.java
@@ -59,7 +59,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
String blockArg = args[2].toLowerCase();
VeinMinerBlock block = VeinMinerBlock.fromString(blockArg);
if (block == null) {
- sender.sendMessage(ChatColor.RED + "Unknown block type/block state (was it an item)? " + ChatColor.GRAY + "Given " + ChatColor.YELLOW + blockArg + ChatColor.GRAY + ".");
+ sender.sendMessage(ChatColor.RED + "Unknown block type, state, or tag (was it an item)? " + ChatColor.GRAY + "Given " + ChatColor.YELLOW + blockArg + ChatColor.GRAY + ".");
return true;
}
@@ -86,7 +86,7 @@ else if (args[1].equalsIgnoreCase("remove")) {
String blockArg = args[2].toLowerCase();
VeinMinerBlock block = VeinMinerBlock.fromString(blockArg);
if (block == null) {
- sender.sendMessage(ChatColor.RED + "Unknown block type/block state (was it an item)? " + ChatColor.GRAY + "Given " + ChatColor.YELLOW + blockArg + ChatColor.GRAY + ".");
+ sender.sendMessage(ChatColor.RED + "Unknown block type, state, or tag (was it an item)? " + ChatColor.GRAY + "Given " + ChatColor.YELLOW + blockArg + ChatColor.GRAY + ".");
return true;
}
diff --git a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/pattern/PatternUtils.java b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/pattern/PatternUtils.java
index b79a287..4e14772 100644
--- a/veinminer-bukkit/src/main/java/wtf/choco/veinminer/pattern/PatternUtils.java
+++ b/veinminer-bukkit/src/main/java/wtf/choco/veinminer/pattern/PatternUtils.java
@@ -6,6 +6,7 @@
import wtf.choco.veinminer.block.BlockList;
import wtf.choco.veinminer.block.VeinMinerBlock;
+import wtf.choco.veinminer.block.VeinMinerBlockTag;
import wtf.choco.veinminer.block.VeinMinerBlockWildcard;
/**
@@ -29,7 +30,7 @@ private PatternUtils() { }
* false otherwise
*/
public static boolean typeMatches(@NotNull VeinMinerBlock block, @Nullable BlockList aliasList, @NotNull BlockData origin, @NotNull BlockData current) {
- if (block instanceof VeinMinerBlockWildcard) {
+ if (block instanceof VeinMinerBlockWildcard || block instanceof VeinMinerBlockTag) {
return origin.getMaterial() == current.getMaterial() || (aliasList != null && aliasList.containsState(current));
}
diff --git a/veinminer-bukkit/src/main/resources/categories.yml b/veinminer-bukkit/src/main/resources/categories.yml
index e71b936..5453243 100644
--- a/veinminer-bukkit/src/main/resources/categories.yml
+++ b/veinminer-bukkit/src/main/resources/categories.yml
@@ -3,7 +3,8 @@
# Block list values are 1:1 with in-game IDs. The prepending of "minecraft:" is optional.
# To specify states, do so with [brackets] as you would in a vanilla /setblock command. For
# example, "minecraft:chest[waterlogged=true]" will search for any waterlogged chests. Other
-# undefined states will be ignored when checking.
+# undefined states will be ignored when checking. Tag keys may also be specified if desired
+# by prepending the key with a #. For example, '#minecraft:logs' will reference all log blocks.
#
# Each category may define any of the following options:
# "RepairFriendly", "MaxVeinSize", "Cost", and "DisabledWorlds"
@@ -108,61 +109,28 @@ Pickaxe:
- 'minecraft:diamond_pickaxe'
- 'minecraft:netherite_pickaxe'
BlockList:
+ - '#minecraft:coal_ores'
+ - '#minecraft:copper_ores'
+ - '#minecraft:diamond_ores'
+ - '#minecraft:emerald_ores'
+ - '#minecraft:gold_ores'
+ - '#minecraft:iron_ores'
+ - '#minecraft:lapis_ores'
+ - '#minecraft:redstone_ores'
- 'minecraft:amethyst_cluster'
- 'minecraft:ancient_debris'
- - 'minecraft:coal_ore'
- - 'minecraft:copper_ore'
- - 'minecraft:deepslate_coal_ore'
- - 'minecraft:deepslate_copper_ore'
- - 'minecraft:deepslate_diamond_ore'
- - 'minecraft:deepslate_emerald_ore'
- - 'minecraft:deepslate_gold_ore'
- - 'minecraft:deepslate_iron_ore'
- - 'minecraft:deepslate_lapis_ore'
- - 'minecraft:deepslate_redstone_ore'
- - 'minecraft:diamond_ore'
- - 'minecraft:emerald_ore'
- - 'minecraft:gold_ore'
- - 'minecraft:iron_ore'
- - 'minecraft:lapis_ore'
- - 'minecraft:nether_gold_ore'
- 'minecraft:nether_quartz_ore'
- 'minecraft:raw_copper_block'
- 'minecraft:raw_gold_block'
- 'minecraft:raw_iron_block'
- - 'minecraft:redstone_ore'
Shears:
Items:
- 'minecraft:shears'
BlockList:
- - 'minecraft:acacia_leaves'
- - 'minecraft:azalea_leaves'
- - 'minecraft:birch_leaves'
- - 'minecraft:black_wool'
- - 'minecraft:blue_wool'
- - 'minecraft:brown_wool'
- - 'minecraft:cherry_leaves'
+ - '#minecraft:leaves'
+ - '#minecraft:wool'
- 'minecraft:cobweb'
- - 'minecraft:cyan_wool'
- - 'minecraft:dark_oak_leaves'
- - 'minecraft:flowering_azalea_leaves'
- - 'minecraft:gray_wool'
- - 'minecraft:green_wool'
- - 'minecraft:jungle_leaves'
- - 'minecraft:light_blue_wool'
- - 'minecraft:light_gray_wool'
- - 'minecraft:lime_wool'
- - 'minecraft:magenta_wool'
- - 'minecraft:mangrove_leaves'
- - 'minecraft:oak_leaves'
- - 'minecraft:orange_wool'
- - 'minecraft:pink_wool'
- - 'minecraft:purple_wool'
- - 'minecraft:red_wool'
- - 'minecraft:spruce_leaves'
- - 'minecraft:white_wool'
- - 'minecraft:yellow_wool'
Shovel:
Items: