12 网络同步与复制(Replication)
目标:建立"GAS 里什么数据走哪条网络通道"的完整地图——复制模式、同步矩阵(已修正)、Ability 复制、带宽优化。
12.1 GAS 的网络模型
GAS 采用服务端权威(Server Authority)模型:所有伤害、属性修改、能力激活的最终判定都在服务端。客户端(拥有者)通过预测获得手感,通过复制获得状态。
要正确使用 GAS 多人功能,必须清晰回答四个问题:
- 谁的 ASC 复制什么数据?(复制模式)
- 能力是怎么同步的?(RPC + 复制)
- 属性/效果/标签/表现各自走哪条通道?
- 怎么控制带宽?
12.2 复制模式(ReplicationMode)总览
enum class EGameplayEffectReplicationMode
{
Minimal, // AI/大量单位
Mixed, // 玩家角色(Fortnite 默认)
Full, // 单机/极小规模
};
同步矩阵(已按权威文档修正)
| 数据类型 | Full | Mixed | Minimal |
|---|---|---|---|
| GameplayEffect | 所有客户端 | 仅拥有者客户端 | 不复制给任何人 |
| GameplayTag(GE 授予) | 所有客户端 | 随 GE(拥有者客户端)* | 不复制 |
| GameplayTag(Loose) | 不复制(本地) | 不复制(本地) | 不复制(本地) |
| GameplayCue | 所有客户端(不可靠多播) | 所有客户端(不可靠多播) | 所有客户端(不可靠多播) |
| AttributeSet 属性 | 所有客户端 | 仅拥有者客户端 | 不复制 |
* 关于 Mixed 下"Tag 复制给所有客户端"的准确口径:GE 复制范围决定 Tag 复制范围——Mixed 下 GE 只到拥有者客户端,因此非拥有者客户端看不到别人身上的 GE 授予 Tag。旧资料里"Mixed 下 Tag 同步给所有客户端"的表格表述过于笼统,实际取决于 Tag 由哪种机制授予。
三条铁律(再次强调):
- GameplayCue 在所有模式下都不可靠多播到所有客户端——唯一的"全员可见"表现通道;
- Mixed 模式要求 OwnerActor 的 Owner 是 Controller(PlayerState 天然满足;Character 需手动设置);
- Fortnite 实战:玩家角色 Mixed、AI 单位 Minimal,这是社区推荐的默认配置。
12.3 能力(GameplayAbility)怎么同步
关键事实:
- Ability 的逻辑不会在模拟代理上运行。Simulated Proxy 只通过表现通道(动画、Cue)"假装"看到技能,真正的 Ability 实例只在服务端和拥有者客户端存在;
- Ability 的复制:
ReplicationPolicy = Replicate且设置了实例化策略的 GA 类,其 Spec 会复制给客户端。这样客户端能拿到"这个角色有哪些技能"(用于 UI、输入绑定),但技能执行仍走服务端; - 激活/结束的同步:通过 RPC 完成——
ServerTryActivateAbility(客户端→服务端)、ClientActivateAbilitySucceed/Failed(服务端→客户端)、ServerEndAbility/ClientEndAbility; - 同帧快速技能可批处理:一个"激活 + 发送 TargetData + 立即结束"的技能,GAS 会把这几个 RPC 合并成一个(Ability Batching),减少网络包数。
12.4 效果(GameplayEffect)的复制机制
- Duration/Infinite GE 生成
FActiveGameplayEffect存入FActiveGameplayEffectsContainer(FFastArraySerializer),逐条复制; - Instant GE 不进入该容器:它只在服务端执行(改 BaseValue),然后通过属性复制把结果值同步给客户端——所以客户端看到的是"属性值变化",而不是"Instant GE 本身";
- GE 的复制模式就是 ASC 的 ReplicationMode;
- 预测性施加的 GE:带预测键,客户端本地先有,服务端确认后覆盖。
12.5 属性(AttributeSet)的复制
- 属性通过
DOREPLIFETIME_CONDITION_NOTIFY注册复制(第 04 章); - 复制范围取决于 ReplicationMode:Mixed 下仅拥有者客户端能看到自己的属性值;其他玩家看到对方的 HP 通常是通过 GameplayCue / UI 事件(比如命中后飘字),而不是直接读对方属性;
- 属性复制走的是整块属性更新(值变化即同步),实时性足够,但要避免高频无意义变化(如每帧变化的临时值)。
12.6 标签(GameplayTag)的复制
| 授予方式 | 复制行为 |
|---|---|
| GE 的 Granted Tags | 随 GE 复制(见同步矩阵) |
| Ability 的 Activation Owned Tags | 不复制(本地) |
| Loose GameplayTags | 不复制;UE5 ReplicatedLooseGameplayTags 仅复制给拥有者客户端(COND_ReplayOrOwner) |
| Fast Replication(项目设置) | 用位掩码压缩高频复制标签,需要两端标签列表一致 |
设计结论:需要"所有客户端都看到的状态"(如死亡、眩晕),优先用 GameplayCue 让各端自行表现;需要"只有自己和服务端知道"的状态用 GE Granted Tags 或 Loose Tag。别指望 Loose Tag 广播给所有人。
12.7 同步架构选择
ASC 放哪(回顾)
| 放置 | 优点 | 缺点 | 适用 |
|---|---|---|---|
| Character | 简单 | 死亡丢失数据 | 单机原型 |
| PlayerState | 数据持久 | 依赖 PlayerState 复制 | 玩家角色(推荐) |
| 自定义 Component | 灵活(Lyra) | 复杂 | 大型项目 |
网络拓扑
| 拓扑 | 说明 |
|---|---|
| Listen Server | 主机兼服务端,主机本机延迟 0;Cue 可能双触发 |
| Dedicated Server | 独立服务端,无本地玩家,最干净 |
| 单机 | 无网络开销,但仍可开启复制做架构一致 |
12.8 带宽优化清单
- AI 用 Minimal 复制模式——AI 的 GE/属性根本不复制,省大量带宽;
- 慎用 Full 模式——Full 会把每个 GE 复制给所有客户端,只在极小规模使用;
- GameplayCue 走不可靠通道——可丢失,别承载关键逻辑;
- 启用 Fast Replication(项目设置 → GameplayTags)压缩高频标签;
- 属性按需复制——Meta 属性、纯服务端属性不注册复制;
- 合并同帧 RPC(Ability Batching)减少包数;
- 慎用
Full的Full——即"所有 GE 复制给所有人",加上不可靠 Cue 高频触发,容易打满带宽。
大规模优化:属性代理复制(Fortnite 大逃杀方案)
100 人大厅中,每个玩家的 ASC 在 PlayerState(always-relevant)上,直接复制大量属性带宽爆炸。Fortnite 的方案:
// 概念代码:模拟代理跳过 ASC 直接复制
void AFortnitePlayerState::ReplicateSubobjects(...)
{
if (bIsSimulatedProxy) return; // 不复制 ASC
Super::ReplicateSubobjects(...);
}
// Pawn 上的代理结构体(位掩码压缩白名单标签)
USTRUCT()
struct FAttributeProxy
{
GENERATED_BODY()
UPROPERTY(Replicated) float Health;
UPROPERTY(Replicated) float Shield;
UPROPERTY(Replicated) float MaxHealth;
UPROPERTY(Replicated) uint32 TagBitmask;
};
- 模拟代理上禁用 ASC 直接复制;
- 用代理结构体在 Pawn 上复制属性子集;
- 客户端收到代理数据后推送到本地 ASC。
Dave Ratti 评价:"不确定在 Replication Graph 等优化后是否仍必要,且不是最可维护的模式。"大型项目优先考虑 Replication Graph,而非手工代理复制。
大规模优化:ASC 懒加载(Fortnite 方案)
大量可破坏 Actor(树木、建筑)每个都挂 ASC 成本高。FNBR 优化为只在首次受伤时创建 ASC:
void AMyDamageableActor::TakeDamage(float Damage, ...)
{
if (!AbilitySystemComponent) // 首次受伤才创建
{
AbilitySystemComponent = NewObject<UAbilitySystemComponent>(this);
AbilitySystemComponent->RegisterComponent();
// 初始化属性集等
}
// 应用伤害 GE
}
12.9 调试工具
showdebug abilitysystem # 屏幕调试视图(标签/能力/效果)
AbilitySystem.Debug.NextCategory # 切换调试类别
AbilitySystem.Debug.NextTarget # 切换调试目标
AbilitySystem.Debug.ClearAll # 清除调试
Log AbilitySystem Verbose # 详细日志
stat game # 网络统计
net showcorrections # 属性校正
旧资料中的
AbilitySystem.Debug.Category.Prediction、net.PredictionKey.MaxDelay等命令并不存在,请使用上面的真实命令。
12.10 本章验证
- [ ] 配置 PlayerState 承载 ASC + Mixed 模式,双人联机验证"自己能看到自己属性,看不到对方属性细节";
- [ ] 用 Minimal 模式跑 AI 单位,对比带宽(stat game / 网络分析器);
- [ ] 联机验证 Cue 在所有模式下都多播到所有客户端;
- [ ] 用
showdebug abilitysystem检查自己与对方 ASC 的标签/能力状态。
下一章:13 实战:从零构建一个技能角色