网络
同步字段、自定义事件、类型化网络事件,以及 NetworkTransform 组件。
Udonite 底层直接使用 VRChat 自己的网络机制,规则和任何 Udon behaviour 完全一样:只有 GameObject 的所有者才能写入它的同步状态,而且只有 public 方法才能跨网络调用。
同步字段
给字段加上 [UdonSynced],并设置 behaviour 的同步模式:
using Udonite.Package.Runtime;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon.Common;
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class Counter : UdoniteBehaviour
{
[UdonSynced] public int count;
public override void Interact()
{
if (!Networking.IsOwner(gameObject))
Networking.SetOwner(Networking.LocalPlayer, gameObject);
count = count + 1;
this.RequestSerialization();
}
public override void OnDeserialization(DeserializationResult result)
{
Debug.Log("count is now " + count);
}
}
BehaviourSyncMode.Manual只在你调用this.RequestSerialization()时发送。Continuous会自动发送,None则完全不同步。[UdonSynced(UdonSyncMode.Linear)]和Smooth会在接收端对数值字段做插值。OnPreSerialization、OnPostSerialization和OnDeserialization会在每次传输前后触发。
响应变化
[FieldChangeCallback] 指定一个属性,每当该字段的同步值到达时,就会执行这个属性的 setter:
[UdonSynced, FieldChangeCallback(nameof(Lit))]
private bool lit;
public bool Lit
{
get => lit;
set
{
lit = value;
lamp.SetActive(value);
}
}
属性的类型必须与字段的类型完全一致。
自定义事件
任何 public 方法都可以按名称发送给其他客户端:
this.SendCustomNetworkEvent(NetworkEventTarget.All, nameof(Ring));
public void Ring()
{
bell.Play();
}
NetworkEventTarget.Owner 只发送给该对象的所有者。SendCustomEventDelayedSeconds 和 SendCustomEventDelayedFrames 会把一次本地调用推迟到之后执行。
类型化网络事件
如果负载需要结构,可以定义一个带 Serialize/Deserialize 的事件类,并在接收方的 behaviour 上放一个处理方法:
using Udonite.Package.Runtime;
using UnityEngine;
public class ScoreEvent : NetworkEvent
{
public int player;
public int score;
public void Serialize(ByteWriter writer)
{
writer.WriteInt32(player);
writer.WriteInt32(score);
}
public void Deserialize(ByteReader reader)
{
player = reader.ReadInt32();
score = reader.ReadInt32();
}
}
public class Scoreboard : UdoniteBehaviour
{
public void Award(int player, int score)
{
ScoreEvent evt = new ScoreEvent();
evt.player = player;
evt.score = score;
Udonite.Network.Send(evt, this);
}
[NetworkEventHandler]
public void OnScore(ScoreEvent evt)
{
Debug.Log("player " + evt.player + " scored " + evt.score);
}
}
Udonite.Network.Send(evt, receiver) 会把事件序列化,并在每个客户端上投递给 receiver 上那个以该事件类型为参数的 [NetworkEventHandler] 方法。请写完整的限定名:在有 using UnityEngine; 的作用域里,单独的 Network 会和 Unity 已废弃的 UnityEngine.Network 冲突。它依靠同步字段传输,因此只有当 receiver 所在 GameObject 的所有者调用时,才会到达其他客户端。
NetworkTransform
NetworkTransform 是一个开箱即用的 behaviour,用于同步位置、旋转和缩放,并带有插值与瞬移检测。把它加到物体上,编译,然后移动物体即可。如果同一物体上还有 VRC_Pickup,那么拾起时会取得所有权,放下时会发送静止时的姿态。发送频率、各通道的阈值以及瞬移判定距离都是 Inspector 上的字段。
所有权
重写 OnOwnershipRequest 并返回 false 即可拒绝所有权转移。OnOwnershipTransferred 会在所有者变化时于每个客户端触发。ClientSim 不会触发所有权请求,这部分请在已上传的世界里测试。