Mob mainhand and offhand item detection

Summoning a husk with an nbt of HandItems:[{id:"minecraft:stick"},{}] spawns a husk holding a stick in its mainhand but using it on an execute command to check the entity also works on a husk holding a stick in its offhand. The command that I used:

/execute as @e[type=husk,nbt={HandItems:[{id:"minecraft:stick"},{}]}] run say I have a stick in my mainhand!

But

/execute as @e[type=husk,nbt={HandItems:[{},{id:"minecraft:stick"}]}] run say I have a stick in my mainhand!

also works.

I want to check if a husk is holding a stick in its mainhand but I can't figure out the exact command to do what I want.


Solution 1:

Firstly, you forgot the stack size:

/summon husk ~ ~ ~ {HandItems:[{id:"stick",Count:1},{}]}

Secondly, there are two very similar syntaxes, which causes this unintuitive behaviour: When summoning an entity, [{},{}] creates a list with two entries. But when checking for NBT, the same syntax checks for the presence of the two entries in the list. And both {}, meaning any entry, and {id:"minecraft:stick"}, meaning an entry with key id and value "minecraft:stick" are matched, so the command runs.

How to actually check for the correct index: Normally you could just use /execute if data, but due to an oversight in the NBT path syntax, a path like HandItems[1]{id:"minecraft:stick"} does not work. What you need to do instead is copying the NBT somewhere else and then checking there.

The proper way to do this is to create a datapack and run a function as the husk, that way you can check the NBT without interfering with anything in the world by using storage:

data modify storage temp Mainhand set from entity @s HandItems[0]
execute if data storage temp Mainhand{id:"minecraft:stick"} run say I have a stick in my mainhand!
data remove storage temp Mainhand

The hacky way to do this does not require a datapack, but it modifies the held item. The tag tag of items can contain any arbitrary NBT, so you can copy the entire item NBT into a sub-tag of the item NBT. Yes, that's stupid, but it doesn't require a datapack. If you just want something copy-paste ready, this is for you:

/execute as @e[type=husk] run data modify entity @s HandItems[0].tag.temp set from entity @s HandItems[0]
/execute as @e[type=husk,nbt={HandItems:[{tag:{temp:{id:"minecraft:stick"}}}]}] run say I have a stick in my mainhand!
/execute as @e[type=husk] run data remove entity @s HandItems[0].tag.temp

Thanks to vdvman1 and PeerHeer in the Minecraft commands Discord group for their help with this answer!