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」。八成的「为什么没生效」在这一步就能看清——代码跑在了错误的端上。