MoLang

亦叫MoLang表达式。MoLang是一种简单的基于表达式的语言,为实时且快速地计算数值而设计。它的设计重点是在JavaScript无法大规模执行的需要更高性能的系统中启用类似脚本的功能。
Molang主要是被用在实体的动画控制器里,有时也会用在实体行为、实体entity定义、渲染控制器、特征等地方。

语法

Molang的入门门槛极低,只要有些编程经验一会儿就能学会,即使不怎么会编程,但是只要初中数学好也可以。
MoLang语言结构主要基于简单的C样式语法,专于处理数学表达式。对于简要情况,脚本由一个表达式组成;而在需要中间值,或有助于减少计算时间的情况下,则可由多个表达式组成。
所有情况下,脚本中最后一个表达式的值会提供该脚本的值。在多表达式脚本中,除最后一个表达式外,所有表达式都必须为变量分配一个值。最后一个表达式也可分配,然而并不需要,因为它的值被默认用作返回值。
以上改编自MinecraftWiki

变量

一个变量可能属于以下几个域

范围示例
temp当前表达式temp.foo = math.sin(query.anim_time); return temp.foo * temp.foo;
variable只读值,通常指向当前实体variable.my_saved_var = variable.my_saved_var + 1;
query只读值,通常指向当前实体query.is_baby
geometry当前渲染控制器(控制使用的几何模型)"geometry": "array.geos[query.is_sheared]"
material当前渲染控制器(与生物体自身发光等效果相关,选项固定,对应文件不开源)"materials": [ { "*": "material.default" }, { "leg*": "material.legs" } ]
texture当前渲染控制器(控制生物使用的材质贴图)"textures": ["array.skins[query.is_saddled]"]

所有数值均为浮点数。
分别将布尔值转换并存储为0.0或1.0的浮点值(分别为false或true)。
对于布尔测试,等于0.0的浮点值为false,不等于0.0的任何值为true。
对于数组索引,浮点数以C样式转换为整数,对于负值,浮点数限制为零;对于大值,浮点数由数组大小包装。
其他受支持的类型为:

Geometry模型
Texture纹理
Material材料
Actor Reference参与者参考
Actor Reference Array参与者引用数组
String字符串
Struct数据结构

如果错误则返回0.0

关键字

关键字描述
floa数值常量值
( )圆括号用于控制运算表达式的先后顺序
[ ]方括号用于数组存取
{{`}}大括号执行范围
query访问实体的属性
math各种数学方法(见下表)
temp在当前表达式中存储一个临时变量
variable在当前实体身上存储一个变量供使用
geometry在实体定义中指向一个贴图
material在实体定义中指向一个贴图
texture在实体定义中指向一个贴图
this在运行这个表达式前的值(上下文相关)
return在复杂的表达式中,这个关键字会在返回后面的表达式的值后停止运算
??空合并运算符,用于处理缺少的变量或过时的actor引用
->箭头运算符,用于访问来自不同实体的数据
context在某些情况下游戏提供的只读存储
loop用于重复一个或多个命令“ n”次
for_each用于遍历实体数组
break用于及早退出循环/ for_each范围
continue用于跳过循环/ for_each迭代的其余语句集并移至下一个迭代
+基础数学运算符,加
-基础数学运算符,减
*基础数学运算符,乘
/基础数学运算符,除
==比较运算符,等于
!=比较运算符,不等于
>比较运算符,大于
<比较运算符,小于
>=比较运算符,大于等于
<=比较运算符,小于等于
===比较运算符,绝对等于
!==比较运算符,绝对不等于
!逻辑运算符,否
&&逻辑运算符,和
||逻辑运算符,或
条件表达式 ? 如果真条件运算符(二元表达式)
条件表达式 ? 如果真 : 如果假条件运算符(三元表达式)

三元表达式
诸如C、Java、JS、Py这些编程语言中都有三元表达式,基本用法也相同。

  • 问号“?”前面的为条件表达式,何为条件表达式?
    "1 * 1 + 1 == 3"这就是一个条件表达式,将会检测最终返回的值是否符合比较运算符,是就再次返回true真,不是则返回false假。
    1乘1加1是明显不等于3的,所以返回假false。如果是"1 * 1 + 1 != 3”那将返回true,因为1乘1加1确实不等于3,符合比较运算符。
  • 问号"?"后面是两个新的表达式。这两个表达式被冒号“:”隔开
    冒号前面的表达式将会在条件表达式返回true时执行,后面的表达式则是在条件表达式返回false时执行。

缩写

为了减少打字负担并在阅读和编写molang时一目了然,因此以下关键字都有缩写形式。

全名缩写
context.mooc.moo
query.mooq.moo
temp.moot.moo
variable.moov.moo

就比如:

math.sin(query.life_amount * math.sqrt(variable.ac / (233 - query.moving + variable.i ) ) ) + variable.i * query.is_jumping

可以这样缩写

m.sin(q.life_amount * m.sqrt(v.ac / (233 - q.moving + v.i ) ) ) + v.i * q.is_jumping

也可以两种形式一起食用

math.sin(q.life_amount * m.sqrt(variable.ac / (233 - query.moving + v.i ) ) ) + v.i * query.is_jumping

结构

数据结构与C不同,是通过用法隐式定义的。它们的目的是更有效地传递数据,例如传递v.location而不是vx,vy和vz。例如:

v.location.x = 1 ; 
v.location.y = 2 ; 
v.location.z = 3 ; 
v.another_mob_set_elsewhere -> v.first_mobs_location = v.location;

molang中的字符串用单引号引起来,例如:'minecraft:pig'或'hello world!'。空字符串定义为两个背对背的单引号。字符串操作仅支持= =!\=此时。
注意:字符串不支持'字符,因为目前不支持转义字符。

->箭头运算符

查询函数的某些返回值或存储在temp / entity / context变量中的值可以是对另一个实体的引用。“->”运算符允许脚本访问该实体上的变量或运行查询。例如,下面的示例将查找当前实体四米以内的所有猪(如果是猪,则包括其自身),如果每只猪上方的块易燃(例如,橡树按钮),则在其自身上增加变量vx ):
请注意,如果->运算符的左手边有错误(值是null,该实体先前被杀死,或其他问题),则表达式将不会计算右手边并将返回0。此实现样式是在性能之间进行选择的,而不是要求内容创建者过分担心在任何地方检查潜在不良值的选择。

"v.x = 0;
for_each(v.pig, query.get_nearby_entities(4, 'minecraft:pig'), {
    v.x = v.x + v.pig->query.get_relative_block_state(0, 1, 0, 'flammable');
});"

公共变量

通常,一个暴徒的变量被认为是该暴徒的私有变量,而另一个变量无法访问。若要将变量对其他生物的只读访问权限,您需要在所属实体的资源定义中对该变量设置“公共”设置。还建议默认初始化变量。

{
  "format_version": "1.10.0",
  "minecraft:client_entity": {
    "description": {
      ...
      "scripts": {
        "variables": {
          "variable.oink": "public"
        },
        "initialize": [
          "variable.oink = 0;"
        ],
        ...
      },
      ...
    }
  }
}

{}括号范围定界符

通过将它们用{和}符号包装,可以将一系列语句分组为一组。这主要用于循环和条件语句中:

(v.moo > 0) ? {
  v.x = math.sin(q.life_time * 45);
  v.x = v.x * v.x + 17.3;
  t.sin_x = math.sin(v.x);
  v.x = t.sin_x * t.sin_x + v.x * v.x;
  v.x = math.sqrt(v.x) * v.x * math.pi;
}
~~~.

### loop

有时您想多次执行一个表达式。您可以使用`loop(count,expression);`而不是将其粘贴粘贴。为了安全起见,我们现在对它们施加了一些任意限制。最大循环计数器是(在撰写本文时)1024。此外,请注意,尽管您可以将循环嵌套在所需的深度内,但是要小心不要循环太久,它会挂断您的游戏。  
斐波那契计算器  
~~~js
v.x = 1;
v.y = 1;
loop(10, {
  t.x = v.x + v.y;
  v.x = v.y;
  v.y = t.x;
});

for_each

query.get_nearby_entities(请参阅下文)返回实体数组。为了遍历它们,可以使用以下新的内置函数“ for_each”。它带有三个参数:for_each(variable,array,expression);变量可以是任何变量,可以是temp或variable,尽管我建议使用temp来不污染实体的变量。可变空间。该表达式是您要为数组中的每个条目执行的任何molang表达式)

break

这将退出loop循环或 for_each。

v.x = 1;
v.y = 1;
loop(10, {t.x = v.x + v.y; v.x = v.y; v.y = t.x; (v.y > 20) ? break;});

按照C语言样式规则,这将立即退出最内部的活动循环。如果你有:

v.x = 0;
loop(10, {loop(10, {v.x = v.x + 1; (v.x > 5) ? break;});});

vx> 5时,break语句将终止内部循环,并继续处理外部循环的脚本。注意,由于没有在外部循环之间重置vx,因此第二次进入内部循环将在vx处再添加一个,然后再次退出内部循环,导致vx的最终值为6 + 1 + 1 + 1 + ... + 1=15`)

continue

continue按照C风格语言规则运行。当前仅在循环中受支持,它将跳至当前循环的下一个迭代。有关内部/外部循环的更多详细信息,请参见上面的break。以下示例将导致vx变为6.0,因为一旦达到该值,增量将被跳过。请注意,在这个人为的示例中,最好跳出循环,因为与继续执行所有10次迭代相比,它的性能更高。

v.x = 0;
loop(10, {
 (v.x > 5) ? continue;
 v.x = v.x + 1;
});

??空合并运算符

类似于空值运算符在C#中的工作方式,现在可以引用一个可能存在或不存在的变量,而不会看到内容错误。如果没有,您现在可以提供要使用的默认值。以前,如果变量不存在,则会出现内容错误。这是为了确保始终正确正确地初始化变量,以避免未初始化的变量错误。不幸的是,这随后需要初始化脚本,或者在某些情况下,需要一些复杂的解决方法来确保变量已初始化。现在,如果您知道在脚本的第一次运行中不会初始化变量,则可以使用以下命令:

variable.x = (variable.x ?? 1.2) + 0.3;

这将使用variable.x的'价值,如果它是有效的,否则,如果1.2variable.x`:
-尚未初始化
-是已删除的实体的引用
-是一个无效的引用
-拥有一个错误

提示“ ??”运算符将与“ variable。” s,“ temp。” s和“ context。” s一起使用,这些变量包含数字或实体引用,但不包含诸如材料,纹理或几何体之类的资源(因为这些必须存在并且有效,否则是内容错误)。如果第一个参数导致无法解决的问题,它将返回第二个参数。

简单与复杂表达式

简单表达式是单个语句

math.sin(query.anim_time * 1.23)

复杂表达式是具有多个语句的表达式,每个语句均以“;”结尾。每个语句按顺序进行评估。在当前的实现中,最后一条语句要求使用return关键字并定义表达式的结果值。例如:

temp.moo = math.sin(query.anim_time * 1.23);
temp.baa = math.cos(query.life_time + 2.0);
return temp.moo * temp.moo + temp.baa;

注意,在简单的表达式中,不允许使用“;”,而在复杂的表达式中,每个语句都需要使用“;”(包括最后一个)。另外,请注意,如果您不从复杂表达式中“返回”值,则该表达式的计算结果将为0.0。

数学函数

函数描述
"math.abs(value)"value的绝对值
"math.sin(value)"value的正弦值
"math.cos(value)"value的余弦值
"math.exp(value)"value以e为底数的指数函数
"math.ln(value)"value以e为底数的对数函数
"math.pow(base, exponent)"返回base的exponent次幂
"math.sqrt(value)"value的平方根
"math.random(low, high)"在最小值到最大值之间的随机数
"math.ceil(value)"数字的向上取整
"math.round(value)"数字四舍五入取整
"math.trunc(value)"截短法取整,这种方式在处理负数时是向上取整
"math.floor(value)"向下取整
"math.mod(value, denominator)"value 除以 denominator后的余数
"math.min(A, B)"返回A和B中的最小值
"math.max(A, B)"返回A和B中的最大值
"math.clamp(value, min, max)"把value限定在最小值和最大值之间
"math.lerp(start, end, 0_to_1)"在start和end之间根据0~1取中间值,即start+(end-start)*0_to_1
"math.lerprotate(start, end, 0_to_1)"作为角度,在start和end之间根据0~1取中间值,360度时会有跨越
"math.atan(value)"值的奥秘
"math.atan2(y,x)"y / x的反正切。注意参数的顺序
"math.die_roll(num,low,high)"返回“ num”个随机数的总和,每个值的范围从低到高。注意:生成的随机数不是像普通骰子那样的整数。为此,请使用math.die_roll_integer。
"math.die_roll_integer(num,low,high)"返回“ num”个随机整数的总和,每个整数的值从低到高。注意:生成的随机数是类似于正常骰子的整数。
"math.hermite_blend(value)"使用Hermite基础函数之一进行简单的平滑曲线插值很有用:3t ^ 2-2t ^ 3。请注意,尽管任何有效的float都是有效的输入,但此功能在[0,1]范围内效果最佳。
"math.pi返回常量pi的float表示形式。
"math.pow(base,exponent)"将“基础”提升至“指数”次幂
"math.random(low,high)"上下限之间的随机值
"math.random_integer(low,high)"上下限之间的随机整数值

查询功能

查询函数是布尔表达式,允许您在不同情况下查询拥有的值。可以在MoLang表达式中使用。如果村民是幼儿,可用于控制更改位置,纹理,动画等内容。

"position": [ 0.0, "query.is_baby ? -8.0 : 0.0", "query.is_baby ? 4.0 : 0.0" ]

实体查询列表

名称描述
query.all_animations_finished仅在动画控制器中有效。如果当前动画控制器状态下的所有动画至少播放了一次,则返回1.0,否则返回0.0。
query.anim_time返回自当前动画开始以来的时间(以秒为单位),否则返回0.0(如果未在动画中调用)
query.any_animation_finished仅在动画控制器中有效。如果当前动画控制器状态下的任何动画至少播放了一次,则返回1.0,否则返回0.0。
query.armor_color_slot将装甲插槽索引作为参数,并返回请求的插槽中装甲的颜色
query.armor_material_slot将装甲插槽索引作为参数,并在请求的装甲插槽中返回装甲材料类型
query.armor_texture_slot将装甲插槽索引作为参数,并返回所请求插槽的纹理类型
query.blocking如果实体正在阻止,则返回1.0,否则返回0.0
query.body_y_rotation如果在actor上调用,则返回身体偏航旋转,否则返回0.0
query.can_climb如果实体可以爬升,则返回1.0,否则返回0.0
query.can_fly如果实体可以飞行,则返回1.0,否则返回0.0
query.can_power_jump如果实体可以跳跃,则返回1.0,否则返回0.0
query.can_swim如果实体可以游泳则返回1.0,否则返回0.0
query.can_walk如果实体可以行走,则返回1.0,否则返回0.0
query.current_squish_value返回当前实体的压缩值,如果没有意义,则返回0.0
query.delta_time返回自上一帧以来的时间(以秒为单位)
query.frame_alpha返回正在渲染此帧的AI刻度之间的比率(从0到1)
query.ground_speed以米/秒为单位返回实体的地面速度
query.has_armor_slot将装甲插槽索引作为参数,如果实体在请求的插槽中有装甲,则返回1.0,否则返回0.0
query.has_collision如果实体启用了碰撞,则返回1.0,否则返回0.0
query.has_gravity如果实体受重力影响,则返回1.0,否则返回0.0
query.has_owner如果实体具有所有者ID,则返回true,否则返回false
query.has_rider如果实体有骑手,则返回1.0,否则返回0.0
query.has_target如果实体具有目标,则返回1.0,否则返回0.0
query.head_roll_angle返回狼实体头部的侧倾角
query.head_x_rotation将一个参数作为参数。如果有意义,则返回该实体的第n个头部x旋转,否则返回0.0
query.head_y_rotation将一个参数作为参数。如果有意义,则返回实体的第n个头y旋转,否则返回0.0
query.invulnerable_ticks如果有意义的话,返回实体剩余的无痕数,否则返回0.0
query.is_angry如果实体生气则返回1.0,否则返回0.0
query.is_avoiding_mobs如果实体逃离暴民则返回1.0,否则返回0.0
query.is_baby如果实体是婴儿,则返回1.0,否则返回0.0
query.is_breathing如果实体呼吸,则返回1.0,否则返回0.0
query.is_bribed如果实体已经贿赂,则返回1.0,否则返回0.0
query.is_carrying_block如果实体携带一个块,则返回1.0,否则返回0.0
query.is_casting如果实体正在投射,则返回1.0,否则返回0.0
query.is_charged如果实体已收费,则返回1.0,否则返回0.0
query.is_charging如果实体正在收费,则返回1.0,否则返回0.0
query.is_chested如果实体已连接箱子,则返回1.0,否则返回0.0
query.is_critical如果实体是关键的,则返回1.0,否则返回0.0
query.is_dancing如果实体在跳舞,则返回1.0,否则返回0.0
query.is_delayed_attacking如果实体使用延迟攻击进行攻击,则返回1.0,否则返回0.0
query.is_eating如果实体正在吃饭,则返回1.0,否则返回0.0
query.is_elder如果实体是旧版本,则返回1.0,否则返回0.0
query.is_enchanted如果附魔该实体,则返回1.0,否则返回0.0
query.is_fire_immune如果该实体不受射击,则返回1.0,否则返回0.0
query.is_first_person如果实体以第一人称模式渲染,则返回1.0,否则返回0.0
query.is_gliding如果实体滑动,则返回1.0,否则返回0.0
query.is_grazing如果实体在放牧,则返回1.0;否则,则返回0.0
query.is_idling如果实体闲置,则返回1.0,否则返回0.0
query.is_ignited如果实体被点燃,则返回1.0,否则返回0.0
query.is_illager_captain如果实体是前卫队长,则返回1.0,否则返回0.0
query.is_in_love如果实体恋爱,则返回1.0,否则返回0.0
query.is_in_water如果实体在水中,则返回1.0,否则返回0.0
query.is_in_water_or_rain如果实体在水或雨中,则返回1.0,否则返回0.0
query.is_interested如果该实体感兴趣,则返回1.0,否则返回0.0
query.is_invisible如果实体不可见,则返回1.0,否则返回0.0
query.is_jumping如果实体在跳跃,则返回1.0,否则返回0.0
query.is_laying_down如果实体放下则返回1.0,否则返回0.0
query.is_laying_egg如果实体下蛋,则返回1.0,否则返回0.0
query.is_leashed如果实体被释放,则返回1.0,否则返回0.0
query.is_lingering如果实体徘徊,则返回1.0,否则返回0.0
query.is_moving如果实体正在移动,则返回1.0,否则返回0.0
query.is_on_ground如果实体在地面上,则返回1.0,否则返回0.0
query.is_onfire如果实体着火则返回1.0,否则返回0.0
query.is_orphaned如果该实体是孤立的,则返回1.0,否则返回0.0
query.is_powered如果实体已通电,则返回1.0,否则返回0.0
query.is_pregnant如果实体已怀孕,则返回1.0,否则返回0.0
query.is_resting如果实体处于静止状态,则返回1.0,否则返回0.0
query.is_riding如果实体在骑行,则返回1.0,否则返回0.0
query.is_roaring如果实体当前正在咆哮,则返回1.0,否则返回0.0
query.is_rolling如果实体正在滚动,则返回1.0,否则返回0.0
query.is_saddled如果实体有鞍,则返回1.0,否则返回0.0
query.is_scared如果该实体感到害怕,则返回1.0,否则返回0.0
query.is_shaking如果实体正在投射,则返回1.0,否则返回0.0
query.is_shaking_wetness如果实体正在甩水,则返回true
query.is_sheared如果实体能够被剪切并被剪切,则返回1.0,否则返回0.0
query.is_shield_powered如果该实体有意义,则返回1.0f(如果该实体具有活动的有源屏蔽),否则返回0.0
query.is_silent如果实体为静默则返回1.0,否则返回0.0
query.is_sitting如果实体坐着,则返回1.0,否则返回0.0
query.is_sleeping如果实体正在睡眠,则返回1.0,否则返回0.0
query.is_sneaking如果实体正在潜行,则返回1.0,否则返回0.0
query.is_sneezing如果实体在打喷嚏,则返回1.0,否则返回0.0
query.is_sprinting如果实体正在冲刺,则返回1.0,否则返回0.0
query.is_stackable如果实体是可堆叠的,则返回1.0,否则返回0.0
query.is_standing如果实体站立,则返回1.0,否则返回0.0
query.is_stunned如果该实体当前处于眩晕状态,则返回1.0,否则返回0.0
query.is_swimming如果实体正在游泳,则返回1.0,否则返回0.0
query.is_tamed如果已驯服实体,则返回1.0,否则返回0.0
query.is_transforming如果实体正在变换,则返回1.0,否则返回0.0
query.is_using_item如果实体正在使用项目,则返回1.0,否则返回0.0
query.is_wall_climbing如果实体正在爬墙,则返回1.0,否则返回0.0
query.item_in_use_duration以秒为单位返回商品的使用时间(最长持续时间),否则返回0.0。
query.item_max_use_duration返回该项目可以使用的最长时间,否则返回0.0。
query.item_remaining_use_duration返回项目剩余可使用的时间(以秒为单位),否则返回0.0。
query.key_frame_lerp_time返回上一个和下一个关键帧之间的比率
query.lie_amount返回实体的躺下数量
query.life_span返回实体的有限寿命,如果实体永久存在,则返回0.0
query.life_time返回自当前动画开始以来的时间(以秒为单位),否则返回0.0(如果未在动画中调用)
query.log调试日志值
query.mark_variant返回实体的mark变体
query.max_trade_tier如果有意义,则返回实体的最大交易层,否则返回0.0
query.model_scale返回当前实体的比例
query.modified_distance_moved返回实体在水平方向上移动的总距离(以米为单位)(自从上次加载以来,不一定是最初创建实体以来),该状态由状态标记(例如is_baby或on_fire)修改
query.modified_move_speed返回由状态标志(例如is_baby或on_fire)修改的实体的当前行走速度
query.overlay_alpha请勿使用-此功能已弃用,将被删除
query.previous_squish_value返回当前实体的前一个压缩值,如果没有意义,则返回0.0
query.roll_counter返回实体的滚动计数器
query.shake_angle返回狼实体的摇动角度
query.sit_amount返回实体的当前坐席量
query.skin_id返回实体的皮肤ID
query.sneeze_counter返回实体的打喷嚏计数器
query.spellcolor.b如果有意义,则返回当前实体拼写颜色的蓝色通道,否则返回0.0
query.spellcolor.g如果可行,则返回当前实体拼写颜色的绿色通道,否则返回0.0
query.spellcolor.r如果有意义,则返回当前实体拼写颜色的红色通道,否则返回0.0
query.standing_scale返回实体的站立程度
query.swell_amount返回实体的肿胀程度
query.swelling_dir如果有意义,则返回实体的膨胀方向,否则返回0.0
query.tai​​l_angle返回狼实体尾巴的角度,否则返回0.0
query.target_x_rotation如果有一个,则返回瞄准当前目标的x旋转,否则返回0.0
query.target_y_rotation如果有一个,则返回瞄准实体当前目标所需的y旋转,否则返回0.0
query.time_stamp返回级别的当前时间戳
query.trade_experience返回有意义的实体当前交易经验,否则返回0.0
query.trade_tier如果有意义,则返回实体的贸易层,否则返回0.0
query.unhappy_counter返回实体的不满意程度
query.variant返回实体的变种值
query.wing_flap_position返回实体的襟翼位置,如果没有意义,则返回0.0
query.wing_flap_speed返回实体的机翼襟翼速度;如果没有意义,则返回0.0
query.yaw_speed返回实体的偏航速度