Expressions
Commander introduces support for evaluating math expressions with dynamic context data.
Expressions use EvalEx for evaluation, it may be useful to familiarize yourself with it. One major difference is that all function, variable, contant names are case-sensitive and all funtion names are camelCase and not UPPER_SNAKE_CASE.
Additional functions and operators
Commander adds some additional functions to EvalEx.
A "Lambda" here means a regular expression, but with the it
parameter. Example: arrayFind(arrayOf(0, 1, 2), it == 1)
. Lambda parameters are marked with λ
.
Variable Arguments (VarArgs) are marked with ...
. (This means you can specify as many arguments as you need)
Math
Function | Description | Arguments | Example |
---|---|---|---|
random | Generates a random number in range. | min , max | random(0, 23) |
clamp | Clamps the value between two other arguments. | value , min , max | clamp(12, 14, 16) |
lerp | Smoothly progresses the value to the target. | delta , start , end | lerp(0.5, 10, 16) |
Arrays
All functions construct new arrays and do not mutate the original array.
Function | Description | Arguments | Example |
---|---|---|---|
arrayOf | Construct an array from the specified objects. | args... | arrayOf(0, 23) |
arrayMap | Mutates all objects in this array. | array , function(λ) | arrayMap(arrayOf(0,1,2), sqrt(it)) |
arrayFind | Filters all objects not matching the predicate. | array , predicate(λ) | arrayFind(arrayOf(0,1,2), it == 1) |
arrayAnyMatch | Checks if any of the objects in this array match the predicate. | array , predicate(λ) | arrayAnyMatch(arrayOf(0,1,2), it == 1) |
arrayNoneMatch | Checks if none of the objects in this array match the predicate. | array , predicate(λ) | arrayNoneMatch(arrayOf(0,1,2), it == 1) |
arrayAllMatch | Checks if all objects in this array match the predicate. | array , predicate(λ) | arrayAllMatch(arrayOf(0,1,2), it == 1) |
arrayFindFirst | Returns the first object in the array or null if empty. | array | arrayFindFirst(arrayOf(0, 23)) |
Registries
Function | Description | Arguments | Example |
---|---|---|---|
Registry | Returns a static content registry | identifier | Registry('entity_type') |
Item | Returns an item from the registry | identifier | Item('diamond') |
Block | Returns a block from the registry | identifier | Block('chest') |
DynamicRegistry | Returns a dynamic content registry | identifier | DynamicRegistry('worldgen/biome') |
Biome | Returns a biome from the registry | identifier | Biome('the_void') |
DimensionType | Returns a dimension type from the registry | identifier | DimensionType('overworld') |
Misc
Function | Description | Arguments | Example |
---|---|---|---|
structContainsKey | Checks if a struct contains some key. | struct , key... | structContainsKey(block_state.properties, 'candles') |
hasContext | Checks if an expression parameter is available | key... | hasContext('tool') |
length | Returns the length of the specified object or 0. | value | length('Hello World!') |
strFormat | Formats a string according to the pattern. | pattern , args... | strFormat('Hello %s World!', 23) |
ifMatches | Simillar to built-in if , but with Lambdas. | value , predicate(λ) , ifTrue(λ) , ifFalse(λ) | ifMatches(arrayFind(arrayOf(0,1,2), it == 1), length(it) > 0, it[0], 0) |
chain | Chains multiple functions using lambdas. it is the last result. | value , actions(λ)... | chain(23, it + 3, sqrt(it)) |
Operators
Function | Description | Arguments | Example |
---|---|---|---|
?. | Attempts to get a field from a structure or returns null | struct , key | struct?.field |
? | Returns b if a is null . a otherwise. | a , b | struct?.y ? 5 |
Context data access
Because Expressions require minecraft's loot context, you can read source data using a special syntax.
identifier.field
identifier.method
identifier.method.field.method
Keep in mind that requested fields and context must be present. Expression will fail without them.
Some examples:
minecraft:this_entity.getX
this_entity.getHealth
minecraft:this_entity.isInWaterOrRain
this_entity.blockPosition.getX
origin.x
origin.reverse.y
minecraft:level.getDayTime
Commander Extensions:
Commander adds special fields to objects to extend expression capabilities.
nbt
(Stacks, Entities, Block Entities)
Added to item stacks, entities, and block entities. Allows you to read the NBT of an object. While this can be convenient, NBT access is not fast, and when used in frequently invoked places (like tick events), can bring the game to a halt.
Example: this_entity.nbt.Air
properties
(Block States)
Added to states, like block states.
Example: block_state.properties.candles
attributes
(Living Entities)
Allows you to access entity attributes. The key is an identifier, so both generic.luck
and minecraft:generic.luck
are acceptible.
Example: this_entity.attributes.'generic.luck'
storage
(Levels, Chunks, Entities, Block Entities)
Allows you to access persistent data storage. The data is modified and written by /cmd:data
P.S.
If you have to do a lot of expensive operations in expressions in tick events, you should delay the execution, if possible, by checking level.getDayTime % 20 == 0
, this will make sure that the expression is executed every second and not 20 times per second. % 40
is every 2 seconds and % 10
is every 1/2 second.
Expressions use Mojang Mappings (downloaded on first load), this means that almost all public fields and getter methods are available in expressions. If Commander fails to setup mappings, you'll have to rely on platform names. (e.g. intermediary on Fabric)
Random examples
Default minecart speed is computed using this formula:
if(this_entity.isInWater, 4, 8) / 20
, and furnace: if(this_entity.isInWater, 3, 4) / 20
This ridicilous expression can print the current level time in human time. https://bukkit.org/threads/how-can-i-convert-minecraft-long-time-to-real-hours-and-minutes.122912/
strFormat('%02.0f:%02.0f', floor((level.getDayTime / 1000 + 8) % 24), floor(60 * (level.getDayTime % 1000) / 1000))
So the output can be: 00:00
, or 13:45
, etc.
Using Expressions
The fastest way to get started is to use the cmd:arithmetica
command. You should wrap your expression with "
to satisfy Brigadier.
Other places you can use expressions in:
JSON Command Macros
Command Macros are explained in detail on the Commands page. Link
Loot number provider
Using the commander:arithmetica
provider in conditions:
{
"condition": "minecraft:value_check",
"value": {
"type": "commander:arithmetica",
"value": "round(random(5, 15))"
},
"range": {
"min": 12.3,
"max": 32
}
}
Loot predicate
Using the commander:expression
predicate:
{
"condition": "commander:expression",
"value": "level.isDay"
}
execute
command
You can use expressions as predicates in the execute if
command.
/execute if cmd:expression "level.isDay" run say It is day!
scoreboard players
command
You can use expressions as modifiers for player predicates. score
variable allows you to get the current score.
The current version does not provide entity context.
/scoreboard players cmd:operate @s test_objective "(score * 1.5) + level.storage.my_score_modifier"