首先寻找程序的入口。

从解决方案筛查代码覆盖范围太大,我查了一下网上已有的文件目录分析,
把代码查询范围缩小到Engine/Source

├── Engine
│ ├── Binaries 二进制可执行文件文件夹
│ │ ├── DotNET 工程 (Mac下是Mac文件夹 编辑器或者崩溃报告器)
│ │ └── ThirdParty arm,mono,penal,oculus等的可执行文件
│ ├── Build 编译时各个平台的集成环境 配置或者依赖
│ │ ├── Android 安卓平台
│ │ ├── BatchFiles 编译的批处理文件bat sh
│ │ ├── BuildFarm 平台兼容perl
│ │ ├── Graph 图表
│ │ ├── HTML5 html5 json2.js
│ │ ├── IOS ios
│ │ ├── Mac mac
│ │ └── TVOS 苹果电视
│ ├── Config 各个平台的参数
│ │ ├── Android
│ │ ├── HTML5
│ │ ├── IOS
│ │ ├── Linux
│ │ ├── Localization 本地化配置文件
│ │ ├── Mac
│ │ └── Windows
│ ├── Documentation 文档
│ │ ├── Extras 额外的东西
│ │ └── Source
│ ├── Extras 额外的工具
│ │ ├── AndroidWorks
│ │ ├── LLDBDataFormatters
│ │ ├── MayaVelocityGridExporter
│ │ ├── Maya_AnimationRiggingTools
│ │ ├── ThirdPartyNotUE
│ │ ├── VisualStudioDebugging
│ │ └── VisualStudioSnippets
│ ├── Plugins 集成的插件
│ │ ├── 2D 2d游戏开发的东西(2d的精灵,地图块等)
│ │ ├── Blendables 混合(光传播)
│ │ ├── Developer 开发方面的(代码访问)
│ │ ├── Editor 编辑器(公司的调查,mac图像转换 插件查看器 speedtree 查找)
│ │ ├── Experimental 一些实验性的插件
│ │ ├── Media 多媒体(视频,音效)
│ │ ├── Messaging 通信(UDP)
│ │ ├── MovieScene 影视场景(levelsequence matinee)
│ │ ├── NetcodeUnitTest 网络代码单元测试
│ │ ├── Runtime 各种运算时环境(移动平台,vr,movieplayer)
│ │ ├── ScriptPlugin 脚本(lua脚本支持)
│ │ └── Slate
│ ├── Programs 依赖的一些程序
│ │ ├── CrashReportClient
│ │ ├── ShaderCompileWorker
│ │ ├── UnrealFrontend
│ │ ├── UnrealGameSync
│ │ ├── UnrealHeaderTool
│ │ └── UnrealLightmass
│ ├── Shaders 着色器 (hlsl glsl usf:ue4引擎跨平台shader)
│ │ └── StandaloneRenderer 独立的着色器 (hlsl glsl )
│ └── Source 源码
│ ├── Developer 开发者用的源码
│ ├── Editor 编辑器UI源码
│ ├── Programs ue4的程序源码
│ ├── Runtime 引擎核心源码
│ └── ThirdParty 第三方库源码
├── Samples 例子(空)
│ ├── MobileStarterContent 编辑器移动端第一次打开显示的东西
│ │ ├── Build
│ │ └── Config
│ └── StarterContent 编辑器第一次打开的显示的东西
│ ├── Build
│ └── Config
└── Templates 游戏模板
├── FP_FirstPerson 第一人称游戏模板 c++模板
│ ├── Config
│ └── Source
├── FP_FirstPersonBP 第一人称游戏 蓝图模板
│ └── Config
├── TP_2DSideScroller 2D滚屏游戏 c++模板
│ ├── Config
│ └── Source
├── TP_2DSideScrollerBP 2D滚屏游戏 蓝图模板
│ └── Config
├── TP_FirstPerson 第一人称游戏 c++模板
│ ├── Config
│ └── Source
├── TP_FirstPersonBP 第一人称游戏 蓝图模板
│ └── Config
├── TP_Flying 飞行类游戏 c++模板
│ ├── Config
│ └── Source
├── TP_FlyingBP 飞行类游戏 蓝图模板 蓝图模板
│ └── Config
├── TP_Puzzle 小游戏 消除 解密游戏 c++模板
│ ├── Config
│ └── Source
├── TP_PuzzleBP 小游戏 消除 解密游戏 蓝图模板
│ └── Config
├── TP_Rolling 滚动游戏 c++模板
│ ├── Config
│ └── Source
├── TP_RollingBP 滚动游戏 蓝图模板
│ └── Config
├── TP_SideScroller 横屏滚屏游戏 c++模板
│ ├── Config
│ └── Source
├── TP_SideScrollerBP 横屏滚屏游戏 蓝图模板
│ └── Config
├── TP_ThirdPerson 第三人称游戏 c++模板
│ ├── Config
│ └── Source
├── TP_ThirdPersonBP 第三人称游戏 蓝图模板
│ └── Config
├── TP_TopDown 上下游戏 c++模板
│ ├── Config
│ └── Source
├── TP_TopDownBP 上下游戏 蓝图模板
│ └── Config
├── TP_TwinStick 双摇杆游戏 c++模板
│ ├── Config
│ └── Source
├── TP_TwinStickBP 双摇杆游戏 蓝图模板
│ └── Config
├── TP_Vehicle 运输类游戏 赛车 赛艇 c++模板
│ ├── Config
│ └── Source
├── TP_VehicleAdv 高级运输类 游戏 c++模板
│ ├── Config
│ └── Source
├── TP_VehicleAdvBP 高级运输类 游戏 蓝图模板
│ └── Config
├── TP_VehicleBP 高级运输类 游戏 蓝图模板
│ └── Config
└── TemplateResources 模板游戏资源
├── High 高材质
└── Standard 一般材质
————————————————
版权声明:本文为CSDN博主「柏白」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn/frabbit_on_fire/article/details/51899044

搜了一下还是有很多结果,再缩小范围
把代码查询范围缩小到Engine/Source/Runtime

有很多不同的结果,这是引擎为了支持不同平台,采用的间接方式。

然而,windows的main叫 winmain。

找到launchWindows.cpp

分析文件顺便讲解一下C++语法(C++17)

该文件第一行是著作权信息
第三行是UE5最核心的头文件CoreMinimal.h,把所有UE5必要的声明都包含在里面了。

然后我们遇到了一个条件宏

载入的头文件定义的是一些DEBUG需要用到的参数


接着我们遇到了一个宏定义的结构体,里面用到了合并操作符

组合成的新结构体名FLogCategory##CategoryNameFLogCategoryLogLaunchWindows


inline __inline __forceinline说明符指示编译器将函数体的副本插入到调用函数的每个位置。
inline__inline 仅当编译器的成本收益分析显示有价值时,才会进行插入:不插入而形成独立函数,一共有两种情况

  • 递归函数。
  • 在翻译单元(.obj文件,编译未链接)中的其他位置通过指针引用的函数。

__forceinline 在任何情况下都会插入
从上面的情况反向思考,__forceinline的存在杜绝了内联函数递归和其他文件通过指针引用内联函数的情况。

然后通读一下这个宏的注释

只能在该单个文件中访问,是因为使用了__forceinline关键字

主循环

mainloop在 FEngineLoop的类中实现的。
第一步在Launch.cpp 实例化了FEngineLoop类,然后进行预初始化阶段

接下来如果是从UE编辑器编译的,需要额外判断是否在编辑器中,条件处理一下是启动编辑器初始化还是启动引擎初始化。
游戏情况下是直接启动引擎初始化。

PreInit阶段

  1. 加载低级引擎模块
  2. 加载用户早期加载项目和插件的源模块
  3. 加载大量高级引擎模块
  4. 默认的加载项目和插件模块的地方 (通常是用户C++代码第一次被注入的地方)

你的游戏模块是在所有基本引擎功能已经加载和初始化的情况下加载的。
但都在任何实际的游戏状态创建之前。

模块被加载的时候发生的事情:

  1. 引擎注册模块中定义的所有UObject类
  2. 还为每个类构造了一个CDO class default object 原型模式,牺牲空间换时间
  3. CDO是处于默认状态的类的记录,它作为进一步继承的原型。
  4. 如果定义了一个自定义Actor类型或自定义游戏模式或任何在前面声明了UCLASS的东西,引擎循环分配这个类的默认实例,然后运行它的构造函数。将父类的CDO作为模板传递进去,这就是构造函数不应该包含任何游戏玩法相关代码的原因之一。实际上只是为了建立类的通用细节,而不是为了修改该类的任何特定实例。
  5. 注册完所有的类后,引擎会调用模块的StartupModule函数,该函数与ShutdownModule匹配。让你有机会处理任何需要绑定到模块生命周期的初始化。
  6. 此时引擎循环已经加载了所有需要的引擎、项目和插件模块。它从这些模块中注册类,并初始化所有需要到位的低级系统。这完成了PreInit阶段,所以我们可以进入Init函数。

FEngineLoop::PreInit -> FCommandLine::BuildFromArgV ->

Init阶段

稍微简化一下,可以看到把事情交给了一个叫UEngine的类。

命名规范:

  1. engine 小写的e是我们正在启动的可执行文件,由不是我们自己编写的代码组成的可执行文件。
  • the Engine,UE_4.25/Engine
  • 包含一个名为Engine的源模块,UE_4.25/Engine/Source/Runtime/Engine;
  • 模块中有个名为Engine.h的头文件,UE_4.25/Engine/Source/Runtime/Engine/Classes/Engine/Engine.h;
  • 在该头文件中定义了一个名为UEngine的类,该类在UEditorEngine和UGameEngine都有实现;
  • 在游戏的初始化阶段,FEngineLoop检查引擎配置文件以确定应该使用哪个GameEngine类,然后它创建该类的一个实例并将其作为全局UEngine实例。
  • 可通过在Engine/Engine.h中声明的全局变量GEngine访问。
  1. 一旦引擎被创建,它就会被初始化。
  2. 完成后,引擎循环,触发全局委托以指示引擎现已初始化。
  3. 然后它加载已配置为延迟加载的任何项目或插件模块。
  4. 最后Engine启动,初始化完成。

FCoreDelegates::OnPostEngineInit.Broadcast();

Engine类作用

Engine类实际上是做什么的呢?

  • 它做了很多事情,但它主要责任在于这组巨大的函数,包括Browse和LoadMap
  • 我们已经了解了进程如何启动并初始化所有引擎系统,但是为了进入真正的游戏并开始玩,我们必须加载到地图中。
  • 正是UEngine类为我们实现了这一点。引擎能够浏览到一个URL,该URL可以表示要连接的服务器地址作为客户端,或要在本地加载的地图的名称。
    URL也可以添加参数,
    127.0.0.1?Name=Jimmie
    SomeMap?Listen

当你在项目的DefaultEngine.ini文件中设置默认地图时,你是在告诉引擎在启动时自动浏览到该地图。
当然,在开发版本中,你也可以重写默认的地图,通过命令行提供URL,你还可以使用open命令浏览到在游戏过程中不同的服务器或地图。

更多推荐

【入口】UE源码 gameloop