UE5 MPCook 流程
UE5 MPCook 流程
首先给出 MPCook 的时序图
请点击查看大图

然后讲数据结构
1. 核心类
-
IWorkerRequests-
协调多进程/单进程任务调度的核心接口
-
它的派生类:
FWorkerRequestsLocal和FWorkerRequestsRemote- 派生类中的成员变量
FExternalRequests,FCookWorkerClient- ExternalRequests 中的成员变量
FFilePlatformRequest
- ExternalRequests 中的成员变量
- 派生类中的成员变量
-
-
FCookWorkerClient,FCookWorkerServer -
CookDirector -
IMPCollector
1.1 IWorkerRequests
用于发送请求到该进程的 Cooker 的接口,以及用于将信息返回给其 Director 的接口。
在单进程模式下,这些函数会被直接传递到本地的 COTFS(CookOnTheFlyServer)。
在多进程模式下,这些函数则通过进程间通信的方式实现,与 CookDirector 进行消息交互。
抽象类,所有函数都是虚函数且 (virtual xxx = 0;),只作声明,实现由派生类 FWorkerRequestsLocal 和 FWorkerRequestRemote 实现。

1.1.1 任务队列管理
-
外部请求处理:
作为 Worker 进程(执行具体 cook 任务的进程)与 Director 进程(任务调度中心)间的通信桥梁,管理来自不同源的 cook 请求和回调。
- 优先级处理:
- 回调 Callbacks 优先于普通烹饪请求(如
DequeueNextCluster)。
- 回调 Callbacks 优先于普通烹饪请求(如
- 无锁检查:
- 通过
HasExternalRequests和GetNumExternalRequests快速判断待处理任务,优化性能。
- 通过
- 批量出队:
- 支持按类型(回调 / Cook) 或全部出队请求,适应不同场景(如取消任务时的清理)。
- 优先级处理:
1.1.2 多进程协调
-
跨进程通信抽象:
在单进程模式下直接在操作本地
CookOnTheFlyServer,多进程时封装 IPC (进程间通信) 细节。- 任务分发:
- 通过
AddCookOnTheFlyRequest,AddStartCookByTheBookRequest等方法添加动态或预定义任务。
- 通过
- 事件等待:
WaitForCookOnTheFlyEvents用于同步多进程间的事件完成状态。
- 任务分发:
1.1.3 资源生成与状态跟踪
- 包(Package)生命周期管理
- 动态发现资源:
QueueDiscoveredPackage将新发现的资源加入处理队列。
- 生成资源完成:
EndQueueGeneratedPackages标记生成结束阶段,可能触发后续处理。
- 状态上报:
ReportDemoteToldle和ReportPromoteToSaveComplete通知任务状态变化(如空闲、保存完成),用于进度跟踪。
- 动态发现资源:
等等,此处更详细的信息不再说明。
1.2 CookWorkerRequestsLocal 和 CookWorkerRequestRemote
是 IWorkerRequests 的派生类,上面说的 任务队列管理,多进程协调,资源生成与状态跟踪在这里具体实现。
FCookWorkerRequestsLocal
比基类 IWorkerRequests 多了一个私有成员变量 FExternalRequests

上面各种方法的实现也与这个类相关,如

FCookWorkerRequestsLocal 是单进程 Cook 相关,CookOnTheFly 和 CookByTheBook 通用。
FCookWorkerRequestsRemote
FCookWorkerRequestsRemote 是多进程 Worker 用到的
比基类 IWorkerRequests 多两个私有成员变量 FExternalRequests 和 FCookWorkerClient 以及一些私有函数,主要是报错的 log 方法

1.3 ExternalRequests
里面有成员变量 FFilePlatformRequest ,因此先讲它
1.3.1 FilePlatformRequest
结构体 FFilePlatformRequest 是 UE CookSystem 中用于表示 单个文件(资源)的 Cook 请求 的数据结构。
封装了 需要 Cook 的文件名、目标平台、回调函数等信息,是调度器 (Scheduler) 处理外部请求的核心单元。
且不使用被 scheluler 内部使用的 FPackageData。
1. 核心功能与设计目的
-
封装 Cook 请求的元数据
描述哪个文件需要被 Cook,针对哪些目标平台,以及请求处理完成的回调。
-
支持多平台 Cook
允许一个文件同时为多个目标平台(如 Windows, PS5, XBox 等)生成资源。
-
异步任务管理
通过回调机制(
FCompletionCallback) 通知请求处理结果(成功、失败、取消等)。 -
动态调整请求属性
支持运行时修改目标平台、紧急状态(Urgent)等参数。
2. 主要成员解析
-
关键数据成员
成员 类型 作用 FilenameFName需要Cook的文件名(如 /Game/AssetName),使用优化哈希性能PlatformsTArray<const ITargetPlatform*>目标平台列表(如 Windows, Android),决定生成哪些平台的资源 CompletionCallbackFCompletionCallback请求完成时的回调函数,用于通知调用方结果。 InstigatorFInstigator请求的发起者信息(如用户操作、系统事件),用于调试和日志追踪。 bUrgentbool紧急标志,若为 true则请求会被优先处理。重点的说一下:
-
FCompletionCallback![image-20250414115412609]()
当请求的 package 完成 cook 的时候的回调函数
-
FInstigator- 用于追踪资源 (Package) 被发现并加入 cook 队列的原因和来源。(后面有具体讲解)。
-
-
构造函数
-
多平台支持
提供多个构造函数重载,支持从多个平台(
InPlatform) 或平台数组(InPlatforms) 初始化请求。 -
移动语义优化
使用
TArray<...>&&和FInstigator&&移动语义减少数据拷贝开销(如大数组传递时)。
-
-
成员函数
函数 作用 SetUrgent/IsUrgent设置或查询请求的紧急状态 AddPlatform/RemovePlatform动态增删目标平台 RemapTargetPlatforms替换目标平台引用(用于热重载或配置更新) IsValid验证请求是否有效(如文件名非空、至少有一个平台) ToString生成可读字符串
3. 设计亮点
-
使用
FName而非FString存储文件名,优化哈希比较性能关于为什么使用 FName 能优化性能,主要是
FName是存储在全局表中的,更多具体细节,见 《UE FName.md》 -
移动语义减少数据拷贝
![image-20250414111904261]()
1.3.2 FInstigator
FFilePlatformRequest 中的构造函数中用到了 FInstigator ,也就是记录了 策动者
- instigator
- n. 策动者;煽动者;教唆者
- instigate v. 使(正式)开始,使发生;鼓动

FInstigator 结构体用于 追踪资源(Package)被发现并加入 Cook 队列的原因和来源。它结合 EInstigator 枚举的类别(Category)和可选的引用者(Referencer),记录资源被 Cook 的上下文信息。
核心作用
- 记录资源被发现的来源
Category: 类型EInstigator: 表示资源被发现的 “原因” 或 “触发途径”。例如:StartupPackage: 引擎启动时必须加载的核心资源。CommandLinePackage: 通过命令行参数显式指定的资源。Dependency: 因其它资源依赖而被间接发现。
Referencer: 类型FName: 可选的引用者名称,用于标识触发该资源发现的直接源头(如依赖他的父资源路径)。
- 调试与 log
- 当资源 cook 出现问题时,通过
FInstigator::ToString()生成的字符串可以快速定位触发该资源 cook 的代码路径或外部输入。 - 例如:若资源因资源 B 的依赖被 cook,log 会显示类似
Dependency(Referencer=/Game/B)。
- 当资源 cook 出现问题时,通过
- 依赖链追踪
- 在复杂资源依赖场景中,通过
Referencer字段可以构建依赖链,帮助解决循环依赖或优化不必要的依赖。
- 在复杂资源依赖场景中,通过
- 优先级与调度决策
- 不同
Category可能影响资源处理的优先级。例如:AlwaysCookMap类别的资源可能被优先处理。Unsolicited(未请求的资源)可能需要额外验证。
- 不同
结合 EInstigator 枚举的具体场景
| EInstigator 值 | 场景 |
|---|---|
StartupPackage |
引擎启动时自动加载的核心资源(如默认材质类、基础蓝图类) |
CommandLinePackage |
通过命令行参数 -cookpackage=/Game/Asset 显式指定需要 Cook 的资源。 |
Dependency / HardDependency |
资源因其它资源的硬依赖被引用(如静态引用的材质或网格)。Referencer 记录父资源路径。 |
CookOnTheFly |
动态运行时按需 Cook 触发的资源请求。 |
AssetManagerModifyCook |
资源管理器(AssetManager)在 cook 过程中动态添加的资源(如主资产列表中的条目)。IniMapSection |
IterativeCook |
增量 cook 模式下,仅处理已修改的资源。 |
代码示例
// 1. 因依赖被发现的资源
FInstigator DependencyInstigator(
EInstigator::Dependency,
FName("/Game/Characters/Hero/BP_Hero") // 引用者:副资源路径
);
// 2. 通过命令行指定的资源
FInstigator CommandLineInstigator(EInstigator::CommandLinePackage);
// 3. 动态按需 cook 请求
FInstigator CookOnTheFlyInstigator(EInstigator::CookOnTheFly);
// 输出调试信息
UE_LOG(LogCook, Display, TEXT("Instigator:: %s"), *DependencyInstigator.ToString());
// 输出:Dependency(Referencer=/Game/Characters/Hero/BP_Hero)
设计意义
-
透明化 cook 流程
通过记录每个资源的触发来源,开发者可以清晰地了解哪些代码路径或配置项导致了 package 被 cook,避免黑盒操作。
-
优化性能
分析高频
Category可以针对性优化。例如:若大量资源因SoftDependency被加载,可能需要重构依赖关系。 -
错误隔离
当某个资源 cook 失败时,通过
FInstigator快速定位是配置错误(如IniMapSection)、依赖问题(如Dependency) 还是外部输入问题(如CommandLinePackage)。 -
扩展性
EInstigator枚举通过宏扩展开定义,新增类别只需修改宏,无需改动FInstigator结构体或相关逻辑。
1.2.3 ExternalRequests
FExternalRequests 是 UE 中一个用于 管理外部 Cook 请求 和 回调任务的线程安全容器。以下是其核心功能解析:
1. 核心职责
- 请求管理
- 回调请求 Callbacks: 通过
AddCallback添加的即时任务(如事件响应),调度器会优先按 FIFO 顺序执行。 - Cook 请求 CookRequests: 通过
EnqueueUnique添加的文件处理任务(如打包资源到特定平台),支持 去重合并。同一文件的多次请求会合并为一个,记录所有目标平台。
- 回调请求 Callbacks: 通过
- 线程安全
- 使用
FCriticalSection锁 (类中的成员变量名为RequestLock) 保护内部数据结构(Queue,RequestMap,Callbacks)。 - 通过原子变量
RequestCount提供无锁的请求数量查询(GetNumRequests和HasRequests),用于快速判断是否需要加锁处理。
- 使用
2. 关键操作
-
添加请求
- 回调请求:直接追加到
Callbacks数组,触发事件通知调度器。 - Cook 请求:通过
EnqueueUnique添加时,如果文件已经存在,合并目标平台列表;否则插入队列(支持插队到队首)。
- 回调请求:直接追加到
-
取出请求:
- 优先级策略:回调请求优先于 Cook 请求(
DequeueNextCluster)。 - 批量处理:每次取出全部回调或 Cook 请求,减少锁竞争。
- 优先级策略:回调请求优先于 Cook 请求(
-
平台管理
- 移除平台:
OnRemoveSessionPlatform清理指定平台相关的 Cook 请求。 - 平台重映射:
RemapTargetPlatforms更新请求中的平台指针(如热更新配置)。
- 移除平台:
3. 数据结构
Queue(环形缓冲区TRingBuffer):按顺序保存 cook 请求的文件名(FName),用于 FIFO 处理。RequestMap(哈希表TMap<FName, FFilePlatformRequest>): 以文件名为 key,存储完整的 cook 请求信息(FFilePlatformRequest),包含目标平台列表。Callbacks(回调数组):存储所有待处理的回调任务。
4. 同步机制
- CookRequestEvent 事件
- 调度器在空闲时等待此事件,当新请求加入(如
AddCallback或EnqueueUnique调用)时触发,唤醒 scheduler 处理。
- 调度器在空闲时等待此事件,当新请求加入(如
5. 典型流程
- 添加请求
- 用于调用
AddCallback或EnqueueUnique添加任务,锁内更新数据结构并递增RequestCount。 - 触发
CookRequestEvent通知 Scheduler。
- 用于调用
- 处理请求
- Scheduler 通过
DequeueNextCluster取出任务:先处理所有回调,再处理 cook 请求。 - 批量取出减少锁争用,处理完成后更新
RequestCount。
- Scheduler 通过
- 清理与调试
EmptyRequests和DequeueAll用于取消任务或重置状态。LogAllRequestedFiles输出 log 帮助调试。
更多的细节可以看 《UE ExternalRequests.md》
1.4 FCookWorkerServer
FCookWorkerServer 是 UE 多进程资源 Cook 系统中负责 与单个 CookWorker 进程通信和任务管理 的核心类。
1.4.1 进程间通信管理
- Socket 通信:
- 通过
FSocket与远端FCookWorkerClient建立 TCP 连接,实现双向数据传输。
- 通过
- 消息队列:
- 使用
SendBuffer和ReceiveBuffer管理待发送/接收的数据包,支持异步消息处理。
- 使用
- 即时与队列发送:
SendMessage: 立即发送关键消息(如心跳、终止指令)。AppendMessage: 将非紧急消息(如任务结果)加入队列,通过TickCommunication周期发送。
1.4.2 任务分配与监控
- 任务分发:
- 通过
AppendAssignments将资源烹饪任务FPackageData分配给 CookWorker,并附带依赖信息(ExtraDatas)。
- 通过
- 任务状态跟踪:
- 维护
PackageToAssign(待处理) 和PendingPackages(处理中)列表,确保任务进度可控。
- 维护
- 异常处理:
AbortAssignment:- 主动取消单个任务(如依赖失败)。
AbortAllAssignments:- 强制回收所有任务(如进程崩溃),通过
OutPendingPackages通知 Director 重新分配。
- 强制回收所有任务(如进程崩溃),通过
1.4.3 进程生命周期控制
- 进程启动:
LaunchProcess调用系统 API 启动 CookWorker 子进程,传递命令行参数(如日志路径、ProfileId)。
- 连接管理:
- 处理连接握手(
TryHandleConnectMessage), 超时检测(TickWaitForConnect),维护状态机EConnectStatus。
- 处理连接握手(
1.5 FCookDirector
FCookDirector 是 UE 中用于 多进程 Cook 协调 的核心类,主要职责是管理和协调多个 CookWorker 进程,实现高效的分布式资源处理。
1. 多进程任务分配与负载均衡
1.1 分布式 Cook
将资源 Cook 任务(如材质、贴图等)分配给多个 CookWorker 子进程,利用多核 / 多机资源加速整体流程。
1.2 动态分配策略
- 算法支持:
- 提供
Striped(简单分片) 和CookBurden(基于任务复杂度)两种负载均衡算法,优化资源利用。
- 提供
- 请求图分析:
- 根据资源依赖关系(
RequestGraph) 智能分配任务,减少子进程间的数据争用。
- 根据资源依赖关系(
- 任务回收:
- 通过
RemoveFromWorker和ReassignAbortedPackages处理异常(如进程崩溃),重新分配未完成任务。
- 通过
2. 进程生命周期管理
- 进程启动:
- 生成并配置
CookWorker进程,传递命令行参数、日志路径等(GetLaunchInfo)。
- 生成并配置
- 状态监控:
- 通过心跳机制(
TickHeartbeat) 检测子进程活性,处理超时或僵死。
- 通过心跳机制(
- 优雅关闭:
ShutdownCookSession确保所有子进程完成工作后安全退出,避免资源泄露。
3. 跨进程通信
- 双向通信:
- 消息广播:
BroadcastGeneratorMessage向所有子进程发送全局事件(如资源生成完成)。
- 消息广播:
以下是网络相关的主要组件和机制:
-
通信协议
-
使用
CompactBinaryTCP(在CompactBinaryTCP.h中定义)进行序列化和数据传输。这种协议基于 紧凑二进制格式(Compact Binary,简称 Cb),适合高效传输结构化数据。CompactBinaryTCP 的讲解见
UE5 MPCook Cb.md文档。
-
-
通信模式
FCookDirector作为服务器端,通过监听 socket(WorkerConnectSocket)接受来自CookWorker的连接请求。每个CookWorker是一个客户端,通过 TCP 连接与CookDirector通信。
-
双线程模型:
- SchedulerThread:
- 通常是 UE 的主线程(GameThread),负责任务分配、状态更新等逻辑。
- CommunicateThread:
- 一个专门的线程(通过
FRunnableThread实现),用于处理与CookWorker的网络通信,减轻主线程负担。
- 一个专门的线程(通过
- SchedulerThread:
-
消息类型
- 定义了多种消息类型
FWorkerConnectMessage,FRetractionRequestMessage,FRetractionResultsMessage,FHeartbeatMessage等,用于不同场景的通信,如 连接建立、任务分配、任务撤销、心跳检测等。
- 定义了多种消息类型
4. 关键网络相关功能
4.1 监听 socket 的创建
TryCreateWorkerConnectSocket 负责创建 监听 Socket,用于接受 CookWorker 的连接请求:
bool FCookDirector::TryCreateWorkerConnectSocket()
{
ISocketSubsystem* SocketSybsystem = ISocketSubsystem::Get();
// 创建一个 Stream 式 Socket(NAME_Stream 表示 TCP 流)
WorkerConnectSocket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT("CookDirector"), false);
if (!WorkerConnectSocket) return false;
TSharedPtr<FInternetAddr> LocalAddr = SocketSubsystem->CreateInternetAddr();
// 绑定到本地地址 SetAnyAddress
LocalAddr->SetAnyAddress();
// 绑定到指定的端口 WorkerConnectPort
LocalAddr->SetPort(WorkerConnectPort);
// 绑定
bool bSuccess = WorkerConnectSocket->Bind(*LocalAddr);
if (!bSuccess)
{
Sockets::CloseSocket(WorkerConnectSocket);
WorkerConnectSocket = nullptr;
return false;
}
// 设置监听队列长度为 8,允许最多 8 个未处理的连接请求
bSuccess = WorkerConnectSocket->Listen(8);
if (!bSuccess)
{
Sockets::CloseSocket(WorkerConnectSocket);
WorkerConnectSocket = nullptr;
return false;
}
// 记录连接的 URI(如 hostname:port),用于 CookWorker 连接
WorkerConnectAuthority = FString::Printf(
TEXT("%s:%d"),
*SocketSubsystem->GetLocalHostAddr(*GLog, false).ToString(),
WorkerConnectPort);
return true;
}
4.2 CookWorker 连接管理
4.2.1 PendingConnection 结构体
CookDirector 使用 FPendingConnection 结构体管理尚未完成初始化的 CookWorker 连接:
struct FPendingConnection
{
explicit FPendingConnection(FSocket* InSocket = nullptr)
: Socket(InSocket)
{}
FPendingConnection(FPendingConnection&& Other);
FPendingConnection(const FPendingConnection& Other) = delete;
~FPendingConnection();
FSocket* DetachSocket();
FSocket* Socket = nullptr;
// FReceiveBuffer 详见 CompactBinaryTCP.h
UE::CompactBinaryTCP::FReceiveBuffer Buffer;
};
- 功能:
- 每个
FPendingConnection包含一个FSocket和一个FReceiveBuffer,用于接收来自CookServer的初始消息(通常是FWorkerConnectMessage)。 FCookDirector::TickWorkerConnects函数(在后面会讲到)定期检查 监听 socket,接受新的连接请求,并将新连接添加到PendingConnections列表中。
- 每个
- 连接流程:
CookWorker启动后,向CookDirector的 监听 socket 发起 TCP 连接。CookDirector接受连接后,将 socket 存储在FPendingConnection中,等待CookWorker发送FWorkerConnectMessage以完成身份验证。- 一旦身份验证完成,连接会被转移到对应的
FCookWorkerServer实例中,用于后续通信。
4.2.2 消息类型结构体
FCookDirector 通过消息机制与 CookWorker 进行通信,主要消息类型包括:
-
FWorkerConnectMessage
CookWorker向CookDirector发送,表明自己已经准备好接收配置和任务。
struct FWorkerConnnectMessage : public IMPCollectorMessage { virtual void Write(FCbWriter& Writer) const override; virtual bool TryRead(FCbObjectView Object) override; int32 RemoteIndex = 0; static FGuid MessageType; };IMPCollectorMessage是一个被 IMPCollectors 使用的解析为 C++ 结构体的信息的基类。具体见UE5_MPCook_Cb 与 MPCollector.md。- 包含
RemoteIndex,标识CookWorker的唯一索引。 - 用于初始化连接,
CookDirector收到后会发送FInitialConfigMessage作为响应。
-
FRetractionRequestMessage和FRetractionResultsMessage:-
FRetractionRequestMessage:CookDirector向CookWorker发送,请求撤销部分已经分配的包。
-
FRetractionResultsMessage:CookWorker响应,告知哪些包被撤销。
-
这些消息用于 负载动态均衡,当某个
CookWorker超载时,CookDirector会将任务重新分配给其他空闲的CookWorker。
-
-
FHeartbeatMessage- 用于检测
CookWorker是否存活,防止连接中断。 TickHeartbeat函数定期发送心跳消息,并检查CookWorker的响应。- 如果心跳超时,
CookDirector会将对应CookWorker标记为断开连接,并重新分配其任务。
- 用于检测
消息的序列化和反序列化基于 CompactBinary 格式,通过 FCbWriter 和 FCbObjectView 实现。FMPCollectorServerMessageContext 提供上下文,用于在消息处理时传递相关信息。
4.2.3 CookWorker 连接处理 TickWorkerConnects
TickWorkerConnects 函数负责处理新连接的建立和初始消息的接收,它被 TickCommunication 调用
void FCookDirector::TickWorkerConnects(ECookDirectorThread TickThread)
{
using namespace UE::CompactBinaryTCP;
if (!WorkerConnectSocket)
{
return;
}
bool bReadReady;
while (WorkerConnectSocket->HasPendingConnection(bReadReady) && bReadReady)
{
// Accept 是创建了一个新的 Socket?
FSocket* WorkerSocket = WorkerConnectSocket->Accept(TEXT("Client Connection"));
if (!WorkerSocket)
{
UE_LOG(LogCook, Warning, TEXT("Pending connection failed to create a ClientSocket."));
}
else
{
// 设置非阻塞
WorkerSocket->SetNonBlocking(true);
// PendingConnection 上面讲过了,用来管理尚未完成初始化的连接
// PendingConnections 是一个数组
PendingConnections.Add(FPendingConnection(WorkerSocket));
}
}
// TIterator 是一个模板类, 可以点进去看
for (TArray<FPendingConnection>::TIterator Iter(PendingConnections); Iter; ++Iter)
{
FPendingConnection& Conn = *Iter;
TArray<FMarshalledMessage> Messages;
// ConnectionStatus 有几种状态:Okay, Terminated, FormatError, Failed, Incomplete
EConnectionStatus Status;
// 核心函数 UE::CompactBinaryTCP::TryReadPacket,尝试读包,把数据存到 Conn.Buffer 这个缓存中,返回连接的状态
Status = TryReadPacket(Conn.Socket, Conn.Buffer, Messages);
if (Status != EConnectionStatus::Okay)
{
UE_LOG(LogCook, Warning,
TEXT("Pending connection failed before sending a WorkerPacket: %s"), DescribeStatus(Status));
// RemoveCurrent 是在 Array 中移除当前元素
// 也就是说连接状态不是 Okay 的直接从 PendingConnections 中移除了
Iter.RemoveCurrent();
}
}
}
核心函数:TryReadPacket

这里接收了三个参数 FSocket, FReceiveBuffer 和 TArray<FMarshalledMessage>& Messages (FMarshalledMessage 是封送消息,还没有序列化的消息)。走到了 FCompactBinaryTCPImpl::TryReadPacket 里面,具体看 "CbTCP_Grok.md" 文档
4.3 通信线程 CommunicationThread 的持续处理
4.3.1 通信线程创建
FCookDirector 使用一个独立的通信线程 CommunicationThread 来处理与 CookWorker 的网络通信,减少主线程的阻塞。
void FCookDirector::LaunchCommunicationThread()
{
if (!CommunicationThread && FPlatformProcess::SupportsMultithreading())
{
CommunicationThread = FRunnableThread::Create(&RunnableShunt, TEXT("FCookDirector"), 0, TPri_Normal);
}
}
uint32 FCookDirector::RunCommunicationThread()
{
// constexpr 是编译期确定值,和 const 仅此区别
constexpr float TickPeriod = 1.f;
constexpr float MinSleepTime = 0.001f;
for (;;)
{
double StartTime = FPlatformTime::Seconds();
// 这个函数在下面展开
TickCommunication(ECookDirectorThread::CommunicationThread);
double CurrentTime = FPlatformTime::Seconds();
// 如果通信的这一帧时长小于 1s,等够 1s
float RemainingDuration = StartTime + TickPeriod - CurrentTime;
if (RemainingDuration > .001f)
{
uint32 WaitTimeMilliseconds = static_cast<uint32>(RemainingDuration * 1000);
if (ShutdownEvent->Wait(WaitTimeMilliseconds))
{
break;
}
}
}
return 0;
}
- 功能:
- 通信线程以固定周期
TickPeriod = 1秒调用TickCommunication
- 通信线程以固定周期
4.3.2 TickCommunication
TickCommunication 是网络通信的核心函数,负责处理所有 CookWorker 的消息:
void FCookDirector::TickCommunication(ECookDirectorThread TickThread)
{
bool bHasShutdownWorkers = false;
TickWorkerConnects(TickThread);
}
1.6 ECookAction
enum class ECookAction
{
Done, // The cook is complete; no requests remain in any non-idle state
Request, // Process the RequestQueue
Load, // Process the LoadQueue
LoadLimited, // Process the LoadQueue, stopping when loadqueuelength reaches the desired population level
Save, // Process the SaveQueue
SaveLimited, // Process the SaveQueue, stopping when savequeuelength reaches the desired population level
Poll, // Execute pollables which have exceeded their period
WaitForAsync, // Sleep for a time slice while we wait for async tasks to complete
YieldTick, // Progress is blocked by an async result. Temporarily exit TickMainCookLoop.
};
记录 Cook Action 状态的 Enum
FTickStackData
// 关于 Cooker 的当前帧的临时生命周期数据
struct FTickStackData
{
double LoopStartTime = 0.;
// 掩码,和 ECookOnTheSideResult 做逻辑运算
uint32 ResultFlags = 0;
FCookTimer Timer;
ECookTickFlags TickFlags;
bool bCookComplete = false;
bool bCookCancelled = false;
explicit FTickStackData(float TimeSlice, ECookTickFlags InTickFlags)
:Timer(TimeSlice), TickFlags(InTickFlags)
{}
};



浙公网安备 33010602011771号