1.4 NetMode 与 Role:看清每个端口的真实身份
两个最常被混淆的词
新手学 UE 网络最容易卡在两个概念上:NetMode(这个端是什么模式)和 Role(这个 Actor 在这个端上是什么角色)。它们共同决定了同一段代码在不同机器上的行为分支。背下这张表,能省掉一半的联网 bug。
NetMode:四种模式
GetWorld()->GetNetMode() 返回当前世界的模式:
| NetMode | 含义 | 典型场景 |
|---|---|---|
| NM_Standalone | 单机,无网络 | 纯单机游戏、前端主菜单 |
| NM_ListenServer | 监听服务器:这台机器既是服务器又有一个本地客户端 | 编辑器多人测试、局域网联机主机 |
| NM_DedicatedServer | 专用服务器:只跑服务器,不渲染不渲染画面 | 正式上线专用服 |
| NM_Client | 纯客户端 | 普通玩家 |
注意 ListenServer 的特殊之处:它一个进程里同时跑着「服务器逻辑」和「一个本地客户端」。这意味着同一段代码在这台机器上可能既以服务器身份执行一次、又以客户端身份执行一次——调试时要分清楚当前在哪个上下文。
Role:三种角色
每个 Actor 实例在每个端上都有自己的 Role(GetLocalRole()):
| Role | 含义 | 出现在哪里 |
|---|---|---|
| ROLE_Authority | 权威端:这份 Actor 是真的,可以修改权威状态 | 服务器上的所有复制 Actor |
| ROLE_SimulatedProxy | 模拟代理:由复制数据驱动的「提线木偶」,客户端做插值平滑 | 远程客户端上看到的别人的角色;所有人看到的非玩家物体 |
| ROLE_AutonomousProxy | 自主代理:本地客户端上自己操纵的那个角色 | 本地客户端上自己的 Pawn |
配合 GetRemoteRole() 可以进一步区分。一个常被忽略的事实:同一个 Actor 在不同机器上 Role 不同。服务器上你的角色是 Authority,你自己的机器上是 AutonomousProxy,其他玩家的机器上是 SimulatedProxy。所以「Authority 判定」不是 Actor 的固有属性,而是「Actor 实例 × 所在端」的组合。
实战:一段代码的三端行为
void AMyCharacter::Fire()
{
if (GetLocalRole() == ROLE_Authority)
{
// 服务器:真实生成弹道、做命中判定、扣血
SpawnProjectile();
}
else
{
// 客户端:发 RPC 通知服务器「我要开火」,同时本地播武器动画
ServerFireRequest(); // 第三章详讲 RPC
PlayFireAnimLocal();
}
}
蓝图里用 Switch Has Authority 节点做同样的分支。另一个高频组合是 IsLocallyControlled():判断这个 Pawn 是不是当前客户端在操纵——本地客户端上自己的角色返回 true,其他角色(包括服务器上的那个)返回 false。很多「只有自己看到的镜头/输入逻辑」都靠它。
常用判定速查
| 想判断什么 | 用什么 |
|---|---|
| 我是不是服务器 | HasAuthority() / NetMode == NM_DedicatedServer 或 NM_ListenServer |
| 这个 Actor 是不是权威 | GetLocalRole() == ROLE_Authority(蓝图:Switch Has Authority) |
| 这个角色是不是我本地操纵 | IsLocallyControlled() |
| 是不是纯客户端 | NetMode == NM_Client |
一个典型误用
有人写「客户端开火」逻辑时用 if (!HasAuthority()) 然后在客户端直接生成弹道——在 ListenServer 的主机上,这段客户端代码也会执行(因为主机上同时有客户端),导致主机看到双倍弹道。正确做法是区分清楚「这段代码预期在哪种端运行」,必要时用 IsLocallyControlled 加 HasAuthority 双重条件。
心得:调试联网问题时,第一步永远是「在出问题的那台机器上打印 NetMode + LocalRole」。八成的「为什么没生效」在这一步就能看清——代码跑在了错误的端上。
