世界日志
从 Unity Console 盯着一个正在跑的世界,以及一个出错的 behaviour 长什么样。
世界一离开 Editor,Unity 的 Console 就什么都看不见了。Play 模式是日志最后一处好读的地方,可世界并不在 Play 模式里坏掉——它坏在有八个人的时候,在别人的网络上,在你一小时前上传的那个版本里。
Udonite → Open Window → Settings → Logging 会在你身处世界之中时读客户端的日志,把你的行放回 Console。
三个设置,其实是一个
| 选择 | 转发什么 |
|---|---|
| 关闭 | 什么都不 |
| Udonite 日志 | 只有用 Log 写的行 |
| 全部日志 | 连客户端自己写的也算,那是相当大的一堆 |
默认是 Udonite 日志。监听只读不写,而且只要世界没在跑、没在写日志,它就什么都不转发。
全部日志 在一次读取里到 200 行就停下,并告诉你丢了多少。热闹的世界一次就能甩回来几千行,而 Console 远在拒绝它们之前就已经慢得像在爬。
如果没在 VRChat 自己的设置里打开完整日志,这里什么都不会来。Console 一片空白,最常见的原因就是这个。
转发过来的行,就是你写的那一行
[combat] [Scoreboard.Award:14] hit for 3
Play 模式里看到的是它,真实世界里看到的也是它。路上什么都不加:没有时间,没有级别词,没有颜色,没有过滤。
这是有意为之,不是没做完。一行字要是因为跑在哪里而有两种读法,它就没法和自己比对,而比对正是转发它的全部理由。时间也没丢——客户端在自己的文件里给每一行都盖了时间,Console 也盖自己的。
不止一个客户端
要测试联机,就得在同一台机器上、用同一个账号开两个客户端。两边的显示名一样,世界也无法告诉你某一行来自哪个窗口。
客户端自己把这件事解决了:每个客户端都写自己的日志文件。所以从第二个客户端开口的那一刻起,Console 就开始编号。
[client 1] [Scoreboard.Award:14] hit for 3
[client 2] [Scoreboard.Award:14] hit for 5
只有一个客户端在说话时,什么都不会被编号。 一个永远只写着 client 1 的前缀谁也告诉不了,却要占掉每一行那么宽。
编号按谁先写日志排,而不是按谁先启动:一个启动后停在加入界面的客户端,对看着 Console 的人来说不是 client 1。
已经在 Console 里的行不会因为第二个客户端出现而重新标注。重新标注做不到,事后猜测比让它们保持原样更糟。
当一个 behaviour 出错
这是 Udon 世界里最糟也最安静的一件事。VM 抛出异常,客户端接住,写一行,然后把那个 behaviour 在这一整局里禁用掉。此外什么都不会发生。门就是不动了,世界照旧在它周围转。
Console 会把这件事报出来:
An Udon behaviour faulted and is disabled for the rest of the session.
System.NullReferenceException: Object reference not set to an instance of an object (program counter 812)
程序计数器是编译后程序里的地址,不是你源码的行号。 要把它换算过来,需要一张从地址到源码的对照表,而 Udonite 目前不生成这张表。所以它不去猜,原样把客户端写的传过来。光是这条消息点到的东西,通常已经够你找到调用的地方了;再配上你自己撒在周围的那些 Log,就能看出这个 behaviour 走到了哪一步。
客户端随后写的几百行栈转储和堆转储,就留在它们该待的地方——那个文件里。