An item to break only SPECIFIED blocks?
Solution 1:
Use the CanDestroy tag on tools:
/give @p minecraft:diamond_pickaxe 1 0 {CanDestroy:["minecraft:stone","minecraft:stonebrick"]}
This will give you an diamond pickaxe that can only break stone and stone bricks.
This will only work in adventure mode.
Solution 2:
This is not what the original asker meant, but since a bounty asks this, I'll answer it anyway: How to do this for Survival mode?
The short answer: This feature does not exist. And usually it's also not useful, because the player could simply switch to another tool to be able to mine again. You should consider putting the player into Adventure mode instead, maybe the Survival features you want are easier and more reliably reproducible with commands. Or maybe switch between Survival and Adventure depending on the held tool.
The long answer: Almost anything is possible in Minecraft, so you can fake it (with some issues), if you want to do that anyway:
Firstly, you can't use attributes (archive), because they're always active when the item is held, no matter which block the player is trying to mine. effect.digSpeed
might also not be available to item-caused or command-caused attribute changes, because it's not available in /attribute
.
So you need to detect when the player holds that item with commands. This is done with the player's SelectedItem
NBT tag. What exactly you want to match is arbitrary, let's say it's a golden hoe named "Horst" that has the custom tag foo:1b
(which is meaningless outside of this command system). Then you can select every player holding such an item in their main hand (offhand doesn't matter for mining) like this:
@a[nbt={SelectedItem:{id:"minecraft:golden_hoe",tag:{display:{Name:"{\"text\":\"Horst\"}"},foo:1b}}}]
As usual in NBT matching, everything needs to be matched exactly, for example minecraft:
in the item ID, the brackets in the name's JSON and the byte type of the custom field.
Next, detecting which block the player is looking at. This requires "raytracing", which I have an answer for here. In short, you can use either a dummy entity, if you use command blocks, or just the execution position in a function and move that forwards in the view direction bit by bit until you hit a block that is not air or water or lava. This isn't perfect, because the player could for example look either at a sign or sideways past it, but doing it perfectly would require doing special calculations for a variable step size and to put every block hitbox into the datapack/command block system. I have heard that someone might have done that in the past, but I can't find such a datapack online. Also note that entities can be in the way, which changes the intended result again, but raytracing usually ignores those as well.
Finally, making it impossible to mine: You can't quite prevent mining completely with the Mining fatigue effect, but you can at least slow it down by a factor of 1234.5 with an effect level of 4 or more (source, archive). If you want to prevent really dedicated players from e.g. breaking a single carpet in over 3 minutes, you can shortly use /clone … replace move
to move it somewhere else and then move it back one tick later. Replacing it with another block does not help, because the mining progress gets saved even when the block changes.
One problem that remains are instant-mineable blocks: most plants, both torches, End rods, fire, flower pots, honey, comparators, repeaters, redstone, scaffolding, slime, structure void (for some reason), TNT, tripwire and hooks. Those can be broken instantly under all circumstances (except Adventure and Spectator mode), which means that this method doesn't prevent breaking them either regularly or in the short phase when the targeted block is moved as written above, if the instant-mineable block is behind it. The only way to "fix" this is by placing it again after the player breaks it. The raytracing part already figures out which block it is, so this can be used to place it again as well. But it can cause glitchy movement if it's the block the player is standing on and it's even possible to turn towards a block client-side in the 0.05s between server ticks and break it before the next tick happens, in which case the broken block is not the one that the server thinks the player targeted. (That's also how https://bugs.mojang.com/browse/MC-12363 happens.) Unlike placed_block
, there is also no advancement criterium for breaking an arbitrary block, so you can't make sure to match the right one that way either. This is just an issue that remains in this system, I don't think it's fixeable.
So, in short: Detect holding the item with SelectedItem
in an NBT selector, then use raytracing to find (hopefully) the targeted block, give Mining fatigue to slow down mining a lot and maybe also move the block away and back every 3 minutes against really patient miners. This is not perfect, but it works alright most of the time.