Lua 脚本:故障排除
本页介绍编写或调试 FreeMinecraftModels 道具脚本时可能遇到的常见问题,以及使用延迟配置生成系统的技巧。如果您正在寻找可运行的示例,请参阅示例与模式。如果您刚刚入门,请参阅入门指南。
常见问题
1. 配置文件未加载 / 脚本未关联
症状: 道具已生成,但不响应点击或任何钩子。
原因和解决方法:
-
尚不存在
.yml配置文件。 FMM 在道具首次生成时延迟创建配置。首次生成模型时,FMM 会异步创建带有默认值(已启用、无脚本)的.yml配置。您需要编辑生成的配置以添加脚本文件名,然后重新生成道具。 -
配置中设置了
isEnabled: false。 打开模型文件旁边的.yml文件,将其设置为isEnabled: true。 -
scripts:列表为空。 添加您的脚本文件名:isEnabled: true
scripts:
- my_script.lua -
.yml文件名与模型文件名不匹配。 配置必须与模型文件具有相同的基本名称。例如,torch_01.fmmodel需要同一目录下的torch_01.yml。
2. 未找到脚本文件
症状: 控制台显示:[FMM Scripts] Script 'my_script.lua' not found in scripts/ folder
原因和解决方法:
-
目录错误。 脚本文件必须位于
plugins/FreeMinecraftModels/scripts/,而不是模型文件旁边。 -
文件名不匹配。
.yml配置中的名称必须与scripts/文件夹中的文件名完全匹配,包括大小写和.lua扩展名。 -
文件不存在。 请仔细检查
.lua文件是否确实存在于scripts/文件夹中。
3. 脚本完全无法加载
症状: 没有控制台错误,但没有钩子触发。
检查服务器控制台在启动时是否有 Lua 语法错误。最常见的原因是:
- 缺少
end来关闭函数或if块 - 括号不匹配
- 返回的表中钩子定义之间缺少逗号
- 文件不以
.lua结尾
如果存在 Lua 错误,控制台会打印一个 [Lua] 错误块,包含文件名、行号和描述。
4. 钩子从未触发
症状: 脚本已加载(您看到了 [FMM Scripts] Bound script 消息),但特定的钩子从未触发。
验证钩子名称是否与钩子参考中列出的完全一致。常见错误:
| 错误名称 | 正确名称 |
|---|---|
on_click | on_right_click 或 on_left_click |
on_interact | on_right_click |
on_hit | on_left_click |
on_tick | on_game_tick |
on_remove | on_destroy |
on_arrow_hit | on_projectile_hit |
还要验证道具是否确实有关联的盔甲架实体。某些道具配置可能不会产生可点击的实体。
5. 超时 / 超出执行预算
症状: 控制台显示如下消息:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
脚本在单次钩子调用中执行了过多的工作。常见原因:
- 在
on_game_tick中遍历了过多的实体 - 每 tick 创建了过多的粒子效果
- 在没有将工作分散到多个 tick 的情况下运行了高开销的循环
解决方法: 将繁重的工作放到基于状态的冷却时间之后,或者使用 scheduler:run_repeating() 配合合理的间隔来代替 on_game_tick。
6. 点击钩子中 context.event 为 nil
这在 on_left_click 和 on_right_click 中通常不应该发生,但始终使用以下方式进行保护:
if context.event then
context.event.cancel()
end
在调度器回调内部,context.event 始终为 nil ——这是预期行为。事件修改只能在事件钩子本身内部进行。
7. 动画不播放
症状: play_animation() 返回 false,或者没有可见的变化。
原因和解决方法:
-
动画名称错误。 名称必须与模型文件中定义的完全匹配。检查您的
.bbmodel或.fmmodel文件以获取正确的动画名称。 -
模型没有动画。 并非所有模型都有动画。验证模型文件是否确实包含动画数据。
-
玩家不在资源包范围内。 动画在服务器端执行,但玩家需要加载 FMM 资源包才能看到模型。
8. 粒子不出现
- 验证粒子名称是有效的 Bukkit
Particle枚举值且为大写:"FLAME",而不是"flame"。 - 验证位置位于已加载的区块中。如果附近没有玩家,区块可能已卸载。
- 验证
count至少为 1。 - 某些粒子(如
DUST)需要特定的额外数据,基本的spawn_particle()可能不支持。使用标准粒子如FLAME、HEART、HAPPY_VILLAGER、NOTE、ENCHANT等。
9. 声音不播放
- 验证声音名称是有效的 Bukkit
Sound枚举常量且为大写。示例:"BLOCK_NOTE_BLOCK_HARP",而不是"block.note_block.harp"。 - 验证位置坐标是否正确(不全为零或 NaN)。
- 验证音量大于 0。
10. 状态意外重置
context.state 是按道具实例存在的,并在道具的生命周期内持续存在。如果状态似乎被重置了:
- 道具可能已被移除并重新生成(每次生成都会创建新实例)。
- 您可能在调度器回调中使用了错误的上下文变量来读取状态。始终使用回调自身的上下文参数。
延迟配置生成的工作原理
了解延迟配置系统有助于避免设置新道具时的困惑:
-
首次生成: 当道具生成且不存在相邻的
.yml文件时,FMM 异步创建配置。这意味着文件在后台线程中写入,不会立即可用。 -
默认值: 生成的配置包含
isEnabled: true和空的scripts: []列表。 -
首次生成时没有脚本: 由于配置是在道具已经生成之后创建的(且没有列出脚本),道具在首次生成时不会关联任何脚本。
-
编辑并重新生成: FMM 创建配置后,您编辑它以添加脚本文件名。下次道具生成时,脚本将被加载。
-
配置位置:
.yml文件创建在与模型文件相同的目录中,具有相同的基本名称。例如:- 模型:
plugins/FreeMinecraftModels/models/fountain.fmmodel - 配置:
plugins/FreeMinecraftModels/models/fountain.yml
- 模型:
- 将模型放入
models/ - 将脚本放入
scripts/ - 生成道具一次(生成
.yml) - 编辑
.yml添加scripts: [my_script.lua] - 重新生成道具——脚本现在已激活
阅读错误消息
当 Lua 道具脚本出错时,控制台会打印一个 [Lua] 错误块。这些消息会用通俗易懂的语言准确地告诉您哪个文件、哪一行、哪个钩子以及出了什么问题。
典型的错误如下所示:
[Lua] Error in 'my_door.lua' at line 12 during 'on_right_click':
[Lua] -> You tried to call a method or function that doesn't exist.
[Lua] -> Check the method name for typos, or make sure you're using ':' (colon) for method calls, not '.' (dot).
[Lua] -> Script has been disabled for this entity to prevent further errors.
系统将常见的 Lua 错误翻译为通俗易懂的语言:
| 原始 Lua 错误 | 控制台告诉您的内容 |
|---|---|
attempt to call nil | 您尝试调用一个不存在的方法或函数。检查拼写错误和 : 与 . 的用法。 |
index expected, got nil | 您尝试访问一个 nil 对象的字段。检查之前的代码是否已初始化它。 |
attempt to index | 您尝试访问一个 nil 或无效值的属性。 |
bad argument | 函数接收了错误类型的参数。消息显示了期望的类型与实际类型。 |
| Timeout | 您的脚本在 'hook_name' 中耗时 Xms(限制:50ms)——脚本已被禁用以防止卡顿。 |
在深入代码之前,请始终阅读完整的 [Lua] 错误消息。它通常会直接指向解决方法。
不要假设存在未文档化的方法
FMM Lua API 公开了一组特定的方法。不要假设存在简写名称或替代名称。常见错误:
context.prop:get_location()——不存在。使用context.prop.current_location(字段,不是方法)。context.prop:set_animation("open")——不存在。使用context.prop:play_animation("open", true, true)。context.event:setCancelled(true)——不存在。使用context.event.cancel()。context.cooldowns:check_local(...)——在 FMM 中不存在。使用context.state配合scheduler:run_later()实现冷却。context.player——在 FMM 道具脚本中不存在。使用context.world:get_nearby_players()查找道具附近的玩家。context.boss——不存在。那是 EliteMobs 的。在 FMM 中使用context.prop。
如有疑问,请查看 道具 API 页面。如果那里没有文档记录,则表示不存在。
调试技巧
1. 大量使用 context.log:info()
调试时在每个步骤添加日志消息:
on_right_click = function(context)
context.log:info("Right click received!")
context.log:info("Event present: " .. tostring(context.event ~= nil))
context.log:info("State is_open: " .. tostring(context.state.is_open))
end
2. 在启动时检查控制台
FMM 会为每次成功绑定记录 [FMM Scripts] Bound script 'X' to prop 'Y'。如果您没有看到此消息,则配置或脚本未被加载。
3. 验证模型文件路径
.yml 配置必须是模型文件的同级文件(相同目录、相同基本名称)。通过检查以下内容来验证:
- 模型文件路径:
plugins/FreeMinecraftModels/models/my_model.fmmodel - 配置文件路径:
plugins/FreeMinecraftModels/models/my_model.yml
4. 单独测试钩子
构建复杂脚本时,先单独测试每个钩子。一次添加一个钩子,验证其触发后再添加下一个。
5. 检查钩子名称的拼写错误
钩子不触发的最常见原因是钩子名称拼写错误。脚本会无错加载,但拼写错误的钩子函数会在验证时被拒绝。
初学者学习路径
如果您想从零开始学习此系统,以下学习路径效果很好:
- 编写一个只包含
api_version = 1和记录消息的on_spawn的文件。 - 将脚本添加到道具配置中,验证日志消息是否出现。
- 添加
on_right_click并在道具被点击时记录日志。 - 添加
on_left_click配合context.event.cancel()实现无敌。 - 在右键点击时播放动画。
- 在右键点击时添加声音。
- 添加状态和切换行为。
- 添加区域监视以实现近距离检测。
- 此后才开始编写带有调度器的复杂多钩子脚本。
每个步骤都建立在前一步的基础上,您可以在每个阶段进行测试。