跳转到内容

附录 · 术语表

约 18 分钟

正文里出现新术语时会用一句口语化括注带过;这里给客观定义和首次出现的章节,方便回查。

每条结构:英文术语(中文译名)+ 客观定义 + 首次出现章节。首次出现的章节链接随章节落地后再补全,目前先用文字标注。

骨架先建出来,定义会随对应章节落笔时扩充。当前没写满的条目会标「待落」。


同步变量 / 同步字段。用 [UdonSynced] 标记的字段,会被 VRChat 网络层从 Owner 同步到所有其他客户端。是 Vol.2 表达「当前状态」的主通道。

首次出现:第 1 章。

网络事件。用 SendCustomNetworkEvent 触发的一次性远程方法调用。适合「发生过一下」的动作,迟入玩家不会重放。

首次出现:第 1 章。

连续同步。同步模式之一,每帧自动尝试发送变更,单次预算约 200 bytes。具体数值以官方文档为准。

首次出现:第 4 章。

手动同步。Owner 主动调用 RequestSerialization 才发送,单次预算约 280 KB,但有 per-object rate limit。

首次出现:第 4 章。

序列化。把 UdonSharp 字段打包成网络数据包的过程。

首次出现:第 4 章。

反序列化。客户端收到网络数据包后,还原成 UdonSharp 字段值的过程。

首次出现:第 4 章。

请求序列化。手动同步模式下,Owner 调用此 API 通知 VRChat 网络层「我要发送一次」。它是请求,不是立即发送。

首次出现:第 4 章。

回调。序列化即将发生时在 Owner 本地执行。适合做发送前的准备,比如更新版本号。

首次出现:第 4 章。

回调。序列化完成后在 Owner 本地执行,参数包含发送结果(成功 / 失败 / 字节数)。是关键系统记录失败、降级的入口。

首次出现:第 4 章。

回调。远程客户端收到并反序列化完成后执行。注意它只在变更被检测到时触发,没变化不会调用。

首次出现:第 4 章。


对象所有者。VRChat 里每个网络对象都有一个 Owner,只有 Owner 能可靠修改它的同步变量。Vol.2 的核心架构问题之一是「每个状态由谁拥有」。

首次出现:第 1 章。

实例主控。第一个进入实例的玩家是 Master,他离开时会自动转给下一个人。Master 不等于 Owner,新系统不应把 IsMaster 当默认权威判断。

首次出现:第 1 章。

本地玩家。当前客户端代表的玩家,通过 Networking.LocalPlayer 取得。

首次出现:第 3 章。

权威。一个抽象概念:哪个客户端的状态是其他客户端要服从的真相。VRChat 的权威分布在多个 Owner 上,不是单一服务器。

首次出现:第 3 章。

转移所有权Networking.SetOwner(player, obj) 是请求,不是瞬间完成。关键状态不能写成「调用后立刻假定已经是 Owner」。

首次出现:第 3 章。

回调。Owner 转移请求发出时,请求方和当前 Owner 双方本地都会触发。返回 false 可以拒绝转移。

首次出现:第 14 章。

回调。所有权确实变更后触发,是确认权属变化的可靠时机。

首次出现:第 14 章。


玩家对象。给每位玩家生成一份对象副本,并锁定该玩家为 Owner。是当前 SDK 下最重要的「每个玩家一份对象」架构单元。

首次出现:第 9 章。

持久化数据。跨会话保存的每玩家键值数据。Vol.2 只讲边界,细节在 Vol.5。

首次出现:第 1 章(仅边界)。

持久化。带 VRCEnablePersistence 的对象可以让指定的玩家数据跨会话保存。本卷只讲边界。

首次出现:第 1 章(仅边界)。

组件,专门同步 Transform 和 Rigidbody 状态,不负责 Udon 状态。

首次出现:第 1 章。

玩家对象池CyanPlayerObjectPool 等社区方案,曾是 per-player 对象的主流做法。当前归档为只读,新项目优先考察 VRCPlayerObject

首次出现:第 10 章。


状态。游戏在某段时间里「始终是某个值」的信息。和「事件」对照。

首次出现:第 1 章。

事件。「发生过一下」的瞬时动作。和「状态」对照:状态会被复制,事件不会重放。

首次出现:第 1 章。

命令。一个被发起、被裁决、被应用的请求。Vol.2 第三部展开「请求式架构」。

首次出现:第 12 章。

快照。某一时刻全部相关状态的完整记录。

首次出现:第 18 章。待落。

节拍。固定步长的逻辑帧,多人游戏里通常作为同步与回放的时间单位。

首次出现:第 18 章。待落。

幂等。同一个操作执行多次和执行一次结果相同。在网络拥塞重发场景里非常重要。Vol.2 用 requestId + lastProcessedRequestId 实现请求幂等。

首次出现:第 12 章。

版本号。给状态打上单调递增的编号,用来辨别「是否是同一份」或「是否过期」。GameState 上的 [UdonSynced] int stateVersionOnPreSerialization 里 +1,远端客户端的 OnDeserialization 里和 lastAppliedStateVersion 对比,跳过中间态。版本号跨 Owner 转移仍单调,不像服务器时间会跳。

首次出现:第 20 章;闭环 3 落地。

请求标识。每位玩家在自己的 PlayerObject 上递增的本地序号,用于裁决、去重、回执。配合 lastProcessedRequestId 数组或映射表(按受控玩家槽位索引)实现幂等处理。

首次出现:第 12 章。

最后处理请求号。GameState 端记忆每位玩家最近一次被处理的 requestId,避免迟入恢复或 Owner 转移时重复处理同一请求。

首次出现:第 12 章。

全局状态对象。一局游戏里承担「房间阶段、当前波次、总分、胜负」等共享状态的核心对象。Vol.2 强调:GameState Owner 是当前实例内的状态提交者,不是可信服务器。

首次出现:第 11 章。

Owner 策略。GameState 这类对象由谁当 Owner 的设计选择。Vol.2 给三种:固定 Owner(场景对象自带 Master Owner)、Owner 候选队列(按加入顺序排队)、Owner 重选(按规则推举)。

首次出现:第 11 章。

批准回执。GameState 不能直接写 PlayerObject 字段(Owner 是该玩家本人),而是通过 SendCustomNetworkEvent(target=Owner) 让玩家本人写自己的字段。这种「裁决在 GameState、落地在 PlayerObject」的模式是 Vol.2 处理跨 Owner 写权的标准做法。

首次出现:第 13 章。

Owner 候选队列。GameState 维护的 [UdonSynced] int[] ownerCandidateOrder,按玩家加入顺序排序。当前 Owner 离开后,下一位候选玩家自动 SetOwner 接管,对应 Vol.2 第 14 章策略 B。

首次出现:第 14 章。

串味状态。玩家离开后,GameState 中和这位玩家相关的暂态字段未被清理,导致后来的玩家看到旧记录残留。Vol.2 在 OnPlayerLeft 里做显式清理,闭环 2 故意保留一部分作为闭环 3 的动机。

首次出现:第 14 章。

开局投票。Lobby 段每位玩家可以切换 wantStart 状态。投票数与总人数比例达到 startVoteThreshold 且全员 Ready 后,进入开局倒计时。倒计时归零调用 BeginMatch 进入 INGAME。任何一位玩家撤 Ready 或撤投票都会立刻取消倒计时。

首次出现:第 15 章。

第 13 章批准回执模式在第 15 章被复用到角色切换上。HandleSetRoleHandleJoinTeam 同款:阶段检查 → 合法性 → 业务约束 → ReplyXxxApproved / ReplyXxxRejected 回执。

首次出现:第 13 章;第 15 章扩展。

比赛生命周期。一局游戏从 LOBBY 进入 INGAME、进入 RESULT、回到 LOBBY 的完整循环。Vol.2 把入口集中到 BeginMatch / EndMatch / RestartMatch 三个固定函数,新加字段时只更新这三处。

首次出现:第 16 章。

局号GameState 上的单调递增字段 matchId。每次正式开局递增一次,用来区分上一局延迟到达的事件和当前局状态。

首次出现:闭环 4。

目标清理 bitmask。闭环 4 的最小项目字段,用 int targetClearedMask 的 bit 位记录训练目标是否已清掉。它服务最小闭环,后续真实敌人状态会转移到 EnemyObject 和对象池。

首次出现:闭环 4。

规则版本。第 45 章建议加在 GameState 上的兼容字段,用来标记当前同步字段语义和结算规则的版本。它不同于世界上传版本号,只服务运行时迁移判断。

首次出现:第 45 章。

项目改造对照表。第 46 章用来把合作防守项目迁移到卡牌、解谜、派对、Boss 战、PvP 一对多等玩法。核心做法是保留 PlayerObject + GameState 骨架,替换玩法对象和胜负条件。

首次出现:第 46 章。

广播SendCustomNetworkEvent(NetworkEventTarget.All, ...) 给所有客户端发同一条事件。每位玩家在自己客户端跑回调,通过 Networking.IsOwner 等本地条件过滤是否处理。Vol.2 用它做 BeginMatch 时清场(让每位玩家自己清自己 PlayerObject 字段)。

首次出现:第 16 章。

一致性检查。在 OnOwnershipTransferredUpdate 周期里跑一次的状态自检:例如 phase=INGAMEGetPlayerCount()=0 时把状态拽回 LOBBY。Vol.2 用它兜底 Owner 转移延迟和异常路径。

首次出现:第 14 章;第 16 章扩展为 TickSanity 周期检查。

个人分PlayerLobbyState 上的 [UdonSynced] int personalScore,玩家本人通过批准回执写。它用于个人 UI 和迟入显示,不作为最终奖励的可信来源;结算里的 MVP 和奖励出口仍以 GameState 快照为准。玩家离开实例时 PlayerObject 销毁,分数自动消失。

首次出现:第 17 章。

队伍分GameState 上的 [UdonSynced] int[] teamScore,按 teamId 索引。GameState OwnerHandleScore 里直接写。PvP 对战玩法的胜负判定从这一层读。

首次出现:第 17 章。

结算快照EndMatch 时由 GameState Owner 计算的 resultWinningTeam / resultMvpPlayerId 等字段。结算屏读这些字段而不是每帧重算,让所有客户端(含迟入观众)看到同一份结算。

首次出现:第 17 章。

旁观者GameState 上的 [UdonSynced] int[] spectatorPlayerIds 数组登记的玩家。INGAME 中加入的迟入玩家自动入旁观席,UI 按钮置灰。BeginMatch / RestartMatch 时清空。

首次出现:第 18 章。

会话内重入。玩家短暂掉线后几秒内重连同一实例,新 playerId 可能与旧的不同。本卷视为「新加入玩家」处理,不恢复原 personalScore

首次出现:第 18 章。

跨会话重连。玩家离开 VRChat 后再次回到同一世界,希望保留之前的成就。本卷只规定接口(OnMatchEndedHook),实现交给 Vol.5 的持久化系统。

首次出现:第 18 章。


状态版本号Version NumberGameState 上的具体落地字段名。配合 OnDeserialization gating 模式让远端客户端只在版本变化时整批应用字段,避免 UI 看到中间态。

首次出现:第 20 章;闭环 3 落地。

[NetworkCallable] 标记。SendCustomNetworkEvent 参数化版本要求被调方法标这一 attribute。SDK 3.8.1 起支持。参数个数上限约 8、单次载荷上限约 16 KB、>1 KB 自动分片。仍然不重放给迟入玩家。

首次出现:第 21 章。

通道决策表。本卷锁在第 21 章的七通道横向对比:本地变量 / SendCustomNetworkEvent(无参 / 参数化)/ [UdonSynced] 基础类型 / [UdonSynced] 数组 / VRCJson / VRCPlayerObject / VRC Object Sync。按字节范围、迟入恢复、改动频率、适合场景四轴对比。第四部所有章节回链这张表。

首次出现:第 21 章。

命令日志GameState 上的环形数组(cmdRequestId[] / cmdPlayerId[] / cmdType[] / cmdPayload[] / cmdServerLikeTime[])记录最近 N 条命令。容量固定(32 / 64 / 128),写入 O(1),旧记录被覆盖。用于战报、复盘、反作弊近似异常分数检测。

首次出现:第 22 章。

「贴近服务器时间」。命名带 Like 是为了不把它当成可信时间戳。Networking.GetServerTimeInSeconds() 在不同客户端之间偏差几十到几百毫秒;Owner 转移瞬间可能跳;但够用作「相对顺序」和「大致时段」。命令日志的 cmdServerLikeTime[] 是这一时间。

首次出现:第 22 章。

位掩码 / 位打包。把多个 bool 字段压进一个 uint 的 32 个 bit 位,把枚举从 int(4 byte)压进 byte(1 byte)或更少 bit。压缩比 6:4 / 4:1 不等。代价是可读性下降、调试时要解码。

首次出现:第 23 章。

范围量化Vector3 position 12 byte,按 1 cm 精度量化到 100×100×50 米地图,每轴 14 bit 共 6 byte。压缩比 12:6。代价是精度被截到 1 cm。FPS 命中判定够用,桌游手指级别精度不够用。

首次出现:第 23 章。

变更掩码[UdonSynced] uint dirtyMask 字段记录本次序列化哪些字段变了。OnPreSerialization 里 Owner 设置 bit;远端 OnDeserialization 检查 bit 决定刷哪部分 UI;Owner 在 OnPostSerialization 中清零。用于增量同步与 UI 局部更新。

首次出现:第 23 章。

数据令牌VRC.SDK3.Data.DataTokenDataDictionary / DataList 元素的统一容器。可以装 int / float / string / bool / double / DataDictionary / DataList 等。读取时按 TokenType 选择 .Int / .Double / .String / .DataDictionary / .DataList 等。

首次出现:第 24 章。

数据字典VRC.SDK3.Data.DataDictionary 是 string-keyed 的字典容器。配合 VRCJson 序列化为 JSON 字符串。注意 int key 字典不能序列化。

首次出现:第 24 章。

数据列表VRC.SDK3.Data.DataList 是有序集合容器。元素是 DataToken。配合 VRCJson 序列化为 JSON 数组。

首次出现:第 24 章。

SDK 内置 JSON 工具VRCJson.TrySerializeToJson(dict, JsonExportType.Minify, out var t) / TryDeserializeFromJson(json, out var t)。失败模式:NaN / Infinity 不能序列化、UdonBehaviour / VRCPlayerApi 引用不能序列化、非 string key 不能序列化。

首次出现:第 24 章。

最后应用版本号。客户端本地缓存(不同步),记 OnDeserialization 上一次应用整批字段时的 stateVersion。比较新旧版本号决定是否触发 ApplyState。这是第 20 章 gating 模式的核心字段。

首次出现:第 20 章;闭环 3 落地。

玩家离开清理回调。闭环 3 在 GameState 上加的方法 OnPlayerLeftCleanup(player),在 OnPlayerLeft 内被调用,用于清理 per-player 业务字段(如 bonusTakenByPlayerId / claimedReward[])。系统字段(lastProcessedRequestId[])由原 OnPlayerLeft 清理;业务字段集中到这一回调,避免「加新字段时漏清」。

首次出现:闭环 3。


回合制循环。事件驱动 tick 的玩法范式:行动窗口 → 玩家提交(或超时) → Owner 裁决 → 推进下一回合。第 25 章给出四个核心同步字段(currentTurnPlayerId / turnNumber / turnStartServerTime / turnDeadlineSeconds)。

首次出现:第 25 章。

轻实时循环。时间驱动 tick 的玩法范式:Update 在 GameState Owner 上按 tickInterval 持续推进,波次结束自动进入下一波。第 26 章给出三档 tick 频率(1Hz / 5Hz / 10Hz)和「事件做反馈、状态做共识」混用模式。

首次出现:第 26 章。

行动窗口。回合制下当前玩家允许行动的时段,从 turnStartServerTimeturnStartServerTime + turnDeadlineSeconds。窗口结束时由 Owner 自动推进到下一位。

首次出现:第 25 章。

回合截止。当前回合的最长持续时间,作为同步字段 turnDeadlineSeconds,由 GameState Owner 写入,可按回合调整(如开局 60 秒、正常 30 秒、收尾 90 秒)。

首次出现:第 25 章。

Tick 间隔。轻实时玩法 Update 推进游戏状态的时间间隔。1 Hz / 5 Hz / 10 Hz 是常见档位。Tick 推进频率不等于同步包频率,后者只在字段真的变化时由 RequestSerialization 触发。

首次出现:第 26 章。

波次序号。轻实时玩法当前进行到第几波的同步字段,单调递增。BeginMatch 时设 1,每次 AdvanceWave +1。迟入恢复靠它而不是时间戳。

首次出现:第 26 章。

助攻窗口。击杀仲裁回看的时段,最近 N 秒内对该敌人造成过伤害的玩家按伤害比例分配助攻分。第 27 章给出两条实现路径(命令日志扫描 / PlayerObject 伤害簿)。

首次出现:第 27 章。

时间奖励。合作 PvE 提前结束时,剩余时间换算成的额外分数。本卷推荐「房间层算总额、按 personalScore 占比分到个人层」,仲裁在 EndMatch 内执行一次,避免 OnDeserialization 重复触发。

首次出现:第 27 章。

不对称队伍。不同人数 / 不同目标的队伍组合(如 1 守 vs 3 攻)。teamScore[] 比大小不能直接给出胜负,需要专门的同步字段(如 attackerWonTimes)和自定义 ComputeWinningTeam 函数。

首次出现:第 27 章。

跨阶段重入。玩家在 INGAME 第 N 阶段离开实例后再次进入同实例时仍在 INGAME。第 28 章给出三种处理(默认旁观 / 立刻入队 / 恢复贡献)和各自的字段成本。VRChat 的 playerId 不保证跨重入一致,「恢复贡献」处理实操不稳。

首次出现:第 28 章。

请求归并名单GameState 上的 wantsToReturnPlayerIds[] 同步字段,记录已按过 REQ_PLAY_NEXT 的旁观者。RestartMatch 时按本字段决定哪些旁观者变回普通玩家。配合 restartMode = true(请求归并)使用。

首次出现:第 28 章。

RESTART 阶段间策略。RESULT → LOBBY 时旁观者归并的策略二选:全员归并(旁观者全部变回普通玩家,第 18 章默认)或请求归并(仅按过 REQ_PLAY_NEXT 的归并回,第 28 章扩展)。由 restartMode 开关控制,运行时不切换。

首次出现:第 28 章。


延迟。从动作发出到对端看见动作之间的时间差。VRChat 公网典型延迟 50-200 ms。

首次出现:第 6 章。

带宽。单位时间内能传输的字节数。VRChat 给客户端约 11 KB/s 的总发送预算(粗略级别)。具体数值以官方文档为准。

首次出现:第 6 章。

可靠性。数据包是否保证到达、是否保证按序到达、是否允许重发。

首次出现:第 17 章。待落。

预测。客户端不等服务器确认就先按本地输入更新画面,等确认到达后再修正。Vol.2 把它降级为体感优化,不当作正确性手段。

首次出现:第 29 章。

本地预演。玩家本地立即播放 UI、音效、粒子、动画等表现,让操作更顺。它不能提前修改分数、HP、阶段、胜负等共识状态。

首次出现:第 29 章;第 43 章项目落地。

待确认请求。本地已经发出、Owner 尚未确认的请求。第 43 章用 pendingHitRequestId 记录命中请求,确认后清空,拒绝时撤销本地预演。

首次出现:第 29 章;第 43 章项目落地。

调和。预测后收到服务器确认,把本地状态修正回服务器版本的过程。第六部只借用 pending 清理和确认回包,不做完整服务器调和。

首次出现:第 29 章。

回滚。允许把本地状态退回到过去某一时刻,再用新的输入重放出来。VRChat 没有原生回滚支持。

首次出现:第 32 章。

延迟补偿。服务器在判定时把客户端的视角「倒回」几十毫秒,让玩家命中自己看到的目标。VRChat 没有权威服务器,无法做严格的延迟补偿。

首次出现:第 31 章。

迟入玩家。游戏开始后才进入实例的玩家。「事件不会重放,状态会复制」是处理迟入的核心原则。

首次出现:第 1 章。

网络拥塞标志Networking.IsClogged 在客户端有大量数据排队等待发送时返回 true。频繁触发的同步代码可以用它做限流。

首次出现:第 6 章。

Networking.IsNetworkSettled 在实例所有同步数据反序列化并应用完成后返回 true。可以作为「迟入恢复完成」的信号。

首次出现:第 7 章。

对象池。VRChat 内建组件,同步管理一组 GameObject 的激活 / 未激活状态。迟入玩家自动看到正确状态,是档③的标准实现。

首次出现:第 5 章。

非玩家角色。由世界逻辑驱动的角色或实体。Vol.2 第七部按同步需求分成 local-only 装饰、Owner 驱动和分片 Owner 三类。

首次出现:第 34 章。

敌人对象。第八部主项目里的池化敌人单体,保存 HP、状态、所属波次、目标玩家等单体状态。GameState 只保存敌人聚合数量和波次。

首次出现:第 42 章。

内测日志。内测时按固定字段记录的一行结构化日志,至少包含版本、matchId、阶段、波次、Owner、事件名和请求号。第 44 章用它定位跨对象问题。

首次出现:第 44 章。

问题优先级。第 44 章把内测问题分为 P0 阻断、P1 严重、P2 普通、P3 观察。判断标准看是否破坏一局成立和共识状态。

首次出现:第 44 章。

行为树。把 AI 条件和动作组织成树状决策的常见模型。第 35 章只借用它的决策顺序思想,在 UdonSharp 里落成枚举状态机和优先级表。

首次出现:第 35 章。

Unity 组件,用于让角色基于 NavMesh 朝目标移动并避开其他 Agent 或障碍物。第七部只把它作为 NPC 移动线索,不把 Unity 普通 AI 系统完整搬进 VRChat。

首次出现:第 34 章。

性能预算。项目在目标设备和目标人数下允许消耗的渲染、脚本、网络和内存成本上限。第七部强调 Quest 与多人场景要先测量,再决定 NPC、物理和对象同步的复杂度。

首次出现:第 39 章。

架构决策记录。Architecture Decision Record 的简称,用一页固定格式记录状态归属、Owner、同步通道、迟入恢复和降级入口这类会影响返工的决定。第八部用它把合作防守世界从玩法反推到架构。

首次出现:理解章 G;第 40 章正式落地。


新术语在正文里能用一句话讲清楚的,直接补到这里;超过 3 句的内容拆到附录百科页(待写)。每条只在「首次出现」记录一次回链。