首发:
Unreal SourceControl 的执行流程、源码原理和扩展方法
研究目的
- 本文以 Perforce 为例,从执行流程和源码角度,对 Unreal 中 的 SourceControl 源码原理等做了分析说明,希望本文对想了解 Unreal 的 SourceControl 的原理或想对其进行优化和扩展的同学有所帮助。
- 本研究最初的目的,是希望能扩展 UE4 中 P4 的 SourceControl 菜单,加个 unlock 功能,以便所有人都能方便快捷地处理异常状态(如 orphaned 、 unknown)下的文件锁。
SourceControl 源码原理
执行流程
- FPerforceSourceControlModule 在 StartupModule 的时候会注册各种操作 Worker ,如 FPerforceRevertWorker。
- 在 FAssetFileContextMenu 的 FillSourceControlSubMenu 函数中注册了各种 SourceControl 的各种操作。如在能对选中的资源或目录执行 Revert 时(CanExecuteSCCRevert),会添加 Revert 菜单。
- 点击菜单里的 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 操作
执行流程图
扩展方法
需求说明
- 当 SourceControl 开启时,在 ContentBrowser 中选中资源或文件夹后,SourceControl 中会显示可执行的操作列表。
- 现在这些操作列表中添加一个 unlock 操作,当文件状态为 orphaned 时可执行此操作,表示将 orphaned 的文件 unlock 。
扩展步骤
- “数据结构”准备
- 参考 FRevert 在 SourceControlOperations.h 中添加 unlock 这种的 FSourceControlOperation ,名字可叫做 FUnlock
* 参考 FPerforceRevertWorker ,在 PerforceSourceControlOperations.h 中添加一个 unlock worker ,名字可叫 FPerforceUnlockWorker 。
- 注册
- 在 FPerforceSourceControlModule::StartupModule 中注册 unlock worker,如 PerforceSourceControlProvider.RegisterWorker( "Unlock", FGetPerforceSourceControlWorker::CreateStatic( &CreateWorker
) );
- 参考 Revert 在 AssetFileContextMenu 的 FillSourceControlSubMenu 函数中注册 unlock 菜单。
- UI交互实现
- 参考 CanExecuteSCCRevert 添加 unlock 菜单的可否执行判断函数 FAssetFileContextMenu::CanExecuteSCCUnlock,注意 AssetFileContextMenu.h 中也要添加对应的函数声明。
- 参考 bCanExecuteSCCRevert 添加 bCanExecuteSCCUnlock 变量并添加到对应的代码如 CanExecuteSCCUnlock 中
- 参考 ExecuteSCCRevert 添加 unlock 菜单的执行函数 FAssetFileContextMenu::ExecuteSCCUnlock,注意 AssetFileContextMenu.h 中也要添加对应的函数声明。
- 参考 SSourceControlRevert.cpp 添加 SSourceControlUnlock.cpp,并让 ExecuteSCCUnlock 调用 FSourceControlWindows::PromptForUnlock
- “是否(可否)执行此操作”的实现
- 在 PerforceSourceControlState.h 的 EPerforceState 中添加 Orphaned
- 在 ISourceControlState.h 中添加 IsOrphaned
- 可在 PerforceSourceControlOperations.cpp 的 ParseUpdateStatusResults 中写逻辑检测 Orphaned 状态
- 参考 ISourceControlState.h 中的 CanRevert 添加 CanUnlock 函数,并在所有的 SourceControl 子类中实现相关逻辑(除 FPerforceSourceControlState 外,全部return false 即可)
- 实现 FPerforceSourceControlState 的 CanUnlock 中的逻辑,如此处直接返回 IsOrphaned 等
- 实现具体的 SourceControl 操作
- 在 PerforceSourceControlOperations.cpp 的 FPerforceUnlockWorker::Execute 中写 unlock 的具体操作。
可能的改动
可能的优化
- 关于 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
Helix Core Command-Line (P4) Reference (2022.1) - P4 Unlock
**声明:**本文来自公众号:GameDevLearning,转载请附上原文链接及本声明。