自定义UObject进行Replicate

UE本身有一套自创的网络框架, 在这个框架里UObject类型默认是无法进行属性同步的. 如果想要UObject进行属性同步就必须进行一系列重写.

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// .h
UCLASS(BlueprintType, Blueprintable)
class UMyTestObject : public UObject
{
GENERATED_BODY()
public:
UMyTestObject(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

public:
// Allows the Object to get a valid UWorld from it's outer.
virtual UWorld* GetWorld() const override;

// allow replicate data
virtual bool IsSupportedForNetworking() const override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

// allow rpc
int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack);
bool CallRemoteFunction(UFunction* Function, void* Parameters, struct FOutParmRec* OutParams, FFrame* Stack);

public:
UPROPERTY(Replicated)
uint32 bReplicatedFlag : 1;
};


// .cpp
UMyTestObject::UMyTestObject(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
:UObject(ObjectInitializer)
{

}

UWorld* UMyTestObject::GetWorld() const
{
if (const UObject* MyOuter = GetOuter())
{
return MyOuter->GetWorld();
}
return nullptr;
}

bool UMyTestObject::IsSupportedForNetworking() const
{
return true;
}

void UMyTestObject::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UMyTestObject, bReplicatedFlag);
}

bool UMyTestObject::CallRemoteFunction(UFunction* Function, void* Parameters, struct FOutParmRec* OutParams, FFrame* Stack)
{
if (AActor* OuterActor = Cast<AActor>(GetOuter()))
{
UNetDriver* NetDriver = OuterActor->GetNetDriver();
if (NetDriver)
{
NetDriver->ProcessRemoteFunction(OuterActor, Function, Parameters, OutParams, Stack, this);
return true;
}
}
return false;
}

int32 UMyTestObject::GetFunctionCallspace(UFunction* Function, FFrame* Stack)
{
if (AActor* OuterActor = Cast<AActor>(GetOuter()))
{
return OuterActor->GetFunctionCallspace(Function, Stack);
}

return FunctionCallspace::Local;
}

在BasePlayerController.h中添加:

由于Replicated, 需要将pTestObj添加到GetLifetimeReplicatedProps中.

重写ABasePlayerController::ReplicateSubobjects函数, 将pTestObj添加到ABasePlayerController列表中.

在BasePlayerController.cpp中动态创建:

经过上述步骤, 可以将自定义UMyTestObject进行属性同步.

UE Replicate流程

UE在进行属性同步时候, 首先进行Actor自身的属性同步, 然后同步SubObject, 最后才同步自定义UObject.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 自定义UObject属性同步流程
--UNetDriver.TickFlush()
|--UNetDriver.ServerReplicateActors()
| |--UNetDriver.ServerReplicateActors_ProcessPrioritizedActors()
| | |--UActorChannel.ReplicateActor()
| | | |--// 同步该Actor自身属性
| | | |--FObjectReplicator.ReplicateProperties()
| | | |--AActor.ReplicateSubobjects()
| | | | |--// 同步Actor中所有需要Replicated的ActorComponent
| | | | |--UActorComponent.ReplicateSubobjects()
| | | | |--UActorChannel.ReplicateSubobject()
| | | | |--// 自定义UObject进行属性同步
| | | | |--UActorChannel.ReplicateSubobject()

引用:RPC浅析