组相关性:退出一个连接的视野不等于ActorTearOff

自动关联目录:组相关性:退出一个连接的视野不等于ActorTearOff

核心判断:组相关性是“连接订阅哪些 Actor”的关系;TearOff 是“服务器永久停止该 Actor 的权威复制”的全局生命周期决定。用后者实现前者,会把局部退订扩大成全局状态变化。

一、业务冲突:同一 Actor 只对一部分连接常驻

队伍标记、私人区域实体和观察者专属信息不适合全连接 Always Relevant。连接可能同时加入多个组,也可能晚于 Actor 创建才加入;退出一个组只能影响该连接,不能让其他连接丢失同一 Actor。

二、实际实现:每连接挂组节点,方向正确

工程为连接动态创建组节点,Actor 注册时遍历现有连接,把它加入匹配节点;Gather 时直接返回节点列表。这避免每帧对所有 Actor 执行组判断,组内对象也可以对成员连接保持常驻。

但三个实际控制流破坏了这个模型:节点查找遇到第一个不匹配组就提前返回,导致多组连接只能可靠命中首个节点;连接晚加入组时只创建空节点,没有补入此前已注册 Actor;退组时遍历节点 Actor 并调用 TearOff,把单连接退订变成 Actor 全局停止复制。Actor 自身换组也缺少完整的旧组移除、新组加入事务。

三、目标设计:共享组注册表 + 每连接订阅

void JoinGroup(Connection& c, GroupId g) {
    Snapshot s = Groups[g].Freeze();        // members + revision
    c.Subscriptions.Add(g, s.revision);
    c.GraphNode(g).ReplaceWith(s.members);
    ApplyDeltasAfter(c, g, s.revision);
}

void LeaveGroup(Connection& c, GroupId g) {
    ActorSet leaving = c.GraphNode(g).Members();
    c.Subscriptions.Remove(g);
    c.RemoveGraphNode(g);
    for (ActorId a : leaving)
        CloseChannelFor(c, a, RelevancyLost); // 只影响该连接
}

全局注册表维护 Group -> ActorSet + Revision,Actor 换组是一次原子 Move;连接节点只表达订阅。Join 使用快照 Revision 加后续 Delta,避免快照期间增删丢失。一般情况下移出 RepGraph 候选后让 UE 相关性超时关闭 Channel;若业务要求立即消失,也必须使用连接级 Channel/销毁通知,不能调用全局 TearOff。

四、TearOff 应何时使用

TearOff 适合服务器发送最后状态后不再控制该 Actor,例如进入客户端自行模拟的最终阶段。它不是隐藏、退队、离开兴趣范围或节省某一连接带宽的 API。普通销毁又是另一种语义:服务器结束 Actor 生命周期,并由网络销毁传播。

五、必须通过的矩阵

场景A连接B连接Actor全局状态
A加入组,B未加入可见不可见继续复制
A同时加入两个组两组均可见不受影响继续复制
Actor先存在,A后加入快照后可见不受影响继续复制
A退出,B仍在组内关闭A的Channel仍可见继续复制
Actor换组原组连接退出新组连接进入NetGUID与状态连续

线上指标应包括组 Actor 数、订阅连接数、Join 快照耗时、快照后 Delta 堆积、连接级 Channel 关闭数、误用 TearOff 次数和多组查找失败数。