参考

网络包的每个成员、它做什么,以及附带的那条规则。

更新于 2026-09-10

Synced<T>

behaviour 上的字段或自动属性,会变成一个按你声明命名的复制变量。

Value 读取;写入会复制,且只有所有者能写
Subscribe(handler) 值到达时在每个客户端上运行处理器
接收 (T old, T current)Subscribe(handler) 同样,但也告诉你它是从什么变过来的
Unsubscribe(handler) 停止;移除没加过的不做任何事
MarkChanged() 说明同步数组的某个元素变了,这是赋值显示不出来的

处理器在整批更新落地之后才跑,所以其中一个可以读同一 behaviour 上的另一个同步值,读到的是随它一起到达的值。

Room

静态的,所以谁都能发:behaviour、普通类、抽象类。

Send(message) 发给所有人
Send(message, target) AllMasterOthers
Send(message, player) 发给某一个玩家,用他自己的 id
Subscribe<T>(handler) 接收该类型中这个客户端该处理的每一条
Unsubscribe<T>(handler) 停止
IsMaster 这个客户端是不是在仲裁的那个
IsInstanceOwner 这个客户端是不是开了这个实例
Master 正在仲裁的人;实例稳定前为 null
PlayersPlayerCount 现在在场的所有人;Players 会分配,不要每帧调用
LocalPlayer 这个客户端的玩家
BusBusOf(player) 承载房间消息的物体

处理器可以是 (T)(VRCPlayerApi, T)。同一个类型两种都能订阅,两种都会跑。处理器可以是 private。

IsMaster 是权限,IsInstanceOwner 是许可。 master 负责仲裁,且在该客户端离开时转移;实例所有者是开了这个地方的人,在公开实例里通常根本不在场。用实例所有者来判断权限的世界,在作者自己的测试实例里完全正常,在其他任何地方都没有权限。

behaviour 扩展方法

这个物体自己的通道,写在就是该物体的那个 behaviour 上。不是房间:Room.Send 经房间总线到达每个客户端,而这些只在这个物体上流动,所以不必再带一个 id 说明指的是哪个物体。

this.Send(message) 在这个物体自己的通道上发给所有人
this.Send(message, target)this.Send(message, player) 带寻址的形式
this.Subscribe<T>(handler)this.Unsubscribe<T>(handler) 接收消息的处理方法
接收 (VRCPlayerApi, T)this.Subscribe<T>(handler) 同样,但同时告诉你是谁发的
this.Pending() 已发出但 VRChat 还没接收的消息数

发送需要拥有该物体。 只有所有者的写入会被复制,所以非所有者当场就被告知,而不是事后才发现消息根本没发出去。若想让任意客户端都能发,先取得所有权。

Pending() 几乎总是 0。若一直大于 0,说明一批的体积超过了一次 manual sync 能带走的量,世界应该少发一些。

客户端不会响应自己到达之前发出的东西。 每一批都带着它是何时生成的,后加入的客户端会丢弃它,而不是重放别人的历史。

NetworkEvent

消息的基类。重写它携带什么:

Serialize(ByteWriter) 写入字段
Deserialize(ByteReader) 按同样的顺序读回来

子类需要一个无参构造函数,因为接收方是在还没有内容可填之前先创建它的。没有字段的信号两个方法都不用重写。消息是什么类型用一个字节传输,编号在构建时按整个项目分配,所以同一个世界里的两个 behaviour 不会对某个编号的含义产生分歧。

Serialize/Deserialize 接收的 ByteWriter/ByteReader 现在在 Udonite Serialization 里——本包只是依赖它,并不包含它。完整成员列表见那边的参考文档

NetworkBus

某个物体自己的消息通道。放到物体上并引用它。

channel.Send(message)channel.Send(message, target) 在该物体上做带类型发送
channel.Subscribe<T>(handler)channel.Unsubscribe<T>(handler) 在该物体上接收该类型
ReceivedSentPending 到达了多少、发出了多少、还在等线路的有多少
Sender 这个通道属于谁,也就是消息来自谁

物体通道只有一个所有者。两个客户端往同一个通道发就会互相争抢,这正是房间消息改用每个玩家一个物体的原因。

Ownership

IsMine(gameObject) 这个客户端能否写该物体的同步值
IsOwner(player, gameObject) 那个玩家是否拥有它
Of(gameObject) 谁拥有它
Claim(gameObject) 若无人拒绝就取得
GiveTo(player, gameObject) 交出去
IsClogged 这个客户端的发送是否已经积压

MasterOwned

一个基类,它的 OnOwnershipRequest 只允许在仲裁的那个客户端,用于不许别人写的状态。继承它,而不是自己写那个重写。

NetworkTransform

由所有者发送、其他人插值的位置、旋转和缩放。设置项和回放的表现见移动物体

出了点问题 重新加载