跳到主要内容

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_clickon_right_clickon_left_click
on_interacton_right_click
on_hiton_left_click
on_tickon_game_tick
on_removeon_destroy
on_arrow_hiton_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_clickon_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() 可能不支持。使用标准粒子如 FLAMEHEARTHAPPY_VILLAGERNOTEENCHANT 等。

9. 声音不播放

  • 验证声音名称是有效的 Bukkit Sound 枚举常量且为大写。示例:"BLOCK_NOTE_BLOCK_HARP",而不是 "block.note_block.harp"
  • 验证位置坐标是否正确(不全为零或 NaN)。
  • 验证音量大于 0。

10. 状态意外重置

context.state 是按道具实例存在的,并在道具的生命周期内持续存在。如果状态似乎被重置了:

  • 道具可能已被移除并重新生成(每次生成都会创建新实例)。
  • 您可能在调度器回调中使用了错误的上下文变量来读取状态。始终使用回调自身的上下文参数。

延迟配置生成的工作原理

了解延迟配置系统有助于避免设置新道具时的困惑:

  1. 首次生成: 当道具生成且不存在相邻的 .yml 文件时,FMM 异步创建配置。这意味着文件在后台线程中写入,不会立即可用。

  2. 默认值: 生成的配置包含 isEnabled: true 和空的 scripts: [] 列表。

  3. 首次生成时没有脚本: 由于配置是在道具已经生成之后创建的(且没有列出脚本),道具在首次生成时不会关联任何脚本。

  4. 编辑并重新生成: FMM 创建配置后,您编辑它以添加脚本文件名。下次道具生成时,脚本将被加载。

  5. 配置位置: .yml 文件创建在与模型文件相同的目录中,具有相同的基本名称。例如:

    • 模型:plugins/FreeMinecraftModels/models/fountain.fmmodel
    • 配置:plugins/FreeMinecraftModels/models/fountain.yml
快速设置流程
  1. 将模型放入 models/
  2. 将脚本放入 scripts/
  3. 生成道具一次(生成 .yml
  4. 编辑 .yml 添加 scripts: [my_script.lua]
  5. 重新生成道具——脚本现在已激活

阅读错误消息

当 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. 检查钩子名称的拼写错误

钩子不触发的最常见原因是钩子名称拼写错误。脚本会无错加载,但拼写错误的钩子函数会在验证时被拒绝。


初学者学习路径

如果您想从零开始学习此系统,以下学习路径效果很好:

  1. 编写一个只包含 api_version = 1 和记录消息的 on_spawn 的文件。
  2. 将脚本添加到道具配置中,验证日志消息是否出现。
  3. 添加 on_right_click 并在道具被点击时记录日志。
  4. 添加 on_left_click 配合 context.event.cancel() 实现无敌。
  5. 在右键点击时播放动画。
  6. 在右键点击时添加声音。
  7. 添加状态和切换行为。
  8. 添加区域监视以实现近距离检测。
  9. 此后才开始编写带有调度器的复杂多钩子脚本。

每个步骤都建立在前一步的基础上,您可以在每个阶段进行测试。


下一步