快速上手

写一行、打个标签、断言点什么,再把这一行交给别处。

更新于 2026-09-08

安装

首先,通过 VCC(VRChat Creator Companion)把日志包添加到你的 Unity 项目。打开你项目的 vccproject.json 并添加包,或者使用 VCC 界面直接安装。

安装后,包在你的项目中可用,你就可以开始使用下面的日志 API 了。

写一行

加上命名空间就能写。场景里不用放东西,也没有要连的引用。

using Udonite.Logging;

public class Door : UdoniteBehaviour
{
    public override void Interact()
    {
        Log.Info("opened");
    }
}
[Door.Interact:8] opened

Log.WarningLog.Error 把同样的一行写进 Console 的另外两个频道。

类型名是从文件名来的。 运行时没有办法问 Udon「包着我的类型是什么」,而 Unity 只认类型名和文件名一致的 behaviour,所以对写日志的 behaviour 来说这两者本来就是同一个字符串。如果从一个名字不同的类里调用,出来的是文件的名字,不是那个类的。

给相关的行打标签

标签把属于同一件事的行归到一起,位置在调用点前面。

Log.Info("hit for " + damage, "combat");
[combat] [Weapon.Fire:22] hit for 3

标签就是行里的普通文字,所以 Console 自带的搜索框就能筛。

断言点什么

Log.Assert 只在条件为假时报告,并且把那个条件的源码原样引出来:

Log.Assert(owner != null);
Log.Assert(players.Length > 0);
[assertion failed] [Room.Join:31] owner != null
[assertion failed] [Room.Join:32] players.Length > 0

这个引用就是它比「一个 if 加一个 Error」更值得用的理由:它说的是什么不成立,而不只是有什么不成立;而且以后改了条件,它说的话依然是对的。

如果光看条件说明不了什么,就用消息顶替这段引用:

Log.Assert(state == Ready, "房间还没加载完,join 处理就跑了");

它只报告然后返回,绝不抛异常。 在 Udon 里抛异常会让那个 behaviour 在这一整局里停摆,本来是个诊断,结果成了世界里所有人的故障。

把一行交给别处

世界里的面板、一个环形缓冲、要送出客户端的字符串——为有去处的那一行,Log.Entry 不写出来,而是把零件交给你:

LogEntry entry = Log.Entry("hit for " + damage, LogLevel.Warning, "combat");

panel.Show(entry.Message, entry.Tag, entry.Time);

Log.Write(entry);

MessageTextTagTypeMemberLineLevelTime 各自是独立的字段。两米外的一块面板想要的部分,和控制台想要的部分本来就不一样。

为了让普通调用保持免费,这是一个单独的调用。 每次 Entry 都会分配一个对象,而一个在 Update 里写日志的世界,没道理为没人读的对象付钱。Log.Info 和它的同伴什么都不返回。

它的代价

一次日志调用要拼字符串,而世界跑在十秒的 VM 预算之下。在人的节奏上这等于没有,在热循环里就是真金白银。别放进每帧、每个玩家都会跑的代码里。

除了把调用删掉,没有办法关掉日志。本该干这件事的机制是 [Conditional],它会把调用连同参数一起抹掉,但 Udonite 目前还不认它。

出了点问题 重新加载