跳至主要內容

NT-2.3.1|UObject复制同步和RPC

Mr.Si大约 2 分钟unreal

本章概要

非Actor对象,比如原生的UObject如何实现同步?以及调用RPC

问题

头像
BABA!我发现一个怪BUG!看下图,有两个数组都开启了复制,一个数组中存了一堆Actor,另一个则是一堆UObject指针
服务端上查看客户端显示正常
服务端上查看客户端显示正常
客户端上可以看到UObject为未知
客户端上可以看到UObject为未知
头像
这是为什么?为什么客户端不能正确同步UObject?
头像
UE原生的UObject默认是无法网络同步的,而Actor可以,所以可以改用Actor指针代替。

变量同步

1. 重写 IsSupportedForNetworking

在自定义 UObject 类中重写 IsSupportedForNetworking 函数,使其返回 true,标记该对象支持网络复制。

UCLASS()
class YOURGAME_API UInventoryPickUpData : public UObject
{
    GENERATED_BODY()

public:
    virtual bool IsSupportedForNetworking() const override
    {
        return true;
    }

    UPROPERTY(Replicated)
    int32 ItemID;

    // 添加其他需要复制的属性
};

2. 标记属性为 Replicated

确保复制的属性被标记为 UPROPERTY(Replicated) 或者使用 ReplicateUsing

3. 实现复制支持

在拥有 UObject 子对象的类中,使用 GetLifetimeReplicatedProps 函数实现复制支持:

void AYourActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // 添加需要复制的子对象
    DOREPLIFETIME(AYourActor, InventoryItem);
}

4. 调用 ReplicateSubobject

确保在 AActorGetSubobjectsWithStableNamesForNetworkingReplicateSubobjects 函数中调用 ReplicateSubobject

bool AYourActor::ReplicateSubobjects(class UActorChannel* Channel, class FOutBunch* Bunch, FReplicationFlags* RepFlags)
{
    bool WroteSomething = Super::ReplicateSubobjects(Channel, Bunch, RepFlags);

    if (InventoryItem)
    {
        WroteSomething |= Channel->ReplicateSubobject(InventoryItem, *Bunch, *RepFlags);
    }

    return WroteSomething;
}

5. 初始化并确保对象正确创建

在构造函数或其他初始化函数中创建和初始化子对象:

AYourActor::AYourActor()
{
    bReplicates = true;
    InventoryItem = CreateDefaultSubobject<UInventoryPickUpData>(TEXT("InventoryItem"));
}

RPC

头像
巧妙地利用了 AActor 的网络处理功能,使 UObject 能够间接地进行网络通信。

1.确保属性变量拥有UPROPERTY(Replicated),UFUNCTION()等反射标记

2. 重写接口(虚函数)


virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
	
virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override;

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

	return FunctionCallspace::Local;
}

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

  1. 正常RPC函数
	UFUNCTION(BlueprintCallable,Server,Reliable)
	void SpawnPickUpActor(const FTransform& SpawnTransform);

	UFUNCTION(BlueprintCallable,Client,Reliable)
	void ClientSpawnPickUpActor(const FTransform& SpawnTransform);

扩展阅读

大佬博客open in new window