UE4区分服务器客户端,最稳的是先看UWorld::GetNetMode()返回的ENetMode,再用Actor的GetLocalRole()和PlayerController的IsLocalController()做补充;不要把HasAuthority直接等同于“服务器”,它在单机模式下也会是true。
UE4怎么判断当前是服务器还是客户端:先认ENetMode
刚接触UE4网络的朋友,常把“有没有网络复制”“是不是权威端”“是不是服务器”混在一起,实际在代码里,World级别的网络模式由ENetMode表达,据Epic Games官方文档(Epic Games)说明,ENetMode主要有以下几种取值:
NM_Standalone:单机模式,没有网络连接,Actor通常拥有权威。NM_DedicatedServer:专用服务器,没有本地玩家。NM_ListenServer:监听服务器,其中一个玩家同时承担服务器职责。NM_Client:纯客户端。
C++里可以这样取:
ENetMode NetMode = GetWorld()->GetNetMode(); bool bDedicatedServer = (NetMode == NM_DedicatedServer); bool bListenServer = (NetMode == NM_ListenServer); bool bClient = (NetMode == NM_Client); bool bStandalone = (NetMode == NM_Standalone);
如果只问“这段逻辑该不该在服务器执行”,可以封装成:
bool IsServerWorld(const UWorld World)
{
if (!World) return false;
const ENetMode Mode = World->GetNetMode();
return Mode == NM_DedicatedServer || Mode == NM_ListenServer;
}
蓝图里操作路径也直接:在蓝图图表右键搜索Get Net Mode,把World连进去,再用Switch on ENetMode分支处理,它判断的是World级别,不判断某个Actor是不是本地玩家。
UE4服务器和客户端区分方法对比:NetMode、Authority与LocalController
几个判断点解决的并不是同一个问题,混用就容易写出“服务器上正常、客户端上失效”的逻辑,可以对照下面这张表:
| 判断方式 | 服务器端表现 | 客户端表现 | 适用对象 | 常见坑 |
|---|---|---|---|---|
GetNetMode() |
专用服务器或监听服务器 | 纯客户端 | World级别 | 监听服务器本机玩家同时有本地表现 |
GetLocalRole()==ROLE_Authority |
通常为true | 本地控制Pawn常为AutonomousProxy,其他为SimulatedProxy |
Actor | 单机模式下也为true |
HasAuthority() |
true | 通常false | Actor | 不能拿来判断“是不是网络服务器” |
IsLocalController() |
主机玩家PC为true,远程PC为false | 本地PC为true | PlayerController | 专用服务器上通常没有本地PC |
IsLocallyControlled() |
主机玩家Pawn为true | 本地玩家Pawn为true | Pawn | 远程玩家Pawn为false |
GetAuthGameMode() |
有值 | 通常为空 | GameMode | 客户端本来就没有GameMode |
关键区别在这里:HasAuthority表达“当前端对这个Actor有没有权威”,不是表达“当前World是不是服务器”,在NM_Standalone下,Actor的HasAuthority()同样可能为true;但在网络项目里,你真正想判断的往往是World有没有服务器职责,这时看GetNetMode()更稳。
UE4联机游戏中区分Server和Client的实操步骤
在真实项目里,不建议到处随手写判断,而是按“World级别、Actor级别、玩家级别”分层处理,下面这套步骤可直接落地。
- World级别判断:在GameMode、GameState、网络管理类里用
GetWorld()->GetNetMode(),服务器逻辑放在NM_DedicatedServer或NM_ListenServer分支;客户端表现放在NM_Client分支;单机模式单独处理。 - Actor级别判断:在Actor的
BeginPlay或业务函数里用GetLocalRole(),需要服务器权威逻辑时判断ROLE_Authority;需要客户端模拟逻辑时判断ROLE_SimulatedProxy或ROLE_AutonomousProxy。 - 玩家级别判断:在PlayerController里用
IsLocalController();在Pawn里用IsLocallyControlled(),本地输入、摄像机、UI通常只应在本地控制器上执行。 - 注意调用时机:不要在Actor构造函数里判断网络模式,那时World和网络角色未必可靠,复制Actor在客户端
的时机也可能晚于服务器,涉及玩家状态时可在BeginPlay
OnRep_PlayerState或合适的初始化回调里处理。
蓝图里怎么判断服务器客户端:Switch Has Authority与Get Net Mode
蓝图里最常用的节点不是“猜”,而是明确用途:
- 判断World网络模式:
Get World->Get Net Mode->Switch on ENetMode。 - 判断Actor权威:
Switch Has Authority。Authority分支适合放服务器结算、生成掉落、修改关键属性;Remote分支适合放客户端表现。 - 判断本地玩家Pawn:
Is Locally Controlled。 - 判断本地PlayerController:
Is Local Controller。 - 判断GameMode:客户端拿不到
GameMode时不要慌,这是正常设计,客户端应通过GameState或PlayerState同步显示所需数据。
一个常见场景:开箱子,服务器分支负责扣除钥匙、生成奖励、写玩家背包;客户端分支只播放开箱动画和音效,这样即使客户端被修改,奖励结算仍以服务器为准。
UE4专用服务器部署成本与网络模式判断
专用服务器模式下,World的NetMode固定为NM_DedicatedServer,客户端为NM_Client,判断逻辑反而简单,部署成本主要看云主机规格、带宽和并发连接数,按云服务商公开计费项通常围绕CPU、内存、带宽展开,具体价格随地域和配置变化,监听服务器成本低,主机玩家有本地优势,但World的NetMode是NM_ListenServer,不能因为本机玩家在跑就误判成纯客户端,业内专家指出,网络模式判断应独立于部署成本做封装,否则换服务器形态时容易牵动大量业务代码。
国内UE4项目服务器客户端区分常见做法
国内UE4项目里,较常见的做法是把网络判断收进一个BlueprintFunctionLibrary或C++工具类,业务层只调用IsServerWorld、IsClientWorld、IsLocalPlayerController这类语义化函数,行业共识认为,统一封装比在每个Actor里散写GetNetMode()更容易维护,也方便排查“单机正常、联机异常”的问题。
C++项目可以这样封装玩家判断:
bool IsLocalPC(const APlayerController PC)
{
return PC && PC->IsLocalController();
}
bool IsLocalPawn(const APawn Pawn)
{
return Pawn && Pawn->IsLocallyControlled();
}
还要避开几个坑:
- 用
GetNetMode()==NM_Client判断“所有客户端逻辑”,但监听服务器主机玩家的本地表现不在这个分支里。 - 用
HasAuthority()判断“是不是服务器”,单机模式下会得到true。 - 在
Tick里反复取GetNetMode(),多数情况下没必要,缓存或按初始化阶段判断即可。 - 把
GameMode当客户端通用入口,客户端通常拿不到,应该改用GameState或PlayerState。 - 在构造函数里做网络分支,容易拿到未初始化完成的World。
核心结论再收一下:World级别看ENetMode,Actor权威看LocalRole,本地玩家看IsLocalController或IsLocallyControlled,三者分工清楚,UE4服务器客户端区分就不会乱。
Q&A:UE4服务器客户端区分的高频问题
Q1:UE4里HasAuthority为true就一定是服务器吗?
不一定。HasAuthority表示当前端对这个Actor拥有权威,单机NM_Standalone下它也可能为true;专用服务器和监听服务器上通常为true;纯客户端上通常为false,要判断World是不是网络服务器,应看GetNetMode()是否返回NM_DedicatedServer或NM_ListenServer。
Q2:UE4监听服务器上本地玩家到底算服务器还是客户端?
World层面看,监听服务器的NetMode是NM_ListenServer,所以它承担服务器职责;主机玩家的PlayerControllerIsLocalController()为true,Pawn的IsLocallyControlled()为true,同时承担本地客户端表现,判断“逻辑该不该在服务器跑”用NetMode或Actor权威,判断“是不是本地玩家”用本地控制相关接口。
Q3:UE4专用服务器和客户端区分时,为什么GameMode在客户端拿不到?
GameMode默认只在服务器存在,负责游戏规则和流程;客户端通过GameState、PlayerState等复制数据获得显示所需状态,因此客户端调用GetAuthGameMode()通常为空,这属于UE4网络复制模型的正常行为。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/770131.html





