宏函数
太长不看
这是内部实现细节 — 你不需要理解它就能使用 RedScript。一切都是"自动工作"的。
但如果你好奇:"等等,MC 命令不支持在坐标位置用变量啊... 这怎么做到的?" — 本章解释幕后的魔法。
RedScript 自动使用 MC 1.20.2+ 的函数宏功能,允许在通常需要编译时字面量的位置(坐标、实体类型等)使用运行时变量。
问题
在原版 Minecraft 命令中,某些值必须是字面量:
# ❌ 这不行 - 坐标不能是计分板值
teleport @s $x $y $z解决方案
RedScript 自动检测你在这些位置使用变量的情况,并编译为宏语法:
fn spawn_at(x: int, y: int, z: int) {
summon("minecraft:zombie", x, y, z);
}
// 用运行时值调用
let px: int = get_player_x();
spawn_at(px, 64, 100);编译结果:
# spawn_at.mcfunction
$summon minecraft:zombie $(x) $(y) $(z)
# 调用处:
execute store result storage rs:macro_args x int 1 run scoreboard players get $px rs
data modify storage rs:macro_args y set value 64
data modify storage rs:macro_args z set value 100
function ns:spawn_at with storage rs:macro_args自动优化
RedScript 智能决定何时使用宏:
spawn_at(100, 64, 200); // 全常量 → 直接内联,不用宏
spawn_at(px, 64, pz); // 有变量 → 使用宏支持的内置函数
所有内置函数都支持宏参数。 任何参数都可以是运行时变量:
fn dynamic_say(msg: string) {
say(msg); // 可以!
}
fn dynamic_effect(eff: string, dur: int) {
effect(@s, eff, dur, 1); // 可以!
}
fn dynamic_setblock(x: int, y: int, z: int, block: string) {
setblock(x, y, z, block); // 可以!
}包括 say、tell、give、effect、summon、teleport、particle、setblock、fill、clone、playsound、weather、time_set、gamerule、tag_add、tag_remove 以及所有其他内置函数。
相对坐标偏移(~ident)
你可以用 ~变量名 语法将一个变量作为相对坐标偏移:
fn launch_up(target: selector, height: int) {
tp(target, ~0, ~height, ~0); // 在 Y 轴相对当前位置偏移 height 格
}为什么这里必须用宏?
Minecraft 的 ~N 语法要求 N 是字面量数字,不存在任何命令能把计分板值作为相对偏移读取。
~height 的含义是*「从当前位置相对偏移 height 格」*,与把 height 作为绝对坐标传入是本质不同的。在 MC 命令层面,唯一的实现方式是在运行时把数值替换进命令文本中,这正是 1.20.2+ 函数宏做的事。
如果没有宏,这在 MC 中是不可能实现的。 替代方案是预先算出绝对 Y 值传入——但那样就失去了相对移动的语义。
编译结果:
$tp $(target) ~0 ~$(height) ~0调用时通过 function ns:launch_up with storage rs:macro_args,宏在运行时将 height 的值替换进波浪号偏移中。
示例:动态传送
struct Waypoint {
x: int,
y: int,
z: int
}
fn tp_to_waypoint(wp: Waypoint) {
teleport(@s, wp.x, wp.y, wp.z);
}
@keep fn go_home() {
let home: Waypoint = { x: 100, y: 64, z: -200 };
tp_to_waypoint(home);
}示例:粒子网格
fn spawn_particle_at(x: int, y: int, z: int) {
particle("minecraft:flame", x, y, z, 0, 0, 0, 0, 1);
}
@keep fn draw_grid() {
for (let i: int = 0; i < 10; i = i + 1) {
for (let j: int = 0; j < 10; j = j + 1) {
spawn_particle_at(i * 2, 64, j * 2);
}
}
}要求
- Minecraft 1.20.2 或更高版本(函数宏在此版本添加)
- 早期版本无法使用宏编译的函数
工作原理
- 检测:编译时,RedScript 扫描函数体
- 标记:在需要字面量位置使用的参数被标记
- 生成:被标记的函数生成
$前缀的命令 - 调用处:变量参数通过 NBT storage 传递
这一切都是自动的 - 你不需要任何特殊语法或装饰器。