UFUNCTION(Client)函数必须由服务器调用且仅在指定客户端执行,用于表现层逻辑如UI动画或本地提示;直接在客户端调用会被静默丢弃。

UFUNCTION(Client) 函数必须由服务器调用,且只在指定客户端执行
Client RPC 不是客户端自己触发的,这点容易误解。它本质是“服务器发指令,只让某个客户端跑这段代码”,比如播放只有该玩家能看到的 UI 动画、弹出本地任务提示、更新瞄准镜偏移。如果你在客户端 C++ 里直接调用 MyClientRPC(),编译能过,但运行时什么都不会发生——因为引擎会静默丢弃这个调用。
实操要点:
- 函数声明必须带
UFUNCTION(Client, Reliable)或UFUNCTION(Client, Unreliable);Reliable适合关键通知(如任务完成),Unreliable适合高频非关键操作(如轻微音效) - 服务端调用前,必须确保目标 Actor 的
Role == ROLE_AutonomousProxy或已正确设置 Owner(通常通过GetOwner()或PlayerController获取) - Client RPC 函数体写在 .cpp 里,但只在拥有对应 Net Role 的客户端上执行;服务端和其它客户端完全不进入该函数
- 不要在 Client RPC 里读取或修改服务端权威状态(比如直接改血量),它只是表现层逻辑
UFUNCTION(Server) 函数只能由拥有 AutonomousProxy 权限的客户端调用
Server RPC 是“客户端喊一声,服务器应答并执行”,典型场景是开火、拾取、跳跃确认。但它不是谁都能喊——只有本地控制的 Pawn(即 Role == ROLE_AutonomousProxy)才能发起调用。如果你在非拥有者客户端(比如观战视角)或服务端代码里调用 MyServerRPC(),调用会被忽略,且不会报错,只会静默失败。
实操要点:
- 声明必须含
UFUNCTION(Server, Reliable)或UFUNCTION(Server, Unreliable);Reliable用于需保证送达的操作(如关键交互),Unreliable用于高频移动同步(但注意:UE 官方更推荐用属性复制而非 Unreliable RPC 同步位置) - 必须实现
MyServerRPC_Implementation()函数体,这是服务器实际执行的逻辑;如果加了WithValidation,还要实现MyServerRPC_Validate()返回true才允许执行 - 在
MyServerRPC_Implementation()开头加if (!HasAuthority()) { return; }是冗余的——Server RPC 天然只在服务器执行,但检查GetLocalRole() == ROLE_Authority可以防其他误用 - 不要在 Server RPC 里直接修改客户端独有变量(如
bIsAiming),这类状态应走属性复制或 Client RPC 下发
RPC 函数不能有返回值,参数必须是复制安全类型
所有 RPC 函数签名都必须是 void,这是硬性限制。试图写 int32 MyServerRPC() 会导致编译失败,并报错 RPC functions must have void return type。另外,参数类型受限严格:只允许基本类型(int32、FVector、FString、bool)、UObject 指针(且必须是网络可识别的,如 AActor*)、以及实现了 NetSerialize 的结构体。传 TArray 前,FMyStruct 必须手动实现序列化。
常见踩坑点:
- 传入
UClass*或UEnum*指针会崩溃,改用FName或整型 ID 替代 - 传
TSubclassOf是安全的,但传TSoftClassPtr需确保资源已加载,否则客户端可能解析失败 - 避免传大结构体(如含数百字节的自定义 struct),Unreliable RPC 更容易因包大小被截断
- 如果需要“回调结果”,得拆成两步:Server RPC 提交请求 → 服务端处理完后,用 Client RPC 或属性变更通知客户端
Client 和 Server RPC 的调用时机依赖 PlayerController 连接就绪
刚连接进来的客户端,在 AGameMode::PostLogin() 执行完之前,它的 PlayerController 还没完全初始化网络连接。此时若服务端尝试调用该控制器拥有的 Actor 的 Client RPC,调用会失败(无日志、无声无息)。同样,客户端在 APlayerController::BeginPlay() 之后才具备调用 Server RPC 的能力。
安全做法:
- 服务端发 Client RPC 前,先检查
TargetActor->GetNetOwningPlayer()->IsReady()或监听OnRep_PlayerState确保 PlayerState 已同步 - 客户端调用 Server RPC 前,在
BeginPlay()后加延时 0.1 秒再调用,或监听GetLocalRole() == ROLE_AutonomousProxy变化 - 不要在
Construct、BeginDestroy或Tick中高频调用 RPC,尤其 Unreliable 类型,容易触发引擎内部丢包保护机制 - 调试时打开控制台命令
net.NetDump和net.DumpRPC,能实时看到 RPC 是否发出、被谁接收
RPC 最容易被忽略的其实是“谁有权限调用”和“谁真正执行”之间的错位。很多同步问题不是代码写错了,而是默认假设了调用端和服务端的角色一致。把 Role 和 Owner 当作每次调用前的必查项,比事后调试快得多。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











