参考
网络包的每个成员、它做什么,以及附带的那条规则。
Synced<T>
behaviour 上的字段或自动属性,会变成一个按你声明命名的复制变量。
Value |
读取;写入会复制,且只有所有者能写 |
Subscribe(handler) |
值到达时在每个客户端上运行处理器 |
接收 (T old, T current) 的 Subscribe(handler) |
同样,但也告诉你它是从什么变过来的 |
Unsubscribe(handler) |
停止;移除没加过的不做任何事 |
MarkChanged() |
说明同步数组的某个元素变了,这是赋值显示不出来的 |
处理器在整批更新落地之后才跑,所以其中一个可以读同一 behaviour 上的另一个同步值,读到的是随它一起到达的值。
Room
静态的,所以谁都能发:behaviour、普通类、抽象类。
Send(message) |
发给所有人 |
Send(message, target) |
All、Master、Others |
Send(message, player) |
发给某一个玩家,用他自己的 id |
Subscribe<T>(handler) |
接收该类型中这个客户端该处理的每一条 |
Unsubscribe<T>(handler) |
停止 |
IsMaster |
这个客户端是不是在仲裁的那个 |
IsInstanceOwner |
这个客户端是不是开了这个实例 |
Master |
正在仲裁的人;实例稳定前为 null |
Players、PlayerCount |
现在在场的所有人;Players 会分配,不要每帧调用 |
LocalPlayer |
这个客户端的玩家 |
Bus、BusOf(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) |
在该物体上接收该类型 |
Received、Sent、Pending |
到达了多少、发出了多少、还在等线路的有多少 |
Sender |
这个通道属于谁,也就是消息来自谁 |
物体通道只有一个所有者。两个客户端往同一个通道发就会互相争抢,这正是房间消息改用每个玩家一个物体的原因。
Ownership
IsMine(gameObject) |
这个客户端能否写该物体的同步值 |
IsOwner(player, gameObject) |
那个玩家是否拥有它 |
Of(gameObject) |
谁拥有它 |
Claim(gameObject) |
若无人拒绝就取得 |
GiveTo(player, gameObject) |
交出去 |
IsClogged |
这个客户端的发送是否已经积压 |
MasterOwned
一个基类,它的 OnOwnershipRequest 只允许在仲裁的那个客户端,用于不许别人写的状态。继承它,而不是自己写那个重写。
NetworkTransform
由所有者发送、其他人插值的位置、旋转和缩放。设置项和回放的表现见移动物体。