Is there a way to match multiple tags in a target selector?

While working on my answer to this question, I came across the situation where I'd like to match multiple scoreboard tags at once, i.e. do something like

/tell @a[tag=Great,tag=Awesome] You are a great and awesome person!

The above command does not work as intended (tested on snapshot 15w45a), since the second tag target selector argument overwrites the first (the same behavior as on every other argument). This means that simply awesome (but not great) persons are called awesome and great, rather than those that are both awesome and great!

Is there a way to include multiple tag matches into the same target selector?


Solution 1:

A workaround to the problem can be achieved via data tag matching. All entities have a Tags tag that contains all scoreboard tags of that entity. On commands that support data tag matching (such as testfor and scoreboard players), you can directly check if multiple tags are present, e.g.

/testfor @a {Tags:["Great","Awesome"]}

Due to Minecraft's partial tag matching, this will also work if the target entity has other tags beside Great and Awesome.

For commands that do not support data tag matching themselves, a meta-tag can be added, e.g.

/scoreboard players tag @a[tag=GreatAndAwesome] remove GreatAndAwesome
/scoreboard players tag @a[tag=!GreatAndAwesome] add GreatAndAwesome {Tags:["Great","Awesome"]}

Afterwards, a simple tag check can be performed for GreatAndAwesome. However, this adds 2 commands for every meta-tag, and does not easily support negation (i.e. check if an entity is Great but not Awesome). As such, using the pre-1.9 method of dummy objectives set to 0 or 1 is often preferable to a tag (since scoreboard objectives each come with their own target selector arguments), though much less elegant.

Solution 2:

Alternatively, you could use an execute command to first select players with one of the tags, then execute your command for players with the second tag in a radius of 0.

For your example:

/execute @a[tag=Great] ~ ~ ~ tell @a[r=0,tag=Awesome] You are a great and awesome person!

This solution is not 100% perfect; if two players are standing in the same place, only one of them has to have the Great tag for them all to match the second command. However, if you know that there is a small chance that two players will be in the same place, or you can somehow narrow down the selectors even more, this provides a solution in only one command block.