1# Expressions 2 3Commander introduces support for evaluating math expressions with dynamic context data. 4 5Expressions use [EvalEx](https://ezylang.github.io/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. 6 7## Additional functions and operators 8 9Commander adds some additional functions to EvalEx. 10 11A "Lambda" here means a regular expression, but with the `it` parameter. Example: `arrayFind(arrayOf(0, 1, 2), it == 1)`. Lambda parameters are marked with `λ`. 12 13Variable Arguments (VarArgs) are marked with `...`. (This means you can specify as many arguments as you need) 14 15::: details Math 16 17| Function | Description | Arguments | Example | 18|---|---|---|---| 19| `random` | Generates a random number in range. | `min`, `max` | `random(0, 23)` | 20| `clamp` | Clamps the value between two other arguments. | `value`, `min`, `max` | `clamp(12, 14, 16)` | 21| `lerp` | Smoothly progresses the value to the target. | `delta`, `start`, `end` | `lerp(0.5, 10, 16)` | 22 23::: 24 25::: details Arrays 26 27All functions construct new arrays and do not mutate the original array. 28 29| Function | Description | Arguments | Example | 30|---|---|---|---| 31| `arrayOf` | Construct an array from the specified objects. | `args...` | `arrayOf(0, 23)` | 32| `arrayMap` | Mutates all objects in this array. | `array`, `function(λ)` | `arrayMap(arrayOf(0,1,2), sqrt(it))` | 33| `arrayFind` | Filters all objects not matching the predicate. | `array`, `predicate(λ)` | `arrayFind(arrayOf(0,1,2), it == 1)` | 34| `arrayAnyMatch` | Checks if any of the objects in this array match the predicate. | `array`, `predicate(λ)` | `arrayAnyMatch(arrayOf(0,1,2), it == 1)` | 35| `arrayNoneMatch` | Checks if none of the objects in this array match the predicate. | `array`, `predicate(λ)` | `arrayNoneMatch(arrayOf(0,1,2), it == 1)` | 36| `arrayAllMatch` | Checks if all objects in this array match the predicate. | `array`, `predicate(λ)` | `arrayAllMatch(arrayOf(0,1,2), it == 1)` | 37| `arrayFindFirst` | Returns the first object in the array or `null` if empty. | `array` | `arrayFindFirst(arrayOf(0, 23))` | 38 39::: 40 41::: details Registries 42 43| Function | Description | Arguments | Example | 44|---|---|---|---| 45| `Registry` | Returns a static content registry | `identifier` | `Registry('entity_type')` | 46| `Item` | Returns an item from the registry | `identifier` | `Item('diamond')` | 47| `Block` | Returns a block from the registry | `identifier` | `Block('chest')` | 48| `DynamicRegistry` | Returns a dynamic content registry | `identifier` | `DynamicRegistry('worldgen/biome')` | 49| `Biome` | Returns a biome from the registry | `identifier` | `Biome('the_void')` | 50| `DimensionType` | Returns a dimension type from the registry | `identifier` | `DimensionType('overworld')` | 51 52::: 53 54::: details Misc 55 56| Function | Description | Arguments | Example | 57|---|---|---|---| 58| `structContainsKey` | Checks if a struct contains some key. | `struct`, `key...` | `structContainsKey(block_state.properties, 'candles')` | 59| `hasContext` | Checks if an expression parameter is available | `key...` | `hasContext('tool')` | 60| `length` | Returns the length of the specified object or 0. | `value` | `length('Hello World!')` | 61| `strFormat` | Formats a string according to the pattern. | `pattern`, `args...` | `strFormat('Hello %s World!', 23)` | 62| `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)` | 63| `chain` | Chains multiple functions using lambdas. `it` is the last result. | `value`, `actions(λ)...` | `chain(23, it + 3, sqrt(it))` | 64 65::: 66 67::: details Operators 68 69| Function | Description | Arguments | Example | 70|---|---|---|---| 71| `?.` | Attempts to get a field from a structure or returns `null` | `struct`, `key` | `struct?.field` | 72| `?` | Returns `b` if `a` is `null`. `a` otherwise. | `a`, `b` | `struct?.y ? 5` | 73 74::: 75 76## Context data access 77 78Because Expressions require minecraft's loot context, you can read source data using a special syntax. 79``` 80identifier.field 81identifier.method 82identifier.method.field.method 83``` 84Keep in mind that requested fields and context **must** be present. Expression will fail without them. 85 86Some examples: 87``` 88minecraft:this_entity.getX 89this_entity.getHealth 90minecraft:this_entity.isInWaterOrRain 91this_entity.blockPosition.getX 92origin.x 93origin.reverse.y 94minecraft:level.getDayTime 95``` 96 97### Commander Extensions: 98 99Commander adds special fields to objects to extend expression capabilities. 100 101::: details `nbt` (Stacks, Entities, Block Entities) 102 103Added 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. 104 105Example: `this_entity.nbt.Air` 106 107::: 108 109::: details `properties` (Block States) 110 111Added to states, like block states. 112 113Example: `block_state.properties.candles` 114 115::: 116 117::: details `attributes` (Living Entities) 118 119Allows you to access entity attributes. The key is an identifier, so both `generic.luck` and `minecraft:generic.luck` are acceptible. 120 121Example: `this_entity.attributes.'generic.luck'` 122 123::: 124 125::: details `storage` (Levels, Chunks, Entities, Block Entities) 126 127Allows you to access persistent data storage. The data is modified and written by [`/cmd:data`](/BrigadierCommands#cmd-data) 128 129::: 130 131### P.S. 132 133If 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. 134 135Expressions 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) 136 137::: details Random examples 138 139Default minecart speed is computed using this formula: 140 141`if(this_entity.isInWater, 4, 8) / 20`, and furnace: `if(this_entity.isInWater, 3, 4) / 20` 142 143*** 144 145This 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/ 146 147`strFormat('%02.0f:%02.0f', floor((level.getDayTime / 1000 + 8) % 24), floor(60 * (level.getDayTime % 1000) / 1000))` 148 149So the output can be: `00:00`, or `13:45`, etc. 150 151::: 152 153## Using Expressions 154 155The fastest way to get started is to use the `cmd:arithmetica` command. You should wrap your expression with `"` to satisfy Brigadier. 156 157Other places you can use expressions in: 158 159::: details JSON Command Macros 160 161Command Macros are explained in detail on the Commands page. [Link](Commands#command-macros) 162 163::: 164 165::: details Loot number provider 166 167Using the `commander:arithmetica` provider in conditions: 168 169```json 170{ 171 "condition": "minecraft:value_check", 172 "value": { 173 "type": "commander:arithmetica", 174 "value": "round(random(5, 15))" 175 }, 176 "range": { 177 "min": 12.3, 178 "max": 32 179 } 180} 181``` 182 183::: 184 185::: details Loot predicate 186 187Using the `commander:expression` predicate: 188 189```json 190{ 191 "condition": "commander:expression", 192 "value": "level.isDay" 193} 194``` 195 196::: 197 198::: details `execute` command 199 200You can use expressions as predicates in the `execute if` command. 201 202``` 203/execute if cmd:expression "level.isDay" run say It is day! 204``` 205 206::: 207 208::: details `scoreboard players` command 209 210You can use expressions as modifiers for player predicates. `score` variable allows you to get the current score. 211 212The current version does not provide entity context. 213 214``` 215/scoreboard players cmd:operate @s test_objective "(score * 1.5) + level.storage.my_score_modifier" 216``` 217 218:::