表达式语法
WorldEdit 表达式解析器的工作方式类似于 Java 及相关语言,但有一些微妙的区别:
- 在大多数情况下,可以省略最终的分号。
- 序列中的最后一个值始终会被返回,即使没有 return 语句。
- 二元中缀运算符
^是幂运算符而不是异或运算符,并且具有相应的优先级。 - 有一个后缀阶乘运算符 (
!)。 - 有一个二元中缀近似运算符 (
~=)。 - 不支持对象
操作符
表达式解析器使用 Java 的优先级规则,但有以下例外和补充:
- 二元幂运算符 (
^) 的优先级在 2 和 3 之间 - 后缀阶乘运算符 (
!) 的优先级为 2 - 近似运算符 (
~=) 的优先级为 7
二元中缀
这些运算符位于两个操作数之间。
算术运算
| 运算符 | 说明 |
|---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 取余 |
^ | 幂运算 |
位运算
这些运算符将操作数解释为 32 位整数并对其位进行操作。
| 运算符 | 说明 |
|---|---|
<< | 左移 |
>> | 右移 |
逻辑运算
这些运算符将大于零的值解释为 true,其他值解释为 false。它们返回 1 表示 true,返回 0 表示 false。
| 运算符 | 说明 |
|---|---|
&& | 逻辑与 |
|| | 逻辑或 |
比较运算
这些运算符比较其操作数,返回 1 表示 true,返回 0 表示 false。
| 运算符 | 说明 |
|---|---|
< | 小于 |
> | 大于 |
<= | 小于或等于 |
>= | 大于或等于 |
== | 等于 |
!= | 不等于 |
~= | 近似 |
赋值运算
这些运算符需要左侧为变量。使用简单赋值运算符 (=) 将值赋给不存在的变量时会创建一个临时变量。
| 运算符 | 说明 |
|---|---|
= | 简单赋值 |
+= | 加法赋值 |
-= | 减法赋值 |
*= | 乘法赋值 |
/= | 除法赋值 |
%= | 取余赋值 |
^= | 幂赋值 |
前缀
这些运算符位于其应用的表达式之前。
前缀运算符
| 运算符 | 说明 |
|---|---|
-x | 负值 |
~x | 按位取反 (参见位运算符) |
!x | 逻辑取反 (参见逻辑运算符) |
++x | 前置递增 |
--x | 前置递减 |
后缀
这些运算符位于其应用的表达式之后。
后缀运算符
| 运算符 | 说明 |
|---|---|
x! | 阶乘 |
x++ | 后置递增 |
x-- | 后置递减 |
三元中缀
三元运算符用于以紧凑的方式表示条件表达式:
<condition> ? <true-branch> : <false-branch>
```bash
它的工作方式与 if/else 语句完全相同,只不过分支只能是单一表达式。
## 函数
### 数学函数
表达式解析器提供以下来自 Java Math 库的函数:
| 函数 | 说明 |
|----------|------------------------------------------------------|
| `abs` | 返回一个数的绝对值 |
| `acos` | 返回值的反余弦值,返回的角度范围为 0.0 到 pi |
| `asin` | 返回值的反正弦值,返回的角度范围为 -pi/2 到 pi/2 |
| `atan2` | 返回从直角坐标 (x, y) 转换为极坐标 (r, θ) 的角度 θ |
| `atan` | 返回值的反正切值,返回的角度范围为 -pi/2 到 pi/2 |
| `cbrt` | 返回值的立方根 |
| `ceil` | 返回大于或等于参数且最接近负无穷大的整数值 |
| `cos` | 返回角度的三角余弦值 |
| `cosh` | 返回值的双曲余弦值 |
| `exp` | 返回欧拉数 e 的值的次幂 |
| `floor` | 返回小于或等于参数且最接近正无穷大的整数值 |
| `ln` | 返回值的自然对数 (以 e 为底) |
| `log` | 返回值的自然对数 (以 e 为底) |
| `log10` | 返回值的 10 为底的对数 |
| `max` | 返回值中的最大值(支持 2 和 3 个参数) |
| `min` | 返回值中的最小值(支持 2 和 3 个参数) |
| `rint` | 返回最接近参数的值并等于一个数学整数 |
| `round` | 返回最接近参数的值 |
| `sin` | 返回角度的三角正弦值 |
| `sinh` | 返回值的双曲正弦值 |
| `sqrt` | 返回值的正确舍入正平方根 |
| `tan` | 返回角度的三角正切值 |
| `tanh` | 返回值的双曲正切值 |
### 其他函数
此外,还提供以下函数:
| 函数 | 说明 |
|---------------------------------------------------|-----------------------------------------------------------|
| `rotate(x, y, angle)` | 按给定角度(以弧度为单位)旋转给定坐标对 |
| `swap(x, y)` | 交换两个给定变量的内容 |
| `random()` | 返回一个小于 1.0 的随机正数 |
| `randint(max)` | 返回一个小于 max 的随机正整数 |
| `perlin(seed, x, y, z, frequency, octaves, persisence)` | 使用给定参数生成柏林噪声 |
| `voronoi(seed, x, y, z, frequency)` | 使用给定参数生成沃罗诺伊噪声 |
| `ridgedmulti(seed, x, y, z, frequency, octaves)` | 使用给定参数生成嶙峋的多重分形噪声 |
### 方块查询函数
以下函数可用于在编辑环境中查询世界中的方块。注意它们仍然使用旧版的 ID 和数据,因此对新(1.13 及以上)方块可能会有未定义的行为。
| 函数 | 说明 |
|-----------------------------------------------|---------------------------------------------------------------------------------------------------------------|
| `query(x, y, z, type, data)` | 如果给定坐标处的方块具有给定的旧 ID 和数据值,则返回 true。如果 type 或 data 是变量,则方块的 ID 和数据会分配给该变量 |
| `queryRel(dx, dy, dz, type, data)` | 类似于 query,但使用相对于当前评估的方块坐标的偏移量 |
| `queryAbs(xp, yp, zp, type, data)` | 类似于 query,但使用绝对世界坐标 |
### 缓冲区函数
这些函数提供对数据缓冲区(本质上是数组)的访问。提供两个缓冲区,一个是全局共享缓冲区,一个是表达式本地缓冲区。带有 `g` 前缀的函数访问全局缓冲区,不带 `g` 前缀的函数访问本地
缓冲区。
| 函数 | 说明 |
|-------------------------------------------------|------------------------------------------------------------------------------------------|
| `(g)megabuf(index)` | 返回缓冲区在给定索引处的值 |
| `(g)megabuf(index, value)` | 设置缓冲区在给定索引处的值 |
| `(g)closest(x, y, z, index, count, stride)` | 在*count*次迭代和每次迭代之间*stride*的空间内,从给定的索引值开始,找到最接近的 x,y,z 值的索引 |
## 常量
### 常量
以下常量始终可用,且不能被赋值。
| 常量 | 值 | 说明 |
|--------|-------------------------|---------------------------|
| `e` | 2.7182818284590452354 | 自然对数的底数 |
| `pi` | 3.14159265358979323846 | 圆的周长与直径之比 |
| `true` | 1 | 布尔操作中表示真 |
| `false`| 0 | 布尔操作中表示假 |
## 代码块语句
代码块语句是用大括号括起来的一组语句:
```bash
{ x=5; y=6; }
```bash
它们主要用于控制结构。
## 控制结构
### if/else
```java
if (<condition>) <true-branch>
if (<condition>) <true-branch> else <false-branch>
```bash
* `<condition>` 被评估以决定执行哪个分支。
* 大于零的值解释为 true,其他值解释为 false。
* `<true-code>` 和 `<false-code>` 可以是用分号分隔的单个语句或代码块语句。
**注意:** else 关键字总是与最后一个 if 关联。这允许像这样构造 elseif:
```java
if (<condition 1>) <true-code 1> else if (<condition 2>) <true-code 2> else <false-code>
```bash
### 循环
循环最多可以循环 256 次。
#### while
```java
while (<condition>) <body>
do <body> while (<condition>);
```bash
* `<condition>` 被评估以决定是否继续循环。
* `<body>` 可以是用分号分隔的单个语句或代码块语句。
* do-while 在执行主体后检查条件。
#### Java/C 风格的 for
```java
for (<init>; <condition>; <increment>) <body>
```bash
* `<init>`、`<condition>` 和 `<increment>` 是单个表达式。
* `<body>` 可以是用分号分隔的单个语句或代码块语句。
**执行步骤**
首先,`<init>` 只会评估一次,然后每次迭代按以下步骤进行:
1. 如果 `<condition>` 的评估结果小于或等于零(即为 false),则循环终止。
2. 执行 `<body>`。
3. 执行 `<increment>`。
#### 简单 for
```java
for (<counter> = <first>, <last>) <body>
```bash
* `<counter>` 是一个用于计数迭代的变量。
* `<first>` 和 `<last>` 是单个表达式。
* `<body>` 可以是用分号分隔的单个语句或代码块语句。
**执行步骤**
首先,内部计数器被设置为 `<first>`。然后,每次迭代按以下步骤进行:
1. 如果内部计数器超过 `<last>`,则循环终止。
2. `<counter>` 被设置为内部计数器。
3. 执行 `<body>`。
4. 内部计数器增加 1.0。
`<first>` 和 `<last>` 仅评估一次。