主题
Molang 脚本
Mojang基岩版脚本的镜像自实现,客户端/服务端的轻量表达式语言,用于动画/特效/曲线驱动。
Molang 在 Behemiron 用于动画/特效/表达式驱动的轻量脚本语言。 在本项目里,Behemiron 的 Molang 支持同时在客户端/服务端运行,实现了 95% 左右的 Molang 语法
- 标准运算(数学四则,布尔,条件,for each循环)
- 局部变量表,变量赋值 / 注入
- 函数调用栈 / Function call
- 数组与数组访问
- 与 Java 对象的互操作
- 编译优化(常量折叠、死变量消除)与 JIT 编译,在 Double 表达式被大量求值时,自动将语句编译为 JVM 汇编以提高运行速度
- 支持注入自定义函数Call与Java对象 Binding
Behemiron 的 Molang 在冷路径运行在解释模式下(词法分析->语法分析->中端优化->直接执行),热路径的 Double 数学表达式运行在 JIT 模式 (词法分析->语法分析->中端优化->编译为 ASM->JVM直接执行)
Quick Start
molang
// 移动判定 -- 地面且有速度
query.is_on_ground && query.ground_speed > 0.02
// 技能蓄力 -- 每帧递增,clamp 到 [0, 1]
variable.charge = math.clamp(variable.charge + 0.02, 0, 1)
// 动画权重 -- 根据速度插值
math.lerp(0.0, 1.0, query.ground_speed)1. 命名空间与别名
Molang 内置命名空间(均可用英文/缩写/中文):
| 命名空间 | 作用 | 常用写法 | 中文别名 |
|---|---|---|---|
query | 只读查询 | query.xxx / q.xxx | 查询.xxx |
variable | 实体变量 | variable.xxx / v.xxx | 局部变量.xxx |
context | 上下文变量 | context.xxx / c.xxx | 上下文变量.xxx |
temp | 临时变量 | temp.xxx / t.xxx | 临时变量.xxx |
math | 数学函数 | math.xxx | 数学.xxx |
func | 脚本函数 | func.xxx | 方法.xxx |
2. 变量生命周期
| 命名空间 | 生命周期 | 读写 | 说明 |
|---|---|---|---|
variable.* | 实体级 | 读写 | 实体销毁后消失(不持久化) |
temp.* | 表达式执行期间 | 读写 | 仅当前表达式内有效 |
context.* | 运行时注入 | 只读 | 由运行时注入 |
query.* | 实体与世界状态 | 只读 | 由实体与世界状态推导 |
3. 常用 Query 变量(完整清单)
3.1 Context 变量
| 变量 | 说明 |
|---|---|
query.anim_time | 当前动画时间 |
query.life_time | 实体存活时间 |
query.actor_count | 场景实体数量 |
query.is_first_person | 是否第一人称 |
3.2 Level 变量
| 变量 | 说明 |
|---|---|
query.time_of_day | 一天中的时间 |
query.time_stamp | 时间戳 |
query.moon_phase | 月相 |
3.3 Entity 变量
| 变量 | 说明 |
|---|---|
query.position_x / y / z | 实体坐标 |
query.eye_target_x_rotation / y_rotation | 视线旋转 |
query.head_x_rotation / y_rotation | 头部旋转 |
query.yaw_speed | 偏航速度 |
query.ground_speed | 地面速度 |
query.vertical_speed | 垂直速度 |
query.cardinal_facing_2d | 2D 朝向 |
query.distance_from_camera | 距摄像机距离 |
query.modified_distance_moved | 修正移动距离 |
query.walk_distance | 行走距离 |
query.has_rider | 是否有骑乘者 |
query.is_in_water | 是否在水中 |
query.is_in_water_or_rain | 是否在水中或雨中 |
query.is_on_fire | 是否着火 |
query.is_on_ground | 是否在地面 |
query.is_riding | 是否骑乘中 |
query.is_sneaking | 是否潜行 |
query.is_jumping | 是否跳跃 |
query.is_spectator | 是否旁观者 |
query.is_sprinting | 是否疾跑 |
query.is_swimming | 是否游泳 |
3.4 LivingEntity 变量
| 变量 | 说明 |
|---|---|
query.body_x_rotation / y_rotation | 身体旋转 |
query.health / query.max_health | 当前 / 最大生命值 |
query.hurt_time | 受伤时间 |
query.is_playing_dead | 是否装死 |
query.is_eating | 是否进食 |
query.is_sleeping | 是否睡觉 |
query.is_using_item | 是否使用物品 |
query.item_in_use_duration | 物品使用时长 |
query.item_max_use_duration | 物品最大使用时长 |
query.item_remaining_use_duration | 物品剩余使用时长 |
query.equipment_count | 装备数量 |
3.5 Player 变量
| 变量 | 说明 |
|---|---|
query.has_cape | 是否有披风 |
query.cape_flap_amount | 披风飘动程度 |
query.player_level | 玩家等级 |
4. Query 函数
| 函数 | 说明 |
|---|---|
query.biome_has_all_tags(...) | 当前生物群系是否包含所有指定标签 |
query.biome_has_any_tag(...) | 当前生物群系是否包含任一标签 |
query.relative_block_has_all_tags(...) | 相对方块是否包含所有标签 |
query.relative_block_has_any_tag(...) | 相对方块是否包含任一标签 |
query.is_item_name_any(...) | 物品名称是否匹配 |
query.equipped_item_all_tags(...) | 装备物品是否包含所有标签 |
query.equipped_item_any_tag(...) | 装备物品是否包含任一标签 |
query.position(...) | 获取坐标分量 |
query.position_delta(...) | 获取坐标增量 |
query.max_durability(...) | 最大耐久度 |
query.remaining_durability(...) | 剩余耐久度 |
query.debug_output(...) | 调试输出 |
示例:
molang
query.is_on_ground && query.ground_speed > 0.025. Math 函数与常量
常量
| 常量 | 值 |
|---|---|
math.pi | 3.14159... |
math.e | 2.71828... |
函数
| 函数 | 说明 |
|---|---|
abs(x) | 绝对值 |
acos(x) / asin(x) / atan(x) | 反三角函数 |
atan2(y, x) | 二元反正切 |
ceil(x) / floor(x) / round(x) / trunc(x) | 取整 |
clamp(value, min, max) | 区间限制 |
cos(x) / sin(x) | 三角函数 |
die_roll(n, low, high) | 掷骰(浮点) |
die_roll_integer(n, low, high) | 掷骰(整数) |
exp(x) / ln(x) | 指数 / 自然对数 |
hermite_blend(t) | Hermite 混合 |
lerp(a, b, t) | 线性插值 |
lerprotate(a, b, t) | 角度线性插值 |
max(a, b) / min(a, b) | 最大 / 最小值 |
min_angle(a) | 最小角度 |
mod(a, b) | 取模 |
pow(base, exp) | 幂运算 |
random(low, high) | 随机浮点 |
random_integer(low, high) | 随机整数 |
sqrt(x) | 平方根 |
to_deg(rad) / to_rad(deg) | 角度/弧度转换 |
6. 内置函数
| 函数 | 说明 | 限制 |
|---|---|---|
loop(count, expression) | 循环执行表达式 | 最多 1024 次 |
for_each(var, array, expression) | 遍历数组 | -- |
print(...) | 调试输出 | -- |
7. 常见问题
| 问题 | 回答 |
|---|---|
| 为什么服务端不解析 Molang? | Molang 运行依赖渲染/实体状态,在客户端执行更稳定且性能更好 |
| 变量从哪里来? | 相关运行时模块会把服务端下发的 vars / flags 注入到 variable.* |
| 可以自定义函数吗? | 可以。通过脚本注册机制挂到 func.* 命名空间 |