简介: 前文算是捋顺了从引擎启动到打开 ProjectBrowser 的一个流程,今天就捋一下在 ProjectBrowser 面板内点击 OpenProject 后,如果开启一个项目。
ProjectBrowser 的界面逻辑索然无味,我们就从点击 Open 按钮后的打开事件开始一步一步往后推
流程格式
由于这个流程会在不同文件之间来回跳转,所以我想了一个格式,用来让跳转更清晰
流程标号. 文件名: 文件内的方法调用及主要流程
如果方法内的流程太长,我会使用 * 将主要步骤大致排列出来
开始捋
- SprojectBrowser.cpp 通过内部绑定到 UI 打开按钮上的 OpenProject 方法开始启动选择的项目。
- 获取将要打开的文件的标识
- 检查要打开的项目是不是当前已经打开的项目
- 判断是否是一个 code 类型项目,是的话就使用 IDE 进行代码的编译,这期间出错就会直接返回
- 检查版本是否与引擎匹配,是否升级,是否使用copy的方式打开等等常规操作
- 最后调用 GameProjectUtils::OpenProject 方法打开指定的项目
GameProjectUtils.cpp OpenProject 方法内主要就是检查项目文件各种是否合格,从命名到后缀到字符,以及文件是否存在,有一条不过就会返回,检查合格后会调用 FUnrealEdMisc::Get().SwitchProject
我发现它是切换项目来实现打开项目的UnrealEdMisc.cpp: SwitchProject 比较有意思,它也没有直接的去打开新工程,而是通过 SetPendingProjectName 方法保存要打开的工程名称,然后向 GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME")); 添加一个 DeferredCommands
DeferredCommands 类似于一个 commandList,这里面的指令会在每帧的最后执行
- 首先会判断是否还在构建的灯光,如果是则会直接返回
- 判断是否需要弹警告,例如当前工程有东西没有报错,是否继续切换,是的话就继续执行,不是的话就会在后面跳过执行切换逻辑
- 向 DeferredCommands 添加 CLOSE_SLATE_MAINFRAME 指令
EditorServer.cpp 内的 UEditorEngine::Exec_Editor 会处理上方的 CLOSE_SLATE_MAINFRAME 指令,它内部就是 获取 IMainFrameModule 然后调用他的 RequestCloseEditor
MainFrameModule.h 这个 RequestCloseEditor 函数是直接写在 .h 文件里的,它的内部会调用 FMainFrameHandler 的ShutDownEditor
MainFrameHandler.cpp 它的内部就是调用各模块的保存,停止,关闭
- 主要处理了 GUnrealEd、GEditor、RootWindow、GlobalTabManager
- 最后使用 GEngine->DeferredCommands.Add(TEXT("QUIT_EDITOR")); 传递 QUIT_EDITOR 退出 Editor 的指令
EditorServer.cpp 获取到 QUIT_EDITOR 命令后,调用 CloseEditor 方法
UnrealEdEngine.cpp UUnrealEdEngine类继承自 UEditorEngine 上面的 CloseEditor 的声明就来自于 UEditorEngine ,所以我们可能无法直接调到 UnrealEdEngine 里的具体实现。至少我没找到直接跳到的方法,有方法的小伙伴可以给我留言哦
这里主要是关闭了 PlayLevel 的一些东西
- EndPlayMap();
- EndPlayOnLocalPc();
- RequestEngineExit(TEXT("UUnrealEdEngine::CloseEditor()"));// 尽快关闭引擎
CoreGlobals.cpp RequestEngineExit 方法内设置 GIsRequestingExit = true; 为 true ,用于退出
Launch.cpp 的 GuardedMain 方法内的 Tick 循环部分使用了 !IsEngineExitRequested() 来作为循环终止条件
- IsEngineExitRequested() 内返回的就是我们上一步看到的设置的 GIsRequestingExit 的值,这里已经为 true,所以退出了 Tick 循环体
- Editor 模式下执行到 EditorExit(); 方法
UnrealEdGlobals.cpp 内的 EditorExit() 方法内主要就是保存配置,保存目录,处理剩余的线程,然后调用 FUnrealEdMisc::Get().OnExit();
UnrealEdMisc.cpp 这里的 OnExit 是最终的退出函数,真难找啊。主要还是在处理一些注销,关闭,解除绑定和清理的工作。
-
在最后的末尾阶段,用到了我们在第 3 步设置的 PendingProjName。
如果 PendingProjName 有效,则会拉起新的工程。这里会判断如果是已经绑定了 Restart,这走Restart的流程,没有的话 则重新生成编辑器实例bool bSuccess = false; if (FEditorDelegates::OnRestartRequested.IsBound()) { bSuccess = FEditorDelegates::OnRestartRequested.Execute(PendingProjName); } else { bSuccess = SpawnEditorInstance(PendingProjName); }
如果没有 success 则会清理 ClearPendingProjectName 直接返回
SpawnEditorInstance 会使用 FPlatformProcess::CreateProc 的方法重新打开带有名称的项目
到此结束 因为在最后使用 cmd 开启项目时,已经传入了项目名称,所以是会直接打开项目,就没有 ProjectBrowser 了
终于算是正常启动项目了,接下来可以正式看拉起项目的步骤了,就是 preinit、init、tick、exit 那些了