跳至正文
版本:最新版 - a1.169.2 ⚖️

调试与日志

如何查找并解决脚本中的问题:读取日志与错误、快速重新加载代码以及检查 UI。

打印到控制台​

Console 静态类以不同的日志级别将消息输出到控制台(及日志文件):

Shared/Index.lua
Console.Log("Normal message") -- 始终显示
Console.Warn("Something looks wrong") -- 橙色,显示堆栈追踪
Console.Error("Something is broken") -- 红色,显示堆栈追踪
Console.Debug("Only shown with log level 2 or 3") -- 默认隐藏

它们都支持使用 string.format 说明符进行格式化,因此你无需手动拼接值:

Console.Log("玩家 %s 拥有 %d 生命值,位于 %s", player:GetName(), character:GetHealth(), tostring(character:GetLocation()))
提示

print(...) 同样有效,它会被重定向到 Console.Log。

若要打印表的内容,请使用 NanosTable.Dump(my_table)。

日志级别​

默认情况下,Console.Debug 消息和内部详细日志是隐藏的。若要查看它们:

  • 服务器:在 Config.toml 的 [debug] 节中设置 log_level = 2(调试)或 3(详细),在启动服务器时传递 --log_level 2,或运行控制台命令 log_level 2。
  • 客户端:在游戏设置的调试部分中更改日志级别。

日志在哪?​

打印到控制台的所有内容也会保存到磁盘上:

端位置
服务器服务器可执行文件旁边的 .logs/ 文件夹。 NanosWorldCore.log 为最近一次会话,更早的会话将在文件名中包含日期并予以保留
客户端%LocalAppData%\NanosWorld\Saved\Logs\

在客户端上,你还可以通过按键绑定(可在设置中配置)打开游戏内控制台,以便在游玩时查看日志并运行命令。

读取 Lua 错误​

当脚本运行失败时,错误会以红色打印,并指出发生位置(如在哪个事件内部),随后是堆栈追踪:导致错误的函数调用链,以及每个调用的文件和行号。第一行([1])即为错误发生的位置。例如:

ERROR Lua Error on Class 'my-package' Event 'TakeDamage':
- [1] [my-package/Server/Index.lua]:24: attempt to call a nil value (global 'Sound')
- [2] [my-package/Server/Index.lua]:77: in function <[string "my-package/Server/Index.lua"]:69>

这意味着在 my-package/Server/Index.lua 的第 24 行中,在 TakeDamage 事件内部,代码尝试调用 Sound(...),但 Sound 在此处不存在。在这种情况下,是因为 Sound 是一个仅限客户端的类,而代码正运行在服务器端!

提示

请始终优先修复你看到的第一个错误。后续的其他错误通常都是由它引起的。

常见错误及其通常含义​

attempt to index a nil value​

函数返回了 nil 而你直接使用了该结果,例如玩家未附身任何物体时的 player:GetControlledCharacter(),或道具数量较少时的 Prop.GetByIndex(10)。在使用前先检查是否为 nil

attempt to call a nil value (method 'X') 或 (global 'X')​

方法或类不存在,或者在对应端不可用(例如在服务器端生成仅限客户端的类)。请在脚本参考中检查其名称和主控

attempt to concatenate a boolean/nil value​

对非字符串或非数字的内容使用了 ..。请使用 tostring(value) 或 Console.Log("%s", value) 格式化

attempt to perform arithmetic on a nil value​

用于数学计算的变量从未被赋值,例如 GetValue 返回了 nil。请传入回退值:GetValue("score", 0)

Expected a class as parameter​

你向 IsA 传入了字符串,请直接使用类本身:entity:IsA(Weapon)

Invalid Channel!、Invalid Index! 等​

参数超出了允许的范围,请检查脚本参考中的方法描述

重新加载代码​

测试更改时无需重启服务器。在服务器控制台中,请使用:

package reload my-package​

卸载并重新加载包,销毁其生成的实体(如果已启用 auto_cleanup)。玩家将自动接收更新后的客户端文件

package hotreload my-package​

重新加载所有文件,但保持 Lua 内存(全局变量)原样不变 |

package reload all​

重新加载所有包,重启整个 Lua 虚拟机 |

由于重新加载时会再次触发 Load 事件,因此良好的作法是编写好你的包,使其在玩家已连接时重新加载也能正常工作。例如,在 Player "Spawn" 时为玩家生成角色,同时也应在 Package "Load" 时遍历已经连接的玩家(参阅快速开始)。

调试 WebUI​

WebUI 运行在真实的 Chromium 浏览器中,因此你可以使用其开发者工具来检查 HTML、查看 JavaScript 错误并调试代码:

Client/Index.lua
local my_ui = WebUI("My UI", "file://UI/index.html")

-- 打开此 WebUI 的 Chromium DevTools
my_ui:OpenDevTools()

JavaScript 的 console.log 消息也会显示在游戏控制台中,其日志类型为 WebUI。

调试世界​

  • Debug 静态类可在世界中绘制线段、框体、球体和文本,非常适合用于可视化位置、方向和追踪射线。追踪射线也可以使用 TraceMode.DrawDebug 自行进行绘制。
  • 若要查看实体的同步方式以及谁是其网络主控,请在设置中启用绘制网络调试(设置 -> 调试)。参阅调试网络与网络主控。
Client/Index.lua
-- 在角色所在位置绘制一个红色球体,持续 10 秒
Debug.DrawSphere(my_character:GetLocation(), 50, 12, Color.RED, 10)

性能问题​

如果服务器记录了 Server Tick too high! 警告或游戏变慢,请参阅性能分析指南以找出耗时过长的代码。