物理快照:分片可以乱序,约束岛不能分帧提交

自动关联目录:物理快照:分片可以乱序,约束岛不能分帧提交

核心判断:网络包是传输单位,约束岛的一帧状态才是应用单位。大快照可以被拆成多包并乱序到达,但只有 Sender、epoch、拓扑、配置、成员身份、覆盖区间和完整性全部验证后,才能用同一时间基准一次提交;缺一个成员时宁可保留旧帧,也不能局部更新。

一、业务冲突:大结构必须分包,物理关系又不允许半帧

独立刚体可以逐个插值,约束结构却共享关节误差和同一求解时刻。一个大型组合的 Transform 样本可能超过单包上限,需要拆分、批量发送;不可靠通道又会乱序、重复和丢失。若接收端每到一片就应用,其中一半成员是新时刻、另一半仍是旧时刻,Joint 会看到不存在于权威端的瞬时拉伸,视觉和碰撞都可能爆开。

跨 VM 还存在身份差异。服务器整数 ObjectId 不能直接在客户端使用,必须先可靠宣布稳定 UniqueId,再映射为本地 ObjectId;身份消息晚到时,物理样本只能暂存或拒绝,不能把服务器 ID 当本地对象。所有权切换后,旧 Owner 的晚包、旧拓扑的完整帧和新拓扑的分片可能同时在路上,单靠 FrameSeq 无法区分。

所以协议需要同时解决边界、防御、组装和播放四层问题。只做序列化压缩,无法保证物理一致性。

二、实际实现:复合版本键组装完整帧,再进入统一播放时钟

岛快照以 (IslandId, IslandEpoch, TopologyGeneration, ConfigRevision, IslandFrameSeq) 为键,并带 AuthorityTime、总成员数、分片序号、分片总数和首成员下标。Codec 使用固定版本、显式小端整数、长度前缀、包体上限与成员上限;过长帧按稳定成员顺序切片,小记录可在不超限时合并到同一包。

Assembler 按 Sender 与复合键保存不完整帧,成员覆盖用 BitSet 记录。相同分片重复可幂等接受,内容不同的重复、Header 冲突、成员区间重叠、成员身份重复、覆盖缺口和超员都会拒绝整帧;不完整帧有短 TTL,每个岛同时保留的候选帧数量有硬上限,序列比较处理 uint32 回绕。新完整帧提交后,旧序列的未完成分片被清掉。

组装完成并不等于可以应用。接收路径再次验证当前 Authority Lease、Sender、epoch、Topology、Config 和预期成员集合,并先把所有稳定身份解析到本地 Body。只有全员成功才生成 IslandSnapshotFrame。观察者对岛使用一个 AuthorityTime 和一个应用模式;插值时所有成员选择同一对帧,外推受时间上限约束,数据不足则整岛冻结。测试统计每成员 Apply 次数,要求一帧内恰好一次,版本在验证与提交之间变化时整帧放弃。

从外推或冻结恢复到插值时,当前独立 Body 路径不会立刻把累计误差硬加到新样本,而是记录上一帧已显示结果与新插值结果的位姿差,在有限时间内衰减表现 Offset;Initial、Releasing 和明显不连续仍走立即应用。岛级路径必须把同样策略提升为整岛共享模式:误差可以逐成员计算,但衰减时间、开始帧和结束条件一致,不能某些成员 Snap、另一些成员 Smooth。

独立 Body 的播放也保留了重要经验:客户端使用共享 Playout Clock,而不是每个物体根据到包时间自由推进;服务器接收 Owner 上行后按自己的固定节奏重广播最新样本,吸收上行抖动,避免把网络到达间隔直接变成观察者的运动快慢。

flowchart LR
    S[同一时刻采样整岛] --> F[稳定排序并分片]
    F --> N[不可靠传输/乱序重复]
    N --> A[按复合版本键组装]
    A --> V{完整且当前?}
    V -->|否| K[保留旧帧/拒绝/超时淘汰]
    V -->|是| B[全成员身份解析]
    B --> P[同一时间基准插值或冻结]
    P --> C[原子提交全岛]

三、值得保留:协议先保证“不能错误应用”,再追求压缩率

复合版本键非常必要。IslandEpoch 排除旧 Owner,TopologyGeneration 排除旧成员关系,ConfigRevision 排除同一拓扑下已经变更的 Constraint 参数,FrameSeq 才负责同一流内排序。把这些维度压成一个全局序号会失去结构化拒绝原因,也难以安全处理并行变更。

Assembler 的有界状态是安全与性能共同要求。包长、成员数、在途帧数和组装 TTL 都有上限,失败时清空输出,不把已解析前半段泄漏给调用方。冲突重复与完全相同重复被区分,既支持网络重发,也不允许同一 FragmentIndex 覆盖不同内容。成员覆盖与身份去重,则从“片都到了”进一步证明“每个期望成员恰好一份”。

固定重广播节奏和统一播放时钟也值得保留。观察者不应直接看到 Owner 上行抖动;一个岛更不能让每个成员各自根据本地到包时间插值。Initial/Releasing 等边界样本绕过普通节流,Stale 后清理远端接管状态,也使开始和结束不依赖“下一份普通包恰好到达”。

四、结构性缺陷:线格式与播放策略仍需更强的跨平台契约

Header 字段已经显式小端编码,但成员 Transform 若仍依赖 Packed POD 布局或整块复制,就需要非常严格的大小、对齐、浮点表示和端序保证。它在同构平台上高效,却不是天然的跨架构协议。长期方案应逐字段编码或生成 Schema Codec,并用跨平台 Golden Bytes 验证,而不是只靠本机 sizeof。

完整快照对大型静止结构成本仍高。每帧发送所有成员可以保证原子性,却会把带宽与岛大小线性绑定;简单改成成员 Delta 又会重新引入缺片与半帧问题。需要的是“完整逻辑帧 + 可引用 Baseline”的 Delta:帧只有在 Baseline 存在且所有变化成员完整时才提交,周期性 Keyframe 负责恢复。

诊断已经能记录协议阶段、字节、队列、结果和拒绝原因,但物理质量指标还应与网络事件关联:插值 Buffer Fill、外推时长、整岛冻结时长、成员最大相对误差、快照年龄、纠正距离和 Handoff 首帧延迟。否则只能证明包被正确处理,不能证明玩家看到的结构稳定。

五、目标设计:以 Validated Frame Store 隔离网络与物理应用

接收线程只负责 Decode 与有界组装,产出仍是不可信的 Wire Frame。Game Thread 的 Validator 用当前 Authority Lease 和 Topology Manifest 将其转换为不可变 ValidatedIslandFrame,其中成员已按稳定序号映射到 Generation-safe Body Handle。Playout 只接受 Validated Frame;Topology 或 Lease 改变时,Store 按版本整体失效。

ReceiveResult OnIslandFragments(Packet p)
{
    WireFrame wire;
    if (!assembler.PushAndComplete(p, wire)) return BufferedOrRejected;

    Lease lease = authority.Current(wire.islandId);
    Manifest manifest = topology.Current(wire.islandId);
    if (!Match(wire, lease, manifest)) return Reject(StaleVersion);

    ValidatedFrame frame;
    for (ExpectedMember m : manifest.orderedMembers) {
        BodyHandle body = identities.Resolve(m.stableId, m.generation);
        if (!body || !wire.ContainsExactlyOnce(m)) return Reject(Incomplete);
        frame.Add(body, wire.SampleFor(m));
    }
    store.Commit(frame); // 到这里仍不直接逐成员写 Body
    return playout.ApplyWholeIslandAtOneTime(frame);
}

Delta 帧必须声明 BaselineFrameSeq 和结果成员集合摘要;缺 Baseline 或摘要不符就等待 Keyframe,不做部分恢复。量化误差应进入 Constraint 类型的误差预算:刚性连接、长链铰接与松散装饰使用不同位置/旋转精度,但一帧内所有成员仍共享同一 AuthorityTime。

六、决策规则:带宽可以降级,原子性不能降级

情况接收或播放决策观测指标
分片乱序/相同重复有界缓存并幂等合并在途帧、重复率、组装时间
冲突重复/区间重叠/身份重复拒绝整帧并记录原因各拒绝原因计数、Sender
少一个成员或身份未映射不应用任何成员,等待或超时Coverage、映射等待、冻结时长
epoch/topology/config 过期立即拒绝并清理相关旧缓存Stale 维度与当前版本
短时丢包整岛有界外推,随后冻结外推时间、漂移、恢复误差
大型静止岛降频或 Baseline Delta,周期 Keyframe字节/秒、Keyframe 恢复时间
Handoff 首帧首个完整目标快照才切 Snapshot SourceCommit 到首帧延迟、旧源保持时间
跨平台协议逐字段固定端序与 Golden Bytes每平台 round-trip、版本拒绝

网络同步最容易被误解为“Transform 压缩和插值”。实际代码说明,真正难点是让身份、拓扑、权威、时间和完整性同时成立。只要约束还存在,任何局部应用都是把网络的不确定性直接注入 Solver;正确策略是传输层允许不完整,验证层绝不输出半帧,播放层宁可整岛冻结也不制造不存在的物理状态。