UE5的引擎初始化流程

news2025/1/23 10:30:43

UE5的引擎初始化流程

首先跟着UE的官方文档[1]获取到UE的源代码,然后在参考GitHub上repo的readme,将UE引擎从源码build出来。以Windows平台为例,先找到引擎的入口函数:

int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ char* pCmdLine, _In_ int32 nCmdShow)
{
	int32 Result = LaunchWindowsStartup(hInInstance, hPrevInstance, pCmdLine, nCmdShow, nullptr);
	LaunchWindowsShutdown();
	return Result;
}

可以看到入口函数很简单,就分为startup和shutdown两部分,那么想必引擎的主循环是在这个startup里。startup函数主要负责初始化各种调用环境,解析命令行参数,调用真正的main函数:

LAUNCH_API int32 LaunchWindowsStartup( HINSTANCE hInInstance, HINSTANCE hPrevInstance, char*, int32 nCmdShow, const TCHAR* CmdLine )
{
	// Setup common Windows settings
	SetupWindowsEnvironment();

	int32 ErrorLevel			= 0;
	hInstance				= hInInstance;

	if (!CmdLine)
	{
		CmdLine = ::GetCommandLineW();

		// Attempt to process the command-line arguments using the standard Windows implementation
		// (This ensures behavior parity with other platforms where argc and argv are used.)
		if ( ProcessCommandLine() )
		{
			CmdLine = *GSavedCommandLine;
		}
	}

    ErrorLevel = GuardedMain( CmdLine );

	return ErrorLevel;
}

简化后的main函数如下:

int32 GuardedMain( const TCHAR* CmdLine )
{
    // Super early init code. DO NOT MOVE THIS ANYWHERE ELSE!
	FCoreDelegates::GetPreMainInitDelegate().Broadcast();

	// make sure GEngineLoop::Exit() is always called.
	struct EngineLoopCleanupGuard 
	{ 
		~EngineLoopCleanupGuard()
		{
			// Don't shut down the engine on scope exit when we are running embedded
			// because the outer application will take care of that.
			if (!GUELibraryOverrideSettings.bIsEmbedded)
			{
				EngineExit();
			}
		}
	} CleanupGuard;

	int32 ErrorLevel = EnginePreInit( CmdLine );

	// exit if PreInit failed.
	if ( ErrorLevel != 0 || IsEngineExitRequested() )
	{
		return ErrorLevel;
	}

#if WITH_EDITOR
    if (GIsEditor)
    {
        ErrorLevel = EditorInit(GEngineLoop);
    }
    else
#endif
    {
        ErrorLevel = EngineInit();
    }

	// Don't tick if we're running an embedded engine - we rely on the outer
	// application ticking us instead.
	if (!GUELibraryOverrideSettings.bIsEmbedded)
	{
		while( !IsEngineExitRequested() )
		{
			EngineTick();
		}
	}

#if WITH_EDITOR
	if( GIsEditor )
	{
		EditorExit();
	}
#endif
	return ErrorLevel;
}

梳理一下大体的逻辑,在一切初始化逻辑开始之前,函数会先把这个消息广播出去,如果有更早需要执行的逻辑,可以注册到这个委托上。另外,为了保证引擎的退出逻辑一定会被调用到,UE在这里定义了一个局部的struct,这个struct定义了一个析构函数,析构函数的实现就是调用引擎的退出逻辑。有了这个局部struct,再定义一个局部的对象,这个对象不是动态分配的,那么C++会保证它离开作用域时就会销毁它,从而调用到引擎的退出逻辑。这也是C++ RAII的常见做法了。

再往下,可以发现引擎的初始化分为PreInit和Init两个步骤。Init会根据是否是Editor环境,调用不同的逻辑。在初始化完成后,就进入到了引擎的主循环。

顺便一提,PreInit,Init,Tick,Exit都是简单的包装函数,它们的实现就是调用全局变量GEngineLoop的相应接口。

int32 EngineInit()
{
	int32 ErrorLevel = GEngineLoop.Init();

	return( ErrorLevel );
}

LAUNCH_API void EngineTick( void )
{
	GEngineLoop.Tick();
}

LAUNCH_API void EngineExit( void )
{
	// Make sure this is set
	RequestEngineExit(TEXT("EngineExit() was called"));

	GEngineLoop.Exit();
}

PreInit初始化了各种底层模块[4],非常繁多。

UE5的引擎初始化流程1

除此之外,还完成了许多模块的加载:

UE5的引擎初始化流程2

Init阶段,UE会根据是否为editor环境调用EditorInit或者EngineInit。而EditorInit本身的实现里就是包含EngineInit的。Init简化后的版本如下。

int32 FEngineLoop::Init()
{
	UClass* EngineClass = nullptr;
	if( !GIsEditor )
	{
		// We're the game.
		FString GameEngineClassName;
		GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("GameEngine"), GameEngineClassName, GEngineIni);
		EngineClass = StaticLoadClass( UGameEngine::StaticClass(), nullptr, *GameEngineClassName);
		GEngine = NewObject<UEngine>(GetTransientPackage(), EngineClass);
	}
	else
	{
#if WITH_EDITOR
		// We're UnrealEd.
		FString UnrealEdEngineClassName;
		GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("UnrealEdEngine"), UnrealEdEngineClassName, GEngineIni);
		EngineClass = StaticLoadClass(UUnrealEdEngine::StaticClass(), nullptr, *UnrealEdEngineClassName);
		GEngine = GEditor = GUnrealEd = NewObject<UUnrealEdEngine>(GetTransientPackage(), EngineClass);
#endif
	}

    GEngine->ParseCommandline();
    GEngine->Init(this);
    FCoreDelegates::OnPostEngineInit.Broadcast();

    if (!IProjectManager::Get().LoadModulesForProject(ELoadingPhase::PostEngineInit) || !IPluginManager::Get().LoadModulesForEnabledPlugins(ELoadingPhase::PostEngineInit))
    {
        RequestEngineExit(TEXT("One or more modules failed PostEngineInit"));
        return 1;
    }

	// Call module loading phases completion callbacks
	SetEngineStartupModuleLoadingComplete();
    GEngine->Start();

	GIsRunning = true;

    FCoreDelegates::OnFEngineLoopInitComplete.Broadcast();
    return 0;
}

Init阶段主要做了如下的事情[3]:

  1. 根据当前是否为编辑器环境,检查引擎配置文件以确定应该使用哪个GameEngine类;
  2. 然后创建该类的一个实例并将其作为全局UEngine实例。也就是GEngine
  3. 创建之后,进行初始化,完成时会触发一个全局委托;
  4. 加载已配置为延迟加载的任何项目或插件模块;
  5. 加载完成后,再触发一个完成的回调;
  6. 正式启动引擎;
  7. 发送引擎启动的委托。

自此,引擎的初始化流程就宣告结束了,后面就进入到了tick的阶段。

Reference

[1] 下载虚幻引擎源代码

[2] 从零开始手敲次世代游戏引擎(五)

[3] UE5 – 引擎运行流程(从main到BeginPlay)

[4] The Unreal Engine Game Framework: From int main() to BeginPlay

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1871432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

头歌资源库(17)多机调度问题

一、 问题描述 二、算法思想 首先&#xff0c;将作业按照所需时间从大到小排序。 创建一个长度为m的数组task_time&#xff0c;用来记录每台机器已经加工的作业时间。 从第一个作业开始&#xff0c;依次将作业分配给空闲的机器&#xff0c;并更新task_time数组。 对于每个…

springboot 集成阿里云 OSS

引入依赖 <!-- 阿里云oss依赖 --> <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.9.1</version> </dependency><?xml version"1.0" encoding"…

阿里云centos 7.9 使用宝塔面板部署.netcore 6.0

前言&#xff1a; 我有一个netcore6.0的系统接口和手机端程序的站点程序之前是部署在一台windows测试服务器的IIS站点中&#xff0c; 服务器最近压力太大扛不住了&#xff0c;买了一台centos7.9的阿里云服务器准备进行迁移。具体操作日记如下。 一、安装宝塔面板 这一步涉及…

【人工智能学习之图像操作(二)】

【人工智能学习之图像操作&#xff08;二&#xff09;】 图像上的运算图像混合按位运算 图像的几何变换仿射变换透视变换膨胀操作腐蚀操作开操作闭操作梯度操作礼帽操作黑帽操作 图像上的运算 图像上的算术运算&#xff0c;加法&#xff0c;减法&#xff0c;图像混合等。 加减…

AI进阶指南第五课,大模型相关概念(知识库,微调)

虽然前面大概讲了一下大模型的一些基本概念&#xff0c;但是那些都比较偏向于大模型本身&#xff0c;但是我们使用的时候如果只靠大模型肯定是不行的。 就好比如果一个人只有一个脑子&#xff0c;其他什么部位也没有的话&#xff0c;那场面。&#xff08;感觉现在网上的AI图片…

泰迪智能科技实验室产品-云计算资源管理平台介绍

云计算资源管理平台是一款集群应用程序管理平台&#xff0c;以Docker、Kubernetes为核心引擎的容器化应用部署、运行环境&#xff0c;对数据中心的物理服务器、网络、存储、虚拟服务器等基础架构资源进行集中统一的管理、分配、监控等。平台旨在围绕行业应用逐步由“虚拟化”向…

llama-3 本地化部署实验

国产大模型的API 有限&#xff0c;编写langchain 应用问题很多。使用openai 总是遇到网络问题&#xff0c;尝试使用ollama在本地运行llama-3。结果异常简单。效果不错。llama-3 的推理能力感觉比openai 的GPT-3.5 好。 Ollama 下载 官网&#xff1a;https://ollama.com/downl…

计算机毕业设计hadoop+spark+hive知识图谱医生推荐系统 医生数据分析可视化大屏 医生爬虫 医疗可视化 医生大数据 机器学习 大数据毕业设计

测试过程及结果 本次对于医生推荐系统测试通过手动测试的方式共进行了两轮测试。 &#xff08;1&#xff09;第一轮测试中执行了个20个测试用例&#xff0c;通过16个&#xff0c;失败4个&#xff0c;其中属于严重缺陷的1个&#xff0c;属于一般缺陷的3个。 &#xff08;2&am…

llm学习2--使用embedding和数据处理

首先可以简单了解一下向量数据库相关知识&#xff1a; 向量数据库相关知识&#xff08;搬运学习&#xff0c;建议还是看原文&#xff0c;这个只是我自己的学习记录&#xff09;-CSDN博客 补充&#xff1a; 使用embedding API 文心千帆API Embedding-V1是基于百度文心大模型…

微服务应用与开发知识点练习【Gateway,OpenFeign,Dubbo,RocketMQ和RabbitMQ,JPA,Redis,Mycat】

一、选择题 【Gateway】 1.Spring Cloud Gateway与Nacos整合实现负载均衡时&#xff0c;路由配置中的URI前缀应该是&#xff1f;&#xff08;A &#xff09; A. lb:// B. nacos:// C. http:// D. discovery:// Spring Cloud Gateway与Nacos整合实现负载均衡时&#xff0c…

【Linux系统编程】进程控制(创建、退出、等待、替换)

目录 再聊进程创建 进程终止 进程等待 进程程序替换 再聊进程创建 初识进程创建 关于进程创建&#xff0c;这里只会说结论&#xff0c;在上面这篇文章中对进程创建进行了比较详细的阐述&#xff0c;而接下来要介绍的&#xff0c;都是基于上文说过的来展开的 一些较为重要…

【FFmpeg】avformat_alloc_output_context2函数

【FFmpeg】avformat_alloc_output_context2函数 1.avformat_alloc_output_context21.1 初始化AVFormatContext&#xff08;avformat_alloc_context&#xff09;1.2 格式猜测&#xff08;av_guess_format&#xff09;1.2.1 遍历可用的fmt&#xff08;av_muxer_iterate&#xff0…

Bad owner or permissions on C:\\Users\\username/.ssh/config > 过程试图写入的管道不存在。

使用windows连接远程服务器出现Bad owner or permissions 错误 问题&#xff1a; 需要修复文件权限 SSH 配置文件应具有受限权限以防止未经授权的访问 确保只有用户对该.ssh/config文件具有读取权限 解决方案&#xff1a; 在windows下打开命令行&#xff0c;通过以下命令打开文…

Spring Cloud Alibaba之负载均衡组件Ribbon

一、什么是负载均衡&#xff1f; &#xff08;1&#xff09;概念&#xff1a; 在基于微服务架构开发的系统里&#xff0c;为了能够提升系统应对高并发的能力&#xff0c;开发人员通常会把具有相同业务功能的模块同时部署到多台的服务器中&#xff0c;并把访问业务功能的请求均…

Kubernetes之 资源管理

系列文章目录 Kubernetes之 资源管理 文章目录 系列文章目录前言一、资源管理介绍二、YAML语言介绍 1.1.YAML语法&#xff1a;2.读入数据总结 一、资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 1. kub…

SMTP 转发器/中继

设置中继邮件服务器 我将设置一个邮件服务器&#xff0c;该服务器稍后将用作 SMTP 中继服务器。首先&#xff0c;在 Digital Ocean 中创建了一个新的 Ubuntu Droplet&#xff1a; Postfix MTA 安装在droplet上&#xff0c;并带有&#xff1a; apt-get install postfix 在pos…

序列检测器(Moore型)

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请用Moore型状态机实现序列“1101”从左至右的不重叠检测。 电路的接口如下图所示。当检测到“1101”&#xff0c;Y输出一个时钟周期的高电平脉冲。 接口电路图如下&#xff1a; 输入描述&#xff1a…

【机器学习300问】132、自注意力机制(Self-Attention)和传统注意力机制(Attention)的区别?

最近学习注意力机制的时候&#xff0c;发现相同的概念很多&#xff0c;有必要给这些概念做一下区分&#xff0c;不然后续的学习可能会混成一团。本文先区分一下自注意力机制和传统注意力机制。我会先直接给出它们之间有何区别的结论&#xff0c;然后通过一个例子来说明。 【机…

阿里云服务器通过镜像下hunggingface上的模型

参考连接https://blog.csdn.net/lanlinjnc/article/details/136709225 https://www.bilibili.com/video/BV1VT421X7xe/?spm_id_from333.337.search-card.all.click&vd_source1ba257184239f03bd3caf4c6cab427e4 pip install -U huggingface_hub# 建议将上面这一行写入 ~/…

Ubuntu Nvidia GPU驱动安装和故障排除

去官网 菜单列表下载&#xff0c;或者直接下载驱动 wget https://cn.download.nvidia.com/XFree86/Linux-x86_64/550.54.14/NVIDIA-Linux-x86_64-550.54.14.run 安装驱动 /data/install/NVIDIA-Linux-x86_64-550.54.14.run 执行命令&#xff0c;显示GPU情况 出错处理&…