Mapz's Blog

可以递归的函数指针

UE4:RPC调用部分代码学习

CallRemoteFunction

函数直接定义在 UObject 上,但是无意义

1
2
3
4
5
6
7
8
9
10
11
/**
* Call the actor's function remotely
*
* @param Function function to call
* @param Parameters arguments to the function call
* @param Stack stack frame for the function call
*/
virtual bool CallRemoteFunction( UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack )
{
return false;
}

在需要的类型上,可以自己重载函数

典型的就是 Actor 的 CallRemoteFunction

Actor RPC 流程

  1. 执行 AActor::CallRemoteFunction
  2. 调用 UNetDriver::ProcessRemoteFunction
  3. 尝试执行 UReplicationDriver::ProcessRemoteFunction

    UReplicationDriver::ProcessRemoteFunction 默认实现总是会返回失败

  4. 尝试执行失败后,执行默认 RPC 方案
    a. 是 Server Multicast 则遍历所有 Connection
    b. 针对 Connection,判断 Actor 是否 IsNetRelevantFor,或者是否为 Reliable 的 RPC,排除不符合条件的 Connection
    c. 调用 RepLayout->BuildSharedSerializationForRPC 生成共享的 RPC 数据缓存
    d. 调用 UNetDriver::InternalProcessRemoteFunctionPrivate
    e. 遍历完成后调用 RepLayout->ClearSharedSerializationForRPC 清除 RPC 数据共享缓存
    f. 不是 Multicast,则调用 UNetDriver::InternalProcessRemoteFunction,内部依然调用的是 UNetDriver::InternalProcessRemoteFunctionPrivate

UNetDriver::InternalProcessRemoteFunctionPrivate 流程

  1. 获得连接,判断类型和函数的 NetCache 是否存在

  2. 获得或者创建 UActorChannel

  3. 调用 UNetDriver::ProcessRemoteFunctionForChannelPrivate
    a. 如果 ActorChanel 还没有 Open,则开启 Open 步骤,初始化同步一次 Actor
    b. 开始搭建 RPC Bunch
    c. 写入 RPC 参数的值

    1
    2
    TSharedPtr<FRepLayout> RepLayout = GetFunctionRepLayout(Function);
    RepLayout->SendPropertiesForRPC(Function, Ch, TempWriter, Parms);

    d. 装载类型ID,函数ID,和参数值到 Bunch
    e. 根据是否使用队列,判断是加入 RPC 队列还是直接调用
    f. 如果是 RPC 队列,则加入队列

    1
    Ch->QueueRemoteFunctionBunch(TargetObj, Function, Bunch);

    g. 如果直接发送,则发送 Bunch

    1
    Ch->SendBunch(&Bunch, true);