【UE】属性同步,源码详解一个勾选了Actor复制的Actor第一次被创建时经历了什么

本文参考https://zhuanlan.zhihu.com/p/640723352

准备工作

先准备一个勾选了复制的Actor,然后在游戏开始时Spawn这个Actor
在这里插入图片描述
在这里插入图片描述

源码过程详解

发送属性同步

在NetDriver的TickFlush中发送属性同步的数据
1、ServerReplicateActors_BuildConsiderList 去找到所有需要属性同步的Actor,并根据一些规则过滤掉一部分
2、ServerReplicateActors_PrioritizeActors 按照优先级对Actor进行排序,不可靠的RPC也会被添加到需要发送的Actor数组末尾
3、ServerReplicateActors_ProcessPrioritizedActors 遍历每个需要发送的Actor
这里就可以找到我们的Actor
在这里插入图片描述
因为是第一次属性同步的数据,所以这个Actor还没有Channel,就会走到这里的创建Channel的逻辑
Channel就是通道,每个网络复制的Actor都有一个,服务端通过Channel将属性同步的数据发送到客户端
在这里插入图片描述
然后走到Channel->ReplicateActor()去执行这个通道的属性同步的操作
在这里插入图片描述
第一次属性同步会走到PackageMapClient类的SerializeNewActor,这里的Connection就是客户端连接。
PackageMap每个Server和Client都会有一个,该对象负责Actor和NetworkGUID的双向映射,以及序列化一个Object。
在这里插入图片描述
然后走到SerializeObject
在这里插入图片描述
调用InternalWriteObject将NetGUID写入到Bunch中,如果有PathName也会一起写入到Bunch中
在这里插入图片描述
NetGUID是一个结构体,是网络复制Actor的唯一标识符,用于复制时判断是否为相同的Actor,如果有PathName就根据PathName判断,没有PathName就根据Value判断,PathName就是Actor的路径 + 编号
在这里插入图片描述
在这里插入图片描述
Archetype:Actor的CDO信息
ActorLevel:Actor所属关卡,同步接受时是根据Level来找Actor的
Location、Scale、Velocity、Rotation这几个Actor属性
在这里插入图片描述
无论在服务器还是客户端,CDO的路径是固定的,只和资源路径有关,与World无关。
比如在Game目录下创建了一个蓝图类,那么它的CDO路径为/Game/TestActor.Default__TestActor_C
如果是C++类,那路径更加毫无疑问是一致的。
我们序列化CDO,只要序列化其路径即可,而且UE把所有UObject的网络同步都交给UPackageMapClient统一管理,CDO也有NetworkGUID,只有第一次同步时需要同步路径,后面都同步NetworkGUID,我们先都考虑第一次同步情况。
具体逻辑通过ExportNetGUID函数实现,它会写入<NetworGUID, path>对应关系,客户端收到后能在本地也建立起这个关系。如果Object有Outer,也要对Outer执行同样操作,把Outer关系也发送给客户端。
通过ExportNetGUID生产的序列化数据后续会被写入bunch前部,相对于把Object和GUID的映射先告诉客户端,客户端在处理后续Bunch时碰到对应NetworkGUID,就知道是哪个Object了。

匿名函数ConditionallySerializeQuantizedVector将Location、Rotation等属性序列化到Bunch中
在这里插入图片描述
在这里插入图片描述
然后去发送属性同步Packet
在这里插入图片描述

接收属性同步

堆栈
在这里插入图片描述
1、是Actor的第一次属性同步,所以接收时客户端还没有这个Actor
也是这六个属性
在这里插入图片描述
SerializeObject去序列化Actor数据到Archetype
在这里插入图片描述
读取到ActorLevel、Location、Rotation等信息
在这里插入图片描述
在这里插入图片描述
如果Actor为空,Archetype(CDO)不为空,就去生成Actor,并附带位置、旋转、所在关卡等信息
在这里插入图片描述
如果Actor生成成功再去添加速度、缩放属性
在这里插入图片描述
去客户端注册这个Actor,也就是去ObjectLookup数组中添加这个Actor,下一次再有属性同步数据时就可以找到这个Actor了
在这里插入图片描述
如果是新生成的Actor执行PostNetInit(),去执行Actor的BeginPlay
在这里插入图片描述
在这里插入图片描述
至此一个Actor的第一次属性复制的流程结束

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过以下步骤在UE4中创建一个Actor并实现截图保存功能: 1. 创建一个继承自Actor的C++类,例如命名为MyActor。 2. 在MyActor.h中添加以下头文件: ```c++ #include "Engine/TextureRenderTarget2D.h" #include "Engine/Texture2D.h" ``` 3. 声明一个TextureRenderTarget2D成员变量和一个Texture2D成员变量: ```c++ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screenshot") UTextureRenderTarget2D* ScreenshotRenderTarget; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Screenshot") UTexture2D* ScreenshotTexture; ``` 4. 在MyActor.cpp中重写BeginPlay()函数,创建RenderTarget和Texture: ```c++ void AMyActor::BeginPlay() { Super::BeginPlay(); ScreenshotRenderTarget = UGameplayStatics::CreateRenderTarget2D(GetWorld(), 1920, 1080); ScreenshotTexture = UTexture2D::CreateTransient(1920, 1080); } ``` 5. 在MyActor.cpp中添加一个截图函数: ```c++ void AMyActor::TakeScreenshot() { if (ScreenshotRenderTarget != nullptr && ScreenshotTexture != nullptr) { FTextureRenderTargetResource* RenderTargetResource = ScreenshotRenderTarget->GameThread_GetRenderTargetResource(); FReadSurfaceDataFlags ReadPixelFlags(RCM_UNorm); ReadPixelFlags.SetLinearToGamma(true); TArray<FColor> OutBMP; RHIReadSurfaceData(RenderTargetResource->GetRenderTargetTexture(), FIntRect(0, 0, ScreenshotRenderTarget->SizeX, ScreenshotRenderTarget->SizeY), OutBMP, ReadPixelFlags); ScreenshotTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE); uint8* TextureData = (uint8*)ScreenshotTexture->PlatformData->Mips[0].BulkData.Realloc(OutBMP.Num() * 4); for (int32 i = 0; i < OutBMP.Num(); i++) { TextureData[i * 4 + 0] = OutBMP[i].B; TextureData[i * 4 + 1] = OutBMP[i].G; TextureData[i * 4 + 2] = OutBMP[i].R; TextureData[i * 4 + 3] = OutBMP[i].A; } ScreenshotTexture->PlatformData->Mips[0].BulkData.Unlock(); ScreenshotTexture->UpdateResource(); FString FileName = FPaths::ProjectSavedDir() + TEXT("Screenshots/MyScreenshot.png"); FFileHelper::SaveArrayToFile(ScreenshotTexture->PlatformData->Mips[0].BulkData, *FileName); } } ``` 6. 在MyActor.cpp中添加一个函数,用于在按下某个按键调用截图函数: ```c++ void AMyActor::CaptureScreenshot() { TakeScreenshot(); } ``` 7. 在MyActor的Blueprint中添加一个InputComponent,将某个按键与CaptureScreenshot函数绑定即可。 完成以上步骤后,你就可以在UE4中创建一个Actor,并在其中实现截图保存功能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值