3.1 三种 RPC:Server、Client、NetMulticast 各自发给谁

一句话区分

RPC 类型 谁调用 发给谁 典型用途
Server RPC 任意端 这个 Actor 的权威端(拥有 Authority 的那份) 客户端「请求」做事:开火、上车、交互
Client RPC 任意端(通常是服务器) 这个 Actor 的拥有者客户端 服务器给某个玩家推事件:你被击中、任务完成
NetMulticast RPC 任意端(通常是服务器) 所有相关客户端 + 服务器本地 全场事件:爆炸、广播字幕、环境变化

记住一张方位图:Server RPC 向上(发往服务器),Client RPC 向单一客户端,Multicast 向所有客户端。

声明方式

// Server RPC:蓝图里勾 Run on Server
UFUNCTION(Server, Reliable, WithValidation)
void ServerFire(FVector TargetLocation);

// Client RPC:蓝图里勾 Run on owning client
UFUNCTION(Client, Reliable)
void ClientNotifyHit(float Damage);

// Multicast:蓝图里勾 Run on all clients
UFUNCTION(NetMulticast, Unreliable)
void MulticastExplode(FVector Center);

执行端的真实规则

关键细节:RPC 在「调用端」和「目标端」各有一次执行。以 Server RPC 为例:

  • 客户端调用 ServerFire() → 网络层把参数发给服务器 → 服务器上同名函数体执行一次。
  • 在服务器上直接调用 ServerFire() → 本地立即执行(不发网络包)。

这个「本地直接执行」行为常被忽略:你在服务器代码里调 ServerFire() 时,它就是一次普通函数调用。同理,ListenServer 主机上调用 Client RPC,因为主机同时是服务器和拥有者客户端,函数会在本地立即执行一次。

「_Implementation」函数体

C++ 里 Server RPC 的实际逻辑写在与名加 _Implementation 后缀的函数里,框架自动生成「网络层壳」:

void AMyCharacter::ServerFire_Implementation(FVector TargetLocation)
{
    // 真实逻辑只写在这里
}

调用 ServerFire() 时,框架判断当前端:服务器 → 直接调 _Implementation;客户端 → 序列化发送。不要直接调 _Implementation,那会绕过网络层。

Client RPC 的「拥有者」概念

Client RPC 发给「拥有这个 Actor 的客户端」——大多数情况下就是控制它的玩家。注意两个边界:

  • Actor 没有拥有者(如普通怪物)→ Client RPC 无处可发,静默丢弃。给怪物推「只给它自己看的提示」要用别的办法。
  • 拥有者是服务器的 Actor → 同样丢弃。

想让「非拥有者客户端也收到」?那是 Multicast 的活。想精确发给「某个指定客户端但不是拥有者」?原生 RPC 不直接支持——需要借助 PlayerController 上的 Client RPC(PlayerController 的拥有者天然就是对应玩家)。

Multicast 的「相关」收束

Multicast 名义上发给「所有客户端」,实际只发给此刻与该 Actor 相关的客户端。不在相关范围内的客户端收不到(这通常是好事,省带宽)。所以 Multicast 爆炸的时候请确保爆炸 Actor 相关性合理,否则远处玩家会「只听见声音不见爆炸」或反之。

心得:画联网架构时,我习惯用三种箭头标 RPC——实线箭头=Server RPC(请求)、虚线=Client RPC(定向推送)、双线=Multicast(广播)。一张图里哪些走状态复制、哪些走事件 RPC,一目了然。