fwalker 发表于 2022-7-15 16:39

Unreal SourceControl 的执行流程、源码原理和扩展方法

首发:

研究目的


[*]本文以 Perforce 为例,从执行流程和源码角度,对 Unreal 中 的 SourceControl 源码原理等做了分析说明,希望本文对想了解 Unreal 的 SourceControl 的原理或想对其进行优化和扩展的同学有所帮助。
[*]本研究最初的目的,是希望能扩展 UE4 中 P4 的 SourceControl 菜单,加个 unlock 功能,以便所有人都能方便快捷地处理异常状态(如 orphaned 、 unknown)下的文件锁。
SourceControl 源码原理

执行流程


[*]FPerforceSourceControlModule 在 StartupModule 的时候会注册各种操作 Worker ,如 FPerforceRevertWorker。

http://pic4.zhimg.com/v2-56541ccf716865fcda11934043f16947_r.jpg


[*]在 FAssetFileContextMenu 的 FillSourceControlSubMenu 函数中注册了各种 SourceControl 的各种操作。如在能对选中的资源或目录执行 Revert 时(CanExecuteSCCRevert),会添加 Revert 菜单。

http://pic2.zhimg.com/v2-26a8f4cb3fd168ac3e4ff996c70eac01_r.jpg


[*]点击菜单里的 Revert 时调用 FAssetFileContextMenu 的 ExecuteSCCRevert ,其中会执行对应的逻辑。如对于 Revert ,会打开一个文件列表,让选择要还原的资源,见:FSourceControlWindows::PromptForRevert(PackageNames) ;
[*]确定执行相关操作时,调用对应 SourceControlProvider 的对应操作(继承自 FSourceControlOperationBase ),见:SourceControlProvider.Execute(ISourceControlOperation::Create
(), RevertPackageFilenames); 实际上调用的是 FPerforceSourceControlProvider::Execute
[*]Execute 根据 Operation 的名字从 FPerforceSourceControlProvider::CreateWorker 中获取对应的 Work 。所有 Work 都保存在 WorkersMap 中 ,在模块开始的时候已经通过 FPerforceSourceControlProvider::RegisterWorker 注册好了。见:FPerforceSourceControlModule 在 StartupModule 。
[*]Execute 根据 InConcurrency 决定采用同步还是异步的方式来执行相关操作,底层实际都是调用的 FPerforceSourceControlProvider::IssueCommand,内部会调用 FPerforceSourceControlCommand::DoWork ,其内又调用 IPerforceSourceControlWorker 的 Execute 。
[*]各 IPerforceSourceControlWorker (如 FPerforceRevertWorker )继承于 IPerforceSourceControlWorker ,override Execute 方法,用于执行具体的 SourceControl 操作。如 FPerforceRevertWorker 的 Execute 中会调用 FPerforceConnection 的 RunCommand 来执行特定的 revert 操作
执行流程图



http://pic4.zhimg.com/v2-92da747df5254ac161d0bcc21cb62227_r.jpg

扩展方法

需求说明


[*]当 SourceControl 开启时,在 ContentBrowser 中选中资源或文件夹后,SourceControl 中会显示可执行的操作列表。
[*]现在这些操作列表中添加一个 unlock 操作,当文件状态为 orphaned 时可执行此操作,表示将 orphaned 的文件 unlock 。
扩展步骤


[*]“数据结构”准备


[*]参考 FRevert 在 SourceControlOperations.h 中添加 unlock 这种的 FSourceControlOperation ,名字可叫做 FUnlock


http://pic2.zhimg.com/v2-ed71a0f6a49c847c70359956af21e64d_r.jpg

* 参考 FPerforceRevertWorker ,在 PerforceSourceControlOperations.h 中添加一个 unlock worker ,名字可叫 FPerforceUnlockWorker 。

http://pic3.zhimg.com/v2-45468b84209bc98195f799ec76acd03a_r.jpg


[*]注册


[*]在 FPerforceSourceControlModule::StartupModule 中注册 unlock worker,如 PerforceSourceControlProvider.RegisterWorker( "Unlock", FGetPerforceSourceControlWorker::CreateStatic( &CreateWorker
) );


http://pic3.zhimg.com/v2-78a1de9d66d0f8939cae1fa866e1ed56_r.jpg


[*]参考 Revert 在 AssetFileContextMenu 的 FillSourceControlSubMenu 函数中注册 unlock 菜单。

http://pic3.zhimg.com/v2-c3528154c02409ab1f188dd2c45aa9ae_r.jpg


[*]UI交互实现
[*]参考 CanExecuteSCCRevert 添加 unlock 菜单的可否执行判断函数 FAssetFileContextMenu::CanExecuteSCCUnlock,注意 AssetFileContextMenu.h 中也要添加对应的函数声明。
[*]参考 bCanExecuteSCCRevert 添加 bCanExecuteSCCUnlock 变量并添加到对应的代码如 CanExecuteSCCUnlock 中
[*]参考 ExecuteSCCRevert 添加 unlock 菜单的执行函数 FAssetFileContextMenu::ExecuteSCCUnlock,注意 AssetFileContextMenu.h 中也要添加对应的函数声明。
[*]参考 SSourceControlRevert.cpp 添加 SSourceControlUnlock.cpp,并让 ExecuteSCCUnlock 调用 FSourceControlWindows::PromptForUnlock


http://pic2.zhimg.com/v2-254cbf418a7fc5f79a4d3e2d95a9ecfd_r.jpg


[*]“是否(可否)执行此操作”的实现
[*]在 PerforceSourceControlState.h 的 EPerforceState 中添加 Orphaned


http://pic2.zhimg.com/v2-58d2936258def14513b899fc002364b9_r.jpg


[*]在 ISourceControlState.h 中添加 IsOrphaned


http://pic1.zhimg.com/v2-19f15226a4d9b1186e52b7f4e45b1a10_r.jpg


[*]可在 PerforceSourceControlOperations.cpp 的 ParseUpdateStatusResults 中写逻辑检测 Orphaned 状态
[*]参考 ISourceControlState.h 中的 CanRevert 添加 CanUnlock 函数,并在所有的 SourceControl 子类中实现相关逻辑(除 FPerforceSourceControlState 外,全部return false 即可)
[*]实现 FPerforceSourceControlState 的 CanUnlock 中的逻辑,如此处直接返回 IsOrphaned 等


http://pic2.zhimg.com/v2-d9426ee34ab5863eebce161e2d640a95_r.jpg


[*]实现具体的 SourceControl 操作


[*]在 PerforceSourceControlOperations.cpp 的 FPerforceUnlockWorker::Execute 中写 unlock 的具体操作。


http://pic1.zhimg.com/v2-805780cf01493d9adb5a1d1c9229b4ac_r.jpg

可能的改动



http://pic3.zhimg.com/v2-1ca38ea11dd935805d5b09a5ce8924ee_r.jpg

可能的优化


[*]关于 SourceCountrol 的扩展方式

[*]为避免引擎改动过大,针对特定需求,只处理特定 SourceCountrol 的特定操作,如只给 P4 添加 unlock 操作,其它 SourceCountrol 不重载也不实现相关逻辑。
[*]基于插件自定义编辑器扩展菜单来扩展 SourceCountrol 操作,理论上完全解耦,且扩展和复用方便。

[*]关于 SourceCountrol 对应操作的实现方式

[*]调用 SourceCountrol 或 P4 的底层API执行对应操作。
[*]调用批处理执行 SourceCountrol 或 P4 操作。

总结


[*]SourceControl 总体上代码的逻辑结构清晰,在尊重现有的代码结构的基础上,要修改或扩展还是不难的,参考现有的功能复制粘贴即可。
[*]感觉 SourceControl 的逻辑跟引擎代码的耦合性相当高,如果想扩展 SourceControl 的功能(如想给 SourceControl 菜单加一个类似 Revert 的 Unlock 功能),可能要改动的引擎代码会很多(见图),尤其是如果这个功能希望所有 SourceControl 软件都适用时。所以如果想扩展 Unreal 的 SourceControl 请自行权衡。
参考链接

Helix Core Command-Line (P4) Reference
https://www.perforce.com/manuals/cmdref/Content/CmdRef/Home-cmdref.html
Helix Core Command-Line (P4) Reference (2022.1) - P4 Unlock
https://www.perforce.com/manuals/cmdref/Content/CmdRef/p4_unlock.html#p4_unlock
Exclusive File Locking
https://p1community.force.com/Community2/s/article/3114
页: [1]
查看完整版本: Unreal SourceControl 的执行流程、源码原理和扩展方法