Skip to main content

Selectors

You can use Sandstone to create any selector, in an easy and type-safe way.

The basics

General Syntax

To create a selector, you need to provide the target and the arguments to Selector:

import { Selector } from 'sandstone'

Selector('@a', { /** Arguments */ })

The first part is the targets: it can be @s, @r, @p, @a or @e. The second part is the arguments. In this object, you can specify any property that would fit into a vanilla selector:

Selector('@e', { type: 'minecraft:cow', limit: 1, sort: 'random' })

Usage

To use selectors, you need to assign them to a variable, and pass them to a command:

// Kill all cows
const cows = Selector('@e', { type: 'minecraft:cow' })
kill(cows)

// Give 32 diamonds to winners
const winners = Selector('@e', { tag: 'winner' })
give(winners, 'minecraft:diamond', 32)

Special Arguments

While most arguments work exactly like the vanilla ones, some of them have a few particularities.

Scores

General syntax

For the scores argument, you can specify a whole number or a range. Ranges are made using an array: [0, 7] becomes 0..7. If you need an open-ended range (like 8.. or ..19), you can use null or Infinity:

  • [8, null] and [8, +Infinity] both become 8..
  • [null, 19] and [-Infinity, 19] both become ..19

Here is an exemple of a selector that checks if a player has more than 10 kills, less than 50 coins and exactly 0 deaths:

Selector('@s', {
scores: {
'kills': [10, +Infinity],
'coins': [-Infinity, 50],
'deaths': 0,
}
})

Matching a Sandstone objective

If you want to use an existing objective, you can use the following ES6 syntax:

const killsObjective = createObjective('kills', 'playerKillCount')

Selector('@s', {
scores: {
[killsObjective.name]: [10, +Infinity],
}
})

Advancements

General syntax

Advancements arguments in Sandstone selectors work precisely like they would in-game, but their complicated syntax deserves a reminder.

To ensure the player has the minecraft:story:/form_obsidian advancement, you would use the following syntax:

Selector('@s', {
advancements: {
'story/form_obsidian': true,
}
})

To select player who wore at least once a full iron armor, you would do:

Selector('@s', {
advancements: {
'story/obtain_armor': true,
}
})

Matching a criteria

To select players who wore at least once a iron helmet, you would do:

Selector('@s', {
advancements: {
'story/obtain_armor': {
'iron_helmet': true,
},
}
})

As you can see, matching a single (or several) advancements criteria is done using a nested object. In the end, the syntax could be defined as:

Selector('@s', {
advancements: {
// Matches a whole advancement
'<advancement name>': boolean,
// Matches some advancement criterion
'<advancement name>': {
'<criteria 1>': boolean,
'<criteria 2>': boolean,
}
}
})

Matching a Sandstone Advancement

In order to use a Sandstone advancement in a selector, you can use the following ES6 syntax:

const myAdvancement = Advancement('myAdvancement', ...)

Selector('@s', {
advancements: {
[myAdvancement.name]: true,
}
})

Tags

Entity tags can be either specified as a single string, or an array of strings.

// Will compile to `@a[tag=single_tag]`
Selector('@a', { tag: 'single_tag' })

// Will compile to `@a[tag=tag1,tag=tag2]`
Selector('@a', { tag: ['tag1', 'tag2'] })

Predicates

General Syntax

Just like tags, you can match one or several predicates at once. This is done using a string or an array of strings.

// Will compile to `@a[predicate=mypredicate]`
Selector('@a', { predicate: 'mypredicate' })

// Will compile to `@a[predicate=first_predicate,predicate=second_predicate]`
Selector('@a', { predicate: ['first_predicate', 'second_predicate'] })

Matching a Sandstone Predicate

In order to use a Sandstone predicate in a selector, you just need to use the variable like you would use a string:

const myPredicate = Predicate('mypredicate', ...)

// To match a single predicate
Selector('@s', { predicate: myPredicate })

// To match several predicates
Selector('@s', { predicate: [myPredicate, 'predicate2'] })

Team

The team argument has the same syntax than the vanilla one, but has a built-in feature to check for the lack or the presence of a team. You can use true to check for entities having a team, and false for entities that are not inside a team.

// Check for entities inside the "red" team
Selector('@e', { team: 'red' })

// Check for entities NOT inside the "red" team
Selector('@e', { team: '!red' })

// Check for entities that aren't inside a team
Selector('@e', { team: false })

// Check for entities that are inside a team
Selector('@e', { team: true })