# Unreal RPC

RPC 在 Unreal 中被广泛运用,是除了 Replication 之外唯二的数据传输方式(另一个是手动压解的收发包模式)。

RPC(Remote Procedure Call)远程过程调用,简单来说就是像执行本地函数一样的调用远程服务接口,简化调用编码复杂度,那么在 Unreal 中具体是如何实现的呢?

# RPC 函数定义

这里以 ServerSetReplicatedTargetData 函数为例,详细了解一下 Unreal 中关于 RPC 的定义:

UFUNCTION(Server, reliable, WithValidation)
void ServerSetReplicatedTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, const FGameplayAbilityTargetDataHandle& ReplicatedTargetDataHandle, FGameplayTag ApplicationTag, FPredictionKey CurrentPredictionKey);

在类声明中,使用 UFUNCTION 宏声明 RPC 函数,并使用 ServerClientNetMulticast 关键字指定 RPC 类型。

  • Server :由客户端调用,但在服务器上执行的函数。
  • Client :由服务器调用,但在特定客户端上执行的函数。
  • NetMulticast :由服务器调用,并在所有连接的客户端上执行的函数。

通过 UHT 生成后的函数定义如下:

GAMEPLAYABILITIES_API UScriptStruct* Z_Construct_UScriptStruct_FGameplayAbilitySpecHandle();
// -------------------------- execFunction --------------------------
DEFINE_FUNCTION(UAbilitySystemComponent::execServerSetReplicatedTargetData)
{
    P_GET_STRUCT(FGameplayAbilitySpecHandle,Z_Param_AbilityHandle);
    P_GET_STRUCT(FPredictionKey,Z_Param_AbilityOriginalPredictionKey);
    P_GET_STRUCT(FGameplayAbilityTargetDataHandle,Z_Param_ReplicatedTargetDataHandle);
    P_GET_STRUCT(FGameplayTag,Z_Param_ApplicationTag);
    P_GET_STRUCT(FPredictionKey,Z_Param_CurrentPredictionKey);
    P_FINISH;
    P_NATIVE_BEGIN;
    if (!P_THIS->ServerSetReplicatedTargetData_Validate(Z_Param_AbilityHandle,Z_Param_AbilityOriginalPredictionKey,Z_Param_ReplicatedTargetDataHandle,Z_Param_ApplicationTag,Z_Param_CurrentPredictionKey))
    {
        RPC_ValidateFailed(TEXT("ServerSetReplicatedTargetData_Validate"));
        return;
    }
    P_THIS->ServerSetReplicatedTargetData_Implementation(Z_Param_AbilityHandle,Z_Param_AbilityOriginalPredictionKey,Z_Param_ReplicatedTargetDataHandle,Z_Param_ApplicationTag,Z_Param_CurrentPredictionKey);
    P_NATIVE_END;
}
struct AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms
{
    FGameplayAbilitySpecHandle AbilityHandle;
    FPredictionKey AbilityOriginalPredictionKey;
    FGameplayAbilityTargetDataHandle ReplicatedTargetDataHandle;
    FGameplayTag ApplicationTag;
    FPredictionKey CurrentPredictionKey;
};
// -------------------------- Function --------------------------
static FName NAME_UAbilitySystemComponent_ServerSetReplicatedTargetData = FName(TEXT("ServerSetReplicatedTargetData"));
void UAbilitySystemComponent::ServerSetReplicatedTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FGameplayAbilityTargetDataHandle const& ReplicatedTargetDataHandle, FGameplayTag ApplicationTag, FPredictionKey CurrentPredictionKey)
{
    AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms Parms;
    Parms.AbilityHandle=AbilityHandle;
    Parms.AbilityOriginalPredictionKey=AbilityOriginalPredictionKey;
    Parms.ReplicatedTargetDataHandle=ReplicatedTargetDataHandle;
    Parms.ApplicationTag=ApplicationTag;
    Parms.CurrentPredictionKey=CurrentPredictionKey;
    ProcessEvent(FindFunctionChecked(NAME_UAbilitySystemComponent_ServerSetReplicatedTargetData),&Parms);
}
// 把函数定义注册到 UAbilitySystemComponent 类里
void UAbilitySystemComponent::StaticRegisterNativesUAbilitySystemComponent()
{
    UClass* Class = UAbilitySystemComponent::StaticClass();
    static const FNameNativePtrPair Funcs[] = {
		{ "ServerSetReplicatedTargetData", &UAbilitySystemComponent::execServerSetReplicatedTargetData },
    };
    FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, UE_ARRAY_COUNT(Funcs));
}
// -------------------------- Function MetaData --------------------------
struct Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics
{
    static const UECodeGen_Private::FStructPropertyParams NewProp_AbilityHandle;
    static const UECodeGen_Private::FStructPropertyParams NewProp_AbilityOriginalPredictionKey;
    #if WITH_METADATA
    static const UECodeGen_Private::FMetaDataPairParam NewProp_ReplicatedTargetDataHandle_MetaData[];
    #endif
    static const UECodeGen_Private::FStructPropertyParams NewProp_ReplicatedTargetDataHandle;
    static const UECodeGen_Private::FStructPropertyParams NewProp_ApplicationTag;
    static const UECodeGen_Private::FStructPropertyParams NewProp_CurrentPredictionKey;
    static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[];
    #if WITH_METADATA
    static const UECodeGen_Private::FMetaDataPairParam Function_MetaDataParams[];
    #endif
    static const UECodeGen_Private::FFunctionParams FuncParams;
};
const UECodeGen_Private::FStructPropertyParams Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_AbilityHandle = { "AbilityHandle", nullptr, (EPropertyFlags)0x0010000000000080, UECodeGen_Private::EPropertyGenFlags::Struct, RF_Public|RF_Transient|RF_MarkAsNative, 1, nullptr, nullptr, STRUCT_OFFSET(AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms, AbilityHandle), Z_Construct_UScriptStruct_FGameplayAbilitySpecHandle, METADATA_PARAMS(nullptr, 0) }; // 3562347300
const UECodeGen_Private::FStructPropertyParams Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_AbilityOriginalPredictionKey = { "AbilityOriginalPredictionKey", nullptr, (EPropertyFlags)0x0010000000000080, UECodeGen_Private::EPropertyGenFlags::Struct, RF_Public|RF_Transient|RF_MarkAsNative, 1, nullptr, nullptr, STRUCT_OFFSET(AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms, AbilityOriginalPredictionKey), Z_Construct_UScriptStruct_FPredictionKey, METADATA_PARAMS(nullptr, 0) }; // 2453680625
#if WITH_METADATA
const UECodeGen_Private::FMetaDataPairParam Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ReplicatedTargetDataHandle_MetaData[] = {
    { "NativeConst", "" },
};
#endif
const UECodeGen_Private::FStructPropertyParams Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ReplicatedTargetDataHandle = { "ReplicatedTargetDataHandle", nullptr, (EPropertyFlags)0x0010000008000082, UECodeGen_Private::EPropertyGenFlags::Struct, RF_Public|RF_Transient|RF_MarkAsNative, 1, nullptr, nullptr, STRUCT_OFFSET(AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms, ReplicatedTargetDataHandle), Z_Construct_UScriptStruct_FGameplayAbilityTargetDataHandle, METADATA_PARAMS(Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ReplicatedTargetDataHandle_MetaData, UE_ARRAY_COUNT(Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ReplicatedTargetDataHandle_MetaData)) }; // 3993235140
const UECodeGen_Private::FStructPropertyParams Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ApplicationTag = { "ApplicationTag", nullptr, (EPropertyFlags)0x0010000000000080, UECodeGen_Private::EPropertyGenFlags::Struct, RF_Public|RF_Transient|RF_MarkAsNative, 1, nullptr, nullptr, STRUCT_OFFSET(AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms, ApplicationTag), Z_Construct_UScriptStruct_FGameplayTag, METADATA_PARAMS(nullptr, 0) }; // 1225434376
const UECodeGen_Private::FStructPropertyParams Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_CurrentPredictionKey = { "CurrentPredictionKey", nullptr, (EPropertyFlags)0x0010000000000080, UECodeGen_Private::EPropertyGenFlags::Struct, RF_Public|RF_Transient|RF_MarkAsNative, 1, nullptr, nullptr, STRUCT_OFFSET(AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms, CurrentPredictionKey), Z_Construct_UScriptStruct_FPredictionKey, METADATA_PARAMS(nullptr, 0) }; // 2453680625
const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::PropPointers[] = {
    (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_AbilityHandle,
    (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_AbilityOriginalPredictionKey,
    (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ReplicatedTargetDataHandle,
    (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_ApplicationTag,
    (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::NewProp_CurrentPredictionKey,
};
#if WITH_METADATA
const UECodeGen_Private::FMetaDataPairParam Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::Function_MetaDataParams[] = {
    { "Comment", "/** Replicates targeting data to the server */" },
    { "ModuleRelativePath", "Public/AbilitySystemComponent.h" },
    { "ToolTip", "Replicates targeting data to the server" },
};
#endif
const UECodeGen_Private::FFunctionParams Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_UAbilitySystemComponent, nullptr, "ServerSetReplicatedTargetData", nullptr, nullptr, sizeof(AbilitySystemComponent_eventServerSetReplicatedTargetData_Parms), Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::PropPointers, UE_ARRAY_COUNT(Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::PropPointers), RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x80220CC0, 0, 0, METADATA_PARAMS(Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::Function_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::Function_MetaDataParams)) };
UFunction* Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData()
{
    static UFunction* ReturnFunction = nullptr;
    if (!ReturnFunction)
    {
        UECodeGen_Private::ConstructUFunction(&ReturnFunction, Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData_Statics::FuncParams);
    }
    return ReturnFunction;
}
const FClassFunctionLinkInfo Z_Construct_UClass_UAbilitySystemComponent_Statics::FuncInfo[] = {
	{ &Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData, "ServerSetReplicatedTargetData" }, // 2588216155
}

生成代码大致可以分为三个部分内容:

  • ServerSetReplicatedTargetData 函数的 MetaData,其中包括描述函数参数的 UECodeGen_Private::FStructPropertyParams 以及函数转为 UFunction 的构造函数 Z_Construct_UFunction_UAbilitySystemComponent_ServerSetReplicatedTargetData ,之后会在 Z_Construct_UClass_UAbilitySystemComponent_Statics 类中注册这些 UFunction 工厂函数,在 UClass 的创建的时候把这些 UFunction 也一并创建,然后就可以通过反射进行函数查找了。
struct FStructPropertyParams // : FPropertyParamsBaseWithOffset
{
    const char*      NameUTF8;
    const char*         RepNotifyFuncUTF8;
    EPropertyFlags      PropertyFlags;
    EPropertyGenFlags   Flags;
    EObjectFlags     ObjectFlags;
    int32            ArrayDim;
    SetterFuncPtr  SetterFunc;
    GetterFuncPtr  GetterFunc;
    int32            Offset;
    UScriptStruct* (*ScriptStructFunc)();
#if WITH_METADATA
	const FMetaDataPairParam*           MetaDataArray;
	int32                               NumMetaData;
#endif
};
  • ServerSetReplicatedTargetData 函数本身,这个函数除了打包参数以外什么都不会去做,而是通过 ProcessEvent 统一调用函数执行,函数查询时通过函数名 "ServerSetReplicatedTargetData"。ProcessEvent 不仅仅会调用函数,还会根据函数的类型、进程的 NetMode、角色的权威性、决定在哪里(本地 or 远程服务器)调用。

image-20230907103825299

  • execServerSetReplicatedTargetData 函数,该函数内会调用两个固定接口 「xxx_Validatexxx_Implementation」。远程调用的时候,会通过 RPC 获取到函数名 "ServerSetReplicatedTargetData",然后通过 Object->FindFunction(FunctionName) 查找到该函数,execServerSetReplicatedTargetData 的注册是在 StaticRegisterNativesUAbilitySystemComponent 是进行的。

image-20230907105035027

# execServerSetReplicatedTargetData 展开

// 展开前
DEFINE_FUNCTION(UAbilitySystemComponent::execServerSetReplicatedTargetData)
{
    P_GET_STRUCT(FGameplayAbilitySpecHandle,Z_Param_AbilityHandle);
    P_GET_STRUCT(FPredictionKey,Z_Param_AbilityOriginalPredictionKey);
    P_GET_STRUCT(FGameplayAbilityTargetDataHandle,Z_Param_ReplicatedTargetDataHandle);
    P_GET_STRUCT(FGameplayTag,Z_Param_ApplicationTag);
    P_GET_STRUCT(FPredictionKey,Z_Param_CurrentPredictionKey);
    P_FINISH;
    P_NATIVE_BEGIN;
    if (!P_THIS->ServerSetReplicatedTargetData_Validate(Z_Param_AbilityHandle,Z_Param_AbilityOriginalPredictionKey,Z_Param_ReplicatedTargetDataHandle,Z_Param_ApplicationTag,Z_Param_CurrentPredictionKey))
    {
        RPC_ValidateFailed(TEXT("ServerSetReplicatedTargetData_Validate"));
        return;
    }
    P_THIS->ServerSetReplicatedTargetData_Implementation(Z_Param_AbilityHandle,Z_Param_AbilityOriginalPredictionKey,Z_Param_ReplicatedTargetDataHandle,Z_Param_ApplicationTag,Z_Param_CurrentPredictionKey);
    P_NATIVE_END;
}
// 展开后
void UAbilitySystemComponent::execServerSetReplicatedTargetData(UObject* Context,
                                                                FFrame& Stack,
                                                                void* const Z_Param__Result)
{
    FGameplayAbilitySpecHandle Z_Param_AbilityHandle;
    Stack.StepCompiledIn<FStructProperty>(&Z_Param_AbilityHandle);;
    FPredictionKey Z_Param_AbilityOriginalPredictionKey;
    Stack.StepCompiledIn<FStructProperty>(&Z_Param_AbilityOriginalPredictionKey);;
    FGameplayAbilityTargetDataHandle Z_Param_ReplicatedTargetDataHandle;
    Stack.StepCompiledIn<FStructProperty>(&Z_Param_ReplicatedTargetDataHandle);;
    FGameplayTag Z_Param_ApplicationTag;
    Stack.StepCompiledIn<FStructProperty>(&Z_Param_ApplicationTag);;
    FPredictionKey Z_Param_CurrentPredictionKey;
    Stack.StepCompiledIn<FStructProperty>(&Z_Param_CurrentPredictionKey);;
    Stack.Code += !!Stack.Code;;
    {
        FBlueprintEventTimer::FScopedNativeTimer ScopedNativeCallTimer;;
        if (!((ThisClass*)(Context))
                 ->ServerSetReplicatedTargetData_Validate(Z_Param_AbilityHandle,
                                                          Z_Param_AbilityOriginalPredictionKey,
                                                          Z_Param_ReplicatedTargetDataHandle,
                                                          Z_Param_ApplicationTag,
                                                          Z_Param_CurrentPredictionKey))
        {
            RPC_ValidateFailed(TEXT("ServerSetReplicatedTargetData_Validate"));
            return;
        }
        ((ThisClass*)(Context))
            ->ServerSetReplicatedTargetData_Implementation(Z_Param_AbilityHandle,
                                                           Z_Param_AbilityOriginalPredictionKey,
                                                           Z_Param_ReplicatedTargetDataHandle,
                                                           Z_Param_ApplicationTag,
                                                           Z_Param_CurrentPredictionKey);
    }
}

展开后的 execServerSetReplicatedTargetData 会执行 ServerSetReplicatedTargetData_ValidateServerSetReplicatedTargetData_Implementation

# Rpc Bunch 包结构

image-20230907171443816

  • FNetworkGUID 标识调用对象
  • FieldNetIndex 标识调用函数

# RPC 调用链路图

Client <-> DS

image-20231010152253641

ListenServer && Stalone

image-20231010152455642

更新于 阅读次数

请我[恰饭]~( ̄▽ ̄)~*

鑫酱(●'◡'●) 微信支付

微信支付

鑫酱(●'◡'●) 支付宝

支付宝