Lua 脚本:Prop API
本页涵盖了 FreeMinecraftModels prop 脚本可用的所有 API:context.prop、context.event、context.world、context.zones、context.scheduler、context.state 和 context.log。如果您是 prop 脚本的新手,请先从入门指南开始。
context.prop
prop 表提供关于 prop 实体的信息以及控制其动画的方法。它在每次 hook 调用时重新构建。
字段
| 字段 | 类型 | 说明 |
|---|---|---|
prop.model_id | string | blueprint 模型名称(例如 "torch_01") |
prop.current_location | location table | 构建上下文时 prop 的位置 |
location 表具有标准字段:x、y、z、world、yaw、pitch。
示例:读取 prop 信息
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop spawned: " .. (context.prop.model_id or "unknown"))
local loc = context.prop.current_location
if loc then
context.log:info("Location: " .. loc.x .. ", " .. loc.y .. ", " .. loc.z)
end
end
}
prop:play_animation(name, blend, loop)
在 prop 模型上播放指定名称的动画。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name | string | 必填 | 模型文件中定义的动画名称 |
blend | boolean | true | 是否与当前动画混合 |
loop | boolean | true | 动画是否循环播放 |
如果找到并启动了动画则返回 true,否则返回 false。
示例
return {
api_version = 1,
on_right_click = function(context)
local success = context.prop:play_animation("open", true, false)
if not success then
context.log:warn("Animation 'open' not found on this model!")
end
end
}
prop:stop_animation()
停止 prop 上当前播放的所有动画。
不接受任何参数。
示例
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
context.event
当前 hook 的事件数据。在 on_left_click、on_right_click 和 on_projectile_hit 中可用。在没有关联事件的 hook 中返回 nil(on_spawn、on_game_tick、on_destroy、on_zone_enter、on_zone_leave)。
字段和方法
| 字段或方法 | 类型 | 说明 |
|---|---|---|
event.is_cancelled | boolean | 事件当前是否已被取消 |
event.cancel() | function | 取消事件(例如阻止伤害或交互) |
event.uncancel() | function | 撤销之前取消的事件 |
并非所有事件都可以取消。如果底层 Bukkit 事件未实现 Cancellable,则 event.cancel() 和 event.uncancel() 不存在,event.is_cancelled 始终为 false。
示例:使 prop 无敌
示例
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
示例:检查取消状态
示例
return {
api_version = 1,
on_left_click = function(context)
if context.event and not context.event.is_cancelled then
context.event.cancel()
context.log:info("Damage cancelled!")
end
end
}
在计划的回调中(scheduler:run_later、scheduler:run_repeating),context.event 始终为 nil。事件修改只能在事件 hook 本身中进行。
context.world
world 表提供查询和与 Minecraft 世界交互的方法。它基于 prop 当前所在的世界构建。
context.world API 与 EliteMobs 共享。FMM prop 使用与 EliteMobs Boss 相同的 Magmacore world 表。此处记录的方法是 Magmacore 基础实现中可用的方法。完整参考请查看 EliteMobs World & Environment 页面——其中列出的作为核心 context.world API 一部分的方法在 FMM 中同样可用。
world.name
包含世界名称的 string 字段。
world:get_block_at(x, y, z)
返回给定坐标处方块的材质名称,为小写字符串(例如 "stone"、"air")。
| 参数 | 类型 | 说明 |
|---|---|---|
x | int | 方块 X 坐标 |
y | int | 方块 Y 坐标 |
z | int | 方块 Z 坐标 |
示例
return {
api_version = 1,
on_spawn = function(context)
local loc = context.prop.current_location
if loc then
local block = context.world:get_block_at(
math.floor(loc.x),
math.floor(loc.y) - 1,
math.floor(loc.z)
)
context.log:info("Prop is standing on: " .. block)
end
end
}
world:spawn_particle(particle, x, y, z, count, dx, dy, dz, speed)
在指定位置生成粒子。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
particle | string | 必填 | Bukkit Particle 枚举名称,大写(例如 "FLAME"、"DUST") |
x | number | 必填 | X 坐标 |
y | number | 必填 | Y 坐标 |
z | number | 必填 | Z 坐标 |
count | int | 1 | 粒子数量 |
dx | number | 0 | X 扩散/偏移 |
dy | number | 0 | Y 扩散/偏移 |
dz | number | 0 | Z 扩散/偏移 |
speed | number | 0 | 粒子速度 |
示例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
context.world:spawn_particle("HEART", loc.x, loc.y + 1, loc.z, 5, 0.3, 0.3, 0.3, 0)
end
end
}
world:play_sound(sound, x, y, z, volume, pitch)
在指定位置播放声音。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
sound | string | 必填 | Bukkit Sound 枚举名称,大写(例如 "ENTITY_EXPERIENCE_ORB_PICKUP") |
x | number | 必填 | X 坐标 |
y | number | 必填 | Y 坐标 |
z | number | 必填 | Z 坐标 |
volume | number | 1.0 | 音量 |
pitch | number | 1.0 | 音调 |
示例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
context.world:play_sound("BLOCK_NOTE_BLOCK_PLING", loc.x, loc.y, loc.z, 1.0, 1.2)
end
end
}
world:strike_lightning(x, y, z)
在指定位置劈下闪电(视觉效果并造成伤害)。
| 参数 | 类型 | 说明 |
|---|---|---|
x | number | X 坐标 |
y | number | Y 坐标 |
z | number | Z 坐标 |
示例
return {
api_version = 1,
on_projectile_hit = function(context)
local loc = context.prop.current_location
if loc then
context.world:strike_lightning(loc.x, loc.y, loc.z)
end
end
}
world:get_time()
返回当前世界时间(以 tick 为单位)。
world:set_time(ticks)
设置世界时间。
| 参数 | 类型 | 说明 |
|---|---|---|
ticks | int | 世界时间(0 = 黎明,6000 = 正午,13000 = 夜晚,18000 = 午夜) |
world:get_nearby_entities(x, y, z, radius)
返回以给定坐标为中心的边界框内所有活着的实体的实体包装表数组。
| 参数 | 类型 | 说明 |
|---|---|---|
x | number | 中心 X |
y | number | 中心 Y |
z | number | 中心 Z |
radius | number | 搜索半径(在三个轴上均用作半范围) |
示例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local entities = context.world:get_nearby_entities(loc.x, loc.y, loc.z, 10)
context.log:info("Found " .. #entities .. " entities nearby")
end
end
}
world:get_nearby_players(x, y, z, radius)
返回以给定坐标为中心的边界框内所有玩家的玩家包装表数组。
| 参数 | 类型 | 说明 |
|---|---|---|
x | number | 中心 X |
y | number | 中心 Y |
z | number | 中心 Z |
radius | number | 搜索半径 |
示例
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local players = context.world:get_nearby_players(loc.x, loc.y, loc.z, 20)
for i = 1, #players do
context.log:info("Nearby player: " .. (players[i].name or "unknown"))
end
end
end
}
context.zones
zones 表允许您创建空间区域并监视玩家进入/离开事件。区域绑定到脚本实例,并在 prop 被移除时自动清理。
zones:create_sphere(x, y, z, radius)
在给定坐标处创建球形区域。返回一个数字区域句柄。
| 参数 | 类型 | 说明 |
|---|---|---|
x | number | 中心 X |
y | number | 中心 Y |
z | number | 中心 Z |
radius | number | 球体半径 |
zones:create_cylinder(x, y, z, radius, height)
创建圆柱形区域。返回一个数字区域句柄。
| 参数 | 类型 | 说明 |
|---|---|---|
x | number | 中心 X |
y | number | 中心 Y(底部) |
z | number | 中心 Z |
radius | number | 圆柱半径 |
height | number | 圆柱高度 |
zones:create_cuboid(x, y, z, xSize, ySize, zSize)
创建长方体区域。返回一个数字区域句柄。
| 参数 | 类型 | 说明 |
|---|---|---|
x | number | 中心 X |
y | number | 中心 Y |
z | number | 中心 Z |
xSize | number | X 方向半范围 |
ySize | number | Y 方向半范围 |
zSize | number | Z 方向半范围 |
zones:watch(handle, onEnterCallback, onLeaveCallback)
开始监视区域的玩家进入/离开事件。当玩家进入或离开区域时,相应的 hook 会触发(on_zone_enter 或 on_zone_leave)。
| 参数 | 类型 | 说明 |
|---|---|---|
handle | int | 来自 create_* 调用的区域句柄 |
onEnterCallback | function 或 nil | 当玩家进入区域时调用 |
onLeaveCallback | function 或 nil | 当玩家离开区域时调用 |
如果监视设置成功则返回 true,如果区域句柄无效则返回 nil。
区域监视在每个服务器 tick 对同一世界中的所有玩家进行检查。请保持合理的区域数量以避免性能开销。
zones:unwatch(handle)
停止监视区域并清理其资源。
| 参数 | 类型 | 说明 |
|---|---|---|
handle | int | 要停止监视的区域句柄 |
示例:近距离触发区域
示例
return {
api_version = 1,
on_spawn = function(context)
local loc = context.prop.current_location
if loc == nil then return end
-- Create a sphere zone around the prop
local handle = context.zones:create_sphere(loc.x, loc.y, loc.z, 5)
-- Watch for player enter/leave
context.zones:watch(
handle,
function(player)
context.log:info("Player entered zone!")
end,
function(player)
context.log:info("Player left zone!")
end
)
-- Store handle so we can clean up later if needed
context.state.zone_handle = handle
end,
on_destroy = function(context)
if context.state.zone_handle then
context.zones:unwatch(context.state.zone_handle)
end
end
}
context.scheduler
scheduler 允许您运行延迟和重复任务。所有任务归脚本实例所有,并在 prop 被移除时自动取消。
scheduler:run_later(ticks, callback)
延迟后运行一次回调。返回一个数字任务 ID。
| 参数 | 类型 | 说明 |
|---|---|---|
ticks | int | 以服务器 tick 为单位的延迟(20 tick = 1 秒) |
callback | function | 延迟到期时以新的 context 调用 |
示例
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Something will happen in 2 seconds...")
context.scheduler:run_later(40, function(delayed_context)
local loc = delayed_context.prop.current_location
if loc then
delayed_context.world:spawn_particle("EXPLOSION_EMITTER", loc.x, loc.y, loc.z, 1)
end
end)
end
}
scheduler:run_repeating(delay, interval, callback)
以固定间隔重复运行回调。返回一个数字任务 ID。
| 参数 | 类型 | 说明 |
|---|---|---|
delay | int | 第一次运行前的初始延迟(tick) |
interval | int | 每次后续运行之间的 tick 数 |
callback | function | 每个间隔以新的 context 调用 |
示例
return {
api_version = 1,
on_spawn = function(context)
-- Emit particles every second
context.state.particle_task = context.scheduler:run_repeating(0, 20, function(tick_context)
local loc = tick_context.prop.current_location
if loc then
tick_context.world:spawn_particle("FLAME", loc.x, loc.y + 1, loc.z, 3, 0.1, 0.1, 0.1, 0.02)
end
end)
end,
on_destroy = function(context)
if context.state.particle_task then
context.scheduler:cancel(context.state.particle_task)
end
end
}
scheduler:cancel(taskId)
通过 ID 取消已计划的任务。
| 参数 | 类型 | 说明 |
|---|---|---|
taskId | int | run_later 或 run_repeating 返回的任务 ID |
如果您启动了重复任务,务必在 on_destroy 中(或不再需要时)取消它。忘记取消会导致后台任务一直运行直到 prop 从服务器移除,浪费性能并可能导致错误。
context.state
一个在 prop 整个生命周期内持久化的普通 Lua 表。用于存储标志、计数器、任务 ID、切换状态以及需要在 hook 之间共享的任何数据。
on_spawn = function(context)
context.state.is_open = false
context.state.click_count = 0
context.state.task_id = nil
end,
on_right_click = function(context)
context.state.click_count = (context.state.click_count or 0) + 1
end
只有 context.state 在 hook 调用之间持久化。所有其他上下文表(context.prop、context.world、context.event 等)每次都会重新构建。
context.log
控制台日志方法。消息在服务器控制台中以脚本文件名为前缀。
| 方法 | 说明 |
|---|---|
log:info(message) | 信息消息 |
log:warn(message) | 警告消息 |
log:error(message) | 错误消息(功能上与 warn 相同) |
示例
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Script loaded!")
end,
on_right_click = function(context)
context.log:warn("Prop was clicked -- this is a debug warning")
end
}
运行时模型
每个 prop 一个运行时
每个附加了脚本的 prop 实体都会获得自己独立的 Lua 运行时实例。当 prop 生成时,FMM 加载 Lua 源代码,在新的沙盒环境中执行,并存储返回的表。当 prop 被移除时,运行时会关闭。
这意味着:
- 在文件作用域声明的局部变量对该 prop 实例是私有的。
context.state在 prop 实例之间完全隔离,即使它们共享相同的脚本文件。
任务所有权
通过 context.scheduler 创建的所有任务归创建它们的运行时所有。当 prop 被移除时:
- 运行时关闭。
- 所有拥有的任务——无论是一次性的还是重复的——都会自动取消。
- 所有区域监视都会被清除。
执行预算
每次 hook 调用和每次回调调用都会计时。如果单次调用超过 50 毫秒,脚本将被禁用并在控制台显示警告:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
为了保持在预算内:
- 避免在 hook 中使用无限循环。
- 保持
on_game_tick处理程序轻量——它们每个 tick 都会运行。 - 使用
context.scheduler:run_repeating(...)将工作分散到多个 tick 中。