RequestSerialization()
- 作用:请求同步
UdonSynced
变量的状态到所有客户端。 - 调用时机:当一个客户端更改了带有
UdonSynced
属性的变量后,调用RequestSerialization()
以确保这些变化被同步到所有其他客户端。 - 执行顺序:
RequestSerialization()
会触发服务器在后台处理并将数据传播给其他客户端,但这是一个异步过程,调用后不会立即生效。
OnDeserialization()
- 作用:当客户端接收到来自服务器的同步数据时自动调用。
- 调用时机:当服务器将同步数据发送到客户端时,客户端接收到数据后,
OnDeserialization()
会被自动调用,用于处理这些同步数据并进行相应的状态更新。 - 执行顺序:在客户端接收到同步数据之后自动调用,不需要显式调用。
SendCustomNetworkEvent()
- 作用:发送一个自定义网络事件,并在指定的目标客户端上调用特定的方法。
- 调用时机:需要触发某个特定事件,并在所有或指定的客户端上执行相应的逻辑时使用。
- 执行顺序:通常在同步变量之后调用,以确保事件处理时变量状态已同步。
关系及执行流程
-
更改同步变量并请求同步:
- 客户端 A 更改
UdonSynced
变量的值,并调用RequestSerialization()
以请求服务器同步该变量。 RequestSerialization()
触发服务器处理同步请求,并在后台将数据传播给其他客户端。
- 客户端 A 更改
-
客户端接收同步数据:
- 服务器将同步数据发送给所有客户端,包括客户端 A 自己。
- 客户端 B 接收到同步数据后,自动调用
OnDeserialization()
方法。
-
执行网络事件:
- 在客户端 A 调用
RequestSerialization()
之后,可以调用SendCustomNetworkEvent()
以通知所有客户端执行某些操作。 - 这确保了当客户端接收到网络事件时,同步变量的最新状态已经生效。
- 在客户端 A 调用
代码示例及解析
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using TMPro;
public class EarthRotationController : UdonSharpBehaviour
{
[UdonSynced(UdonSyncMode.None)]
private bool isRotating = false; // 控制地球是否旋转的布尔变量
public GameObject earth; // 地球模型
public TextMeshPro statusText; // 显示地球旋转状态的文本
public float rotationSpeed = 10f; // 控制地球旋转速度
private void Start()
{
UpdateStatusText();
UpdateButtonState();
}
private void Update()
{
if (isRotating)
{
// 绕自身的 Y 轴旋转
earth.transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime, Space.Self);
}
}
public override void Interact()
{
// 检查并请求对象的拥有权
if (!Networking.IsOwner(gameObject))
{
Networking.SetOwner(Networking.LocalPlayer, gameObject);
}
// 切换地球旋转状态
isRotating = !isRotating;
// 请求同步变量 同步 isRotating 的值
RequestSerialization();
// 发送网络事件,通知所有客户端更新状态文本和按钮状态
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "UpdateStatusText");
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "UpdateButtonState");
}
private void UpdateButtonState()
{
if (!isRotating)
{
earth.transform.rotation = Quaternion.Euler(23.5f, earth.transform.rotation.eulerAngles.y, 0);
}
}
public void UpdateStatusText()
{
if (isRotating)
{
statusText.text = "Earth is rotating";
}
else
{
statusText.text = "Earth is stopped";
}
}
public override void OnDeserialization()
{
// 当同步变量更新时调用,确保状态同步
UpdateStatusText();
UpdateButtonState();
}
}
代码解析
-
更改同步变量并请求同步:
- 在
Interact()
方法中,当用户点击按钮时,切换isRotating
变量的状态。 - 调用
RequestSerialization()
请求同步isRotating
变量的值。
- 在
-
发送网络事件:
- 调用
SendCustomNetworkEvent()
发送自定义网络事件,通知所有客户端调用UpdateStatusText()
和UpdateButtonState()
方法。 - 这些方法负责更新文本状态和地球的旋转状态。
- 调用
-
处理同步数据:
- 当其他客户端接收到同步数据时,自动调用
OnDeserialization()
方法。 OnDeserialization()
方法中调用UpdateStatusText()
和UpdateButtonState()
,确保状态在所有客户端同步。
- 当其他客户端接收到同步数据时,自动调用
OnDeserialization() 下执行的方法和 SendCustomNetworkEvent()传递的方法是一样的,这是为什么?
OnDeserialization()
当同步变量更新时(例如通过 RequestSerialization() 请求后),OnDeserialization() 在所有客户端被调用。
我们在 OnDeserialization() 中调用 UpdateStatusText() 和 UpdateButtonState() 以确保所有客户端的状态一致。
SendCustomNetworkEvent()
当需要立即通知所有客户端执行某些逻辑时(例如在按钮点击事件中),使用 SendCustomNetworkEvent()。
即使客户端已经在 OnDeserialization() 中更新了状态,我们依然通过 SendCustomNetworkEvent() 确保所有客户端执行相应的更新逻辑,避免任何潜在的延迟或不同步问题。