UE4 Config配置文件详解
一、配置总体概述
在UE4中,配置文件(Config)实际上就是.ini文件,可用于设置加载时要初始化的属性值,配置信息以键值对的格式呈现。虚幻4官方文档仅提供了简单的使用规则,若要深入了解,还需查看源代码。在此,我将自己的学习成果分享给大家。一个完整的配置文件格式如图1 - 1所示。

我们常见的配置文件一般存于以下四个路径:
\Engine\Config及其子目录\Engine\Saved\Config及其子目录(引擎运行后生成)Projects\[ProjectName]\Config及其子目录Projects\[ProjectName]\Saved\Config及其子目录(游戏项目运行后生成)
如上述标记,路径2和路径4的配置信息是后续生成的。
二、概念须知
为使后续描述更清晰,这里先简要介绍一些基本原理和概念。
概念
- Section:如图1 - 1所示,每个配置文件包含多个模块,每个模块的标题即为一个section。
- Flush:在代码中,类
FConfigCacheIni有一个名为Flush()的方法。其字面意思是冲洗、奔涌,在代码里表示将内存信息(即缓存的配置信息)准确无误地写入文件。 - GConfig:全局空间的一个配置缓存变量,定义如下:
FConfigCacheIni* GConfig = NULL;在不同情况下,
GConfig存储不同的信息,如图2 - 1和图2 - 2所示。关于GConfig的内容,后续会详细讲解。

基本原理
配置文件结构
为全面了解配置文件,需弄清其结构。
- 配置分类
Compat(兼容性)DeviceProfiles(设备概述文件)Editor(编辑器)EditorGameAgnostic(编辑器游戏未知的配置信息)EditorKeyBindings(编辑器按键绑定)EditorUserSettings(编辑器用户设置)Engine(引擎)Game(游戏)Input(输入)Lightmass(灯光构建相关)Scalability(可扩展性)EditorLayout(编辑器布局)SourceControlSettings(源码控制设置,只存在于引擎和工程的Save目录)TemplateDefs(模板定义,只存在于引擎和工程的Save目录)
上述内容基本涵盖了所有配置文件的类型,不同类型的配置设置存于不同文件中。
- 文件层次结构
配置文件读入时从
Base.ini开始,文件结构中后面文件内的值会覆盖之前的值。Engine文件夹中的文件适用于所有项目,而特定项目的文件应位于项目目录中。最后,所有特定项目和特定平台的差异信息会保存到[ProjectDirectory]/Saved/Config/[Platform]/[Category].ini文件中。以下是配置文件的Engine类的文件层次结构示例:- ①
Engine/Config/Base.ini:该文件通常为空。 - ②
Engine/Config/BaseEngine.ini - ③
Engine/Config/[Platform]/[Platform]Engine.ini - ④
[ProjectDirectory]/Config/DefaultEngine.ini - ⑤
[ProjectDirectory]/Config/[Platform]/[Platform]Engine.ini - ⑥
[ProjectDirectory]/Saved/Config/[Platform]/Engine.ini
- ①
对上述内容解释如下:读取配置信息时,会按上述路径进行。由于后面层级的内容对项目的针对性逐渐增强,所以层级越高,配置信息的优先级越高。同时要注意,很多配置文件的名称是固定的(中括号内的除外),不能随意删除和修改。后续原理2.2.1会进一步阐述。
配置文件目录分析
在总体概述中,我们简单介绍了配置文件的目录,这里进行深入分析。
我们常见的配置文件一般存于以下四个路径:
\Engine\Config及其子目录\Engine\Saved\Config及其子目录(引擎运行后生成)Projects\[ProjectName]\Config及其子目录Projects\[ProjectName]\Saved\Config及其子目录(游戏项目运行后生成)
下面给出这4个目录下的文件内容,以便直观了解。请牢记这4个路径及其编号,后续会多次提及。


那么这四个目录之间有何关系和作用呢?
首先,路径1和路径3中的配置文件在引擎运行时不会自动生成,需手动添加。不过,引擎路径1的配置文件通常已写好,一般无需改动。当新建一个空白项目时,引擎会在路径3中自动生成DefaultEngine.ini、DefaultGame.ini,可能还会生成DefaultEditor.ini;若使用提供的模板,还会生成DefaultEditor.ini和DefaultInput.ini配置文件。
根据对比图,可将引擎和项目分开来看。打开纯引擎编辑器时,与项目无关,引擎会依据自身代码逻辑和路径1中的配置信息生成路径2中的配置信息。同理,运行工程时,会根据代码逻辑和路径3的配置信息生成路径4的配置信息,但存在一点区别。结合原理2.2.1的文件层次结构可知,工程的配置文件(路径4下的)生成还与路径1中的引擎配置文件有间接关系(与路径2无关)。
另外,我们对比的实际是路径3与路径4\windows,路径4下的结构通常如下,除平台文件夹外,还有一个CleanSourceConfigs文件夹。
![图2 - 4 Projects[ProjectName]\Saved\Config目录结构图](此处应插入图2 - 4的实际链接)
生成的信息分布在这两个文件夹中。CleanSource文件夹中是路径1和路径3配置信息的总和(即文件层次结构⑥之前的配置信息),其他与游戏本身、平台相关的差异配置信息最终会存储到Windows(对应平台)目录下。
总结来说,无论是引擎还是项目,Config下的配置信息需手动添加,而Save/Config下的信息是引擎或项目运行后生成的。
注意:若删除工程下的DefaultEngine.ini,工程将无法运行,会提示如下错误(这表示Engine目录下的配置必须有[URL] GameName=ProjectName)。

三、使用流程
自动配置
在UE4中,利用引擎特性,简单配置即可实现配置信息的保存与读取。基本流程如下:

- 为指定从哪个配置文件读取哪个变量,在包含这些变量的类的
UCLASS宏中应赋予Config标识符。
注意:必须为Config标识符提供类别(如Game(游戏)),这决定了从哪个配置文件读取类的变量以及将其保存到哪个配置文件。所有可能的分类在类ConfigCacheIni(实际是GConfig对象)中定义,所有配置文件的分类列表在第二部分已描述。
- 若要指定读取和保存到配置文件中的某个变量,该属性的
UPROPERTY()宏也必须提供Config标识符,如下图所示。
对属性的Config标识符不提供任何分类。ExampleVariable属性可从配置文件结构(第二部分有描述)的任意Game配置文件中读取,只要信息由以下语法指定(其中ModuleName指的是包Package,ExampleClass是对应的类名)。
- 这一步官方文档未说明。实际上,要使标记
config属性的值与构造函数初始化时的值不同。若仅按前两个步骤操作,会发现对应的配置文件中没有所需变量。因为引擎执行SaveConfig时,会遍历所有标记Config的属性,判断当前对象的config属性是否与同属一类CDO的相同属性值相同,若相同则认为未修改,无需存储到配置文件中。
因此,有两种方法修改属性值:一是在方法中修改config属性的值,然后在游戏开始时调用;二是将该config属性设置为蓝图可读写,在蓝图配置中修改。修改操作执行后,一定要调用SaveConfig保存配置信息,信息会写入配置文件。
注:CDO即ClassDefaultObject,涉及UE4每个对象的内部结构,可暂时理解为系统运行时会默认构造一个该类的对象,该对象仅执行构造函数。
手动编码配置
除自动配置方法外,还可通过编码将配置信息保存到任意文件。此时需使用SaveConfig函数,该函数可在使用配置类修饰符的类上调用。一般来说,SaveConfig()保存的变量位于按[(package).(classname)]格式命名的部分标题中。例如,DefaultEngine.ini中的[/Script/Engine.Engine]部分指向存储在Engine包内部的Engine类。

下面举例说明在GameMode中如何使用手动编码将信息保存到指定位置。
首先定义一个方法,用于将某个类型的配置信息保存到
GConfig中。其逻辑是判断当前值是否为要配置的默认值,是否已存在于GConfig中。若是默认值且不在GConfig中,则执行GConfig->SetBool操作,将该bool变量保存到GConfig。然后在
GameMode初始化阶段执行该方法并调用SaveConfig保存。
GGameUserSettingsIni是全局的FString,保存的是GameUserSetting配置文件的路径,因此可将GameMode的配置信息保存到GameUserSetting中。其他配置文件路径可在Core.cpp中搜索。
四、配置文件的存储流程

注:SaveConfig是UObject的方法,可在任何标记Config的子类上调用。
原理与特性分析
配置文件的意义
刚接触配置文件时,最大的疑问是配置文件一般用于读取,为何要生成这么多配置文件和信息?
可这样理解:第一次运行游戏项目时,引擎会先读取引擎目录\Config、游戏目录\Config中的配置信息,以及配置文件路径(运行游戏时的配置路径为[ProjectDirectory]/Saved/Config/[Platform]/),并将其存储到GConfig中。其他配置信息会在各个模块执行SaveConfig()时写入GConfig(前面简单描述过),最后通过GConfig写入生成的配置文件(指Projects\[ProjectName]\Saved\Config及其子目录,第二章节有讲解)。
第二次运行时,由于之前已生成配置文件,引擎会先将所有配置文件的数据读入GConfig(包括第一次运行生成的)。若发现配置文件信息有遗漏或改动,执行SaveConfig()时会再次写入GConfig,并写入路径4(见2.2.1章节)的配置文件中。
由此可知,修改后来生成的配置信息意义不大,因为每次游戏运行时,都希望将配置信息存储成代码或工程所需的样子。这些生成的配置信息可在游戏运行后读取并利用。不过,可修改路径3(见2.2.1章节,工程默认配置)中的信息,修改后会立即生效。若事先将所有信息写在路径3下,会发现路径4中的配置信息为空。
配置文件的存储原理
GConfig前面多次出现,有必要了解其本质。实际上,GConfig是一个配置信息缓存量,运行时会一直保存所有配置信息。
以下是GConfig所属的类及其继承关系图。

从图中可看出,GConfig可视为一个三层结构的Map(最底层为MultiMap),依次存储配置路径、配置section、配置属性与值。详细结构可通过下图进一步了解。

这里对FConfigFile类型进行解释。从上述两个图可知,一个配置文件FConfigFile类由5个成员构成,这些成员可解释前面的很多规则和现象:
FName:记录该配置文件的类型。SourceIniHierarchy:如第二章节2.2.1所述,该成员变量描述文件的层级结构,根据此结构,最终的差异信息会存储到\Windows下面。SourceConfigFile:表示从本地最初加载的配置内容(即加载第二章节2.2.2中所说的路径1和路径4中的配置信息)。dirty:文件是否被修改,写文件时,若该值为False则不会重写配置文件。NoSave:文件是否未保存。
配置文件和继承
Config UCLASS和UPROPERTY标识符都会被子类继承。这意味着子类可读取或保存父类中指定为Config的所有变量,且这些变量会位于相同的配置文件分类中。变量会位于具有子类名称的部分下。例如,继承ExampleClass的ChildExampleClass的配置文件信息如下所示,且会保存在同一个Config配置文件中。
子类无法否定继承父类的Config标志,但可通过重新声明config关键字并指定不同的文件名来更改.ini文件。
基于每个对象实例的配置
虚幻引擎4可将一个对象的配置信息保存到任何所需的配置文件中。若PerObjectConfig标识符用于UCLASS宏,该类的配置信息将基于每个对象实例存储,每个对象实例在.ini文件中都有一部分,文件以对象的名字命名,格式为[ObjectName ClassName]。该关键字会传递给子类。
这样的例子可参考UDeviceProfile类,其前置宏为UCLASS(config=DeviceProfiles, perobjectconfig, Blueprintable),表示会生成名为DeviceProfile.ini的配置文件,其中的信息如下:
[XboxOne DeviceProfile]
Key=Value
[iPhone5S DeviceProfile]
Key=Value
代码细节是,执行SaveConfig时,会判断当前对象是否用PerObjectConfig标记,若是则为该对象单独标记一个配置信息(如Section = L" iPhone5S DeviceProfile "),否则统一标记到该类中(如Section = L"/Script/UdpMessaging.UdpMessagingSettings")。
六、其他
- 配置文件的生成远早于内容书写。若为第一次运行,工程运行开始时会通过
GenerateDestIniFile生成空的配置文件。 FPaths包含游戏工程的各种目录路径,如EngineDir、GameSavedDir、GameContentDir等,对配置信息的存储路径很重要。