Skip to main content

网络组件

本文档涵盖可在 Udon 程序中使用的网络组件、属性和事件。

网络属性​

可以从 Networking 获取的特殊属性:

属性名称描述
LocalPlayer返回本地玩家 VRC Player API 对象。
IsInstanceOwner在邀请、邀请+、好友和好友+实例中,为实例创建者返回 true。
在群组实例、公共实例和 SDK 的"Build & Test"模式下始终返回 false。
InstanceOwner返回拥有该实例的玩家的 VRC Player API 对象。如果拥有者当前不在实例中,则返回 null。如果拥有者返回,则再次返回实例拥有者。
实例拥有者具有特殊的审核权限。实例所有权永远不会改变。
IsMaster如果本地玩家是实例主控者,则返回 true。主控者是网络游戏对象的默认拥有者。
不应将其用于安全或限制对世界的访问。应使用 IsInstanceOwner 或实现审核系统。
Master返回当前实例主控者的 VRC Player API 对象。始终有效。
IsNetworkSettled如果实例中的所有数据都已反序列化、应用并准备就绪,则返回 true。
IsClogged如果有太多数据试图发出,则返回 true。你可以使用此方法等待直到网络畅通或调整逻辑。
SimulationTime返回玩家或具有网络组件的对象的当前模拟时间。详见下文。

模拟时间​

模拟时间是一个时间戳,指对象在时间上被回溯模拟的程度。该值在内部用于 VRCObjectSync 和玩家,但也可以在 Udon 脚本中使用。例如,如果你的 Time.realtimeSinceStartup 是 45,而对象的 SimulationTime 是 44.5,则 VRChat 认为需要 500ms 的延迟来平滑复制该对象。你可以使用该数字来了解 VRCObjectSync 正在做什么,或创建自己的类似系统。例如,如果你执行 Time.realTimeSinceStartup - SimulationTime(player),则会准确告诉你该玩家此刻的延迟。

模拟时间会根据网络条件频繁调整,包括延迟、可靠性和接收数据包的频率等因素。调整的目标是尽可能接近实时以减少延迟,但留出足够的空间以防止卡顿。有多种因素可能导致卡顿,但一个例子是从拥有者接收到的数据包不足。

网络事件​

以下是网络系统提供的用于控制数据同步方式的事件。

OnPreSerialization​

此事件在序列化数据即将发送前触发,是设置要与其他玩家更新的同步变量的好时机。

OnDeserialization​

当同步数据从字节转换回可用变量时触发此事件。它不会告诉你哪些数据已更新,而是作为一个起点,更新所有监视同步变量的内容,或检查新数据与旧数据并做出特定更新。

OnDeserialization(DeserializationResult)​

与 OnDeserialization 相同,但包含关于请求发送和接收时间的额外信息。

DeserializationResult​

DeserializationResult 包含三个属性:

  • sendTime:此消息发送的时间(秒)。
  • receiveTime:此消息接收的时间(秒)。
  • isFromStorage:如果为 true,则包含的数据是从存储中恢复的,而不是从其他实时客户端接收的。

sendTime 和 receiveTime 都基于 VRChat 启动以来的时间(秒),从你的视角计算(参见 Time.realtimeSinceStartup)。这意味着,如果你想知道某个 Deserialization 是在多少秒前发送的,可以用 Time.realtimeSinceStartup - sendTime 计算。

请注意,每个用户的 Time.realtimeSinceStartup 都不同,因此一个玩家的 sendTime 将与另一个玩家的 sendTime 不同。因此,如果你想将特定的 sendTime 同步给其他玩家,需要减去你的 Time.realtimeSinceStartup 来计算偏移量。然后,当其他玩家接收到该偏移量时,他们可以将自己的 Time.realtimeSinceStartup 加回偏移量,以确定相对于自己时钟的绝对时间。

如果消息是在你启动 VRChat 之前由其他人发送的,SendTime 可能为负数。

此事件在尝试发送序列化数据之后立即触发。它返回一个 SerializationResult 结构体,包含 success 布尔值和 byteCount 整数,表示发送的字节数。

OnSpawn​

此事件已弃用——如果你希望在对象从池中"Spawn"时执行某些操作,请使用常规的 OnEnabled 事件。

OnOwnershipRequest​

当有人请求获取所有权时触发此事件。它包含请求者和被请求拥有者的 PlayerObject。要批准或拒绝更改,请在"Set Return Value"节点中设置布尔值。此逻辑在请求者和拥有者双方本地运行,因此请注意,双方逻辑不一致会导致不同步。这最可能表现为所有权转移被拥有者意外拒绝。

OnOwnershipTransferred​

当对象的所有权发生变更时,此事件会对实例中的所有人触发,并包含新拥有者的 PlayerObject。

OnMasterTransferred​

当实例主控者因前一实例主控者离开实例而发生变化时,此事件会对实例中的所有人触发。 它包含一个参数 newMaster,即成为主控者的玩家的 VRC Player API 对象。此参数始终有效。 对于第一个加入新实例的用户,此事件将在 OnPlayerJoined 之后触发,表明主控者状态从"无人"转移而来。

OnVariableChanged​

这是一种特殊类型的事件,你可以为任何变量创建。在 Udon Graph 中,你可以通过按住 alt 键将变量拖入图表来创建。此事件会在变量发生变化时检测到,包括从其他玩家接收到同步变量时。

  • 更改数组的内容不会触发更改,因为数组本身仍然是同一个。
  • OnVariableChanged 在变量本身被写入时立即触发,这与 OnDeserialization 不同,后者在完成所有同步变量的写入后才触发。这意味着,如果你从一个同步变量使用 OnVariableChanged 并尝试获取另一个同步变量的内容,不能保证该变量已使用最新的同步数据进行了更新。

VRC Object Sync​

此组件将自动同步其所在对象的 Transform(位置、旋转、缩放)和 Rigidbody(物理)。它有几种特殊的方法和属性供你访问:

FlagDiscontinuity​

当你想要传送对象时触发此方法——你在此帧所做的更改将立即应用,无需平滑过渡。

Set/Get Gravity​

启用重力时,此刚体受重力影响并会落向地面。通常,重力是刚体的一个属性。但是,当你使用 VRCObjectSync 时,此属性必须由 VRCObjectSync 组件控制。你可以使用这些函数来实现这一点。这实际上表现为一个同步变量,因此只有拥有者可以设置重力。

Set/Get Kinematic​

启用运动学模式时,此刚体忽略力、碰撞和关节。通常,运动学是刚体的一个属性。但是,当你使用 VRCObjectSync 时,此属性必须由 VRCObjectSync 组件控制。你可以使用这些函数来实现这一点。这实际上表现为一个同步变量,因此只有拥有者可以设置运动学。

Respawn​

将此对象传送回其起始位置和旋转,并移除其速度。 具体来说,它将 DiscontinuityHint 设置为 true,以使以下更改立即生效而非平滑过渡。然后:

  • 将 transform.position 设置为初始位置
  • 将 transform.rotation 设置为初始旋转

如果对象有刚体:

  • 将 rigidbody.velocity 设置为 Vector3.zero
  • 将 rigidbody.angularVelocity 设置为 Vector3.zero
  • 将 rigidbody.position 设置为初始位置
  • 将 rigidbody.rotation 设置为初始旋转

VRC Object Pool​

VRC Object Pool 提供了一种管理游戏对象数组的轻量级方法。对象池将管理并同步其持有的每个对象的激活状态。

要使对象激活,对象池的拥有者触发 TryToSpawn 节点,该节点将返回已激活的对象,如果没有可用对象则返回空对象。对象池拥有者可以通过 Return 节点将对象返回到池中,并自动禁用该对象。

延迟加入的玩家将自动看到对象处于适当的激活或非激活状态。