风蚀之月

UE4中Config的使用

06 Jun 2017 UE4 Config

UE4中本身有一套非常成熟的INI文件配置机制,对于简单的属性配置,可以直接进行借用。

当前使用的UE4版本为4.15.2。

引擎配置

整个Config机制在引擎中最常见的地方就是引擎的配置本身了,项目配置与引擎配置,Localize的配置……这些都是通过这个机制进行的。

引擎自带的配置分类有以下这些:

Compat(兼容性)

DeviceProfiles(设备概述文件)

Editor(编辑器)

EditorGameAgnostic(编辑器游戏不可知论)

EditorKeyBindings(编辑器按键绑定)

EditorUserSettings(编辑器用户设置)

Engine(引擎)

Game(游戏)

Input(输入)

Lightmass

Scalability(可扩展性)

配置文件是有加载优先的,按照官方文档提供的顺序,越靠后的值会覆盖前面的值。

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

这个加载次序是以Engine配置为基础的。

关于这部分的详细可以参照[官方文档]。

自主调用

使用GConfig就可以对这个配置系统中的值进行查询和写入,要对配置进行读取的话可以使用:

if(!GConfig) return;

FString ValueReceived;
  GConfig->GetString(
  TEXT("/Script/Engine.WorldInfo"),
  TEXT("GlobalDefaultGameType"),
  ValueReceived,
  GGameIni
);

而写入的话,可以使用:

if (!GConfig) return;
GConfig->SetInt(
  TEXT("sectionname"),
  TEXT("key"),
  100,
  GGameUserSettingsIni
  );
GConfig->Flush(false, GGameUserSettingsIni);

这里使用的Get/Set是一系列函数,对应引擎内部的不同值,第四个参数是配置的名称,与上面给出的配置分类是对应的,应该,没有仔细的考证过。可以看到GGameUserSettingsIni附近有很多这样的定义:

FString                GEngineIni;                                                    /* Engine ini filename */

/** Editor ini file locations - stored per engine version (shared across all projects). Migrated between versions on first run. */
FString                GEditorIni;                                                    /* Editor ini filename */
FString                GEditorKeyBindingsIni;                                        /* Editor Key Bindings ini file */
FString                GEditorLayoutIni;                                            /* Editor UI Layout ini filename */
FString                GEditorSettingsIni;                                            /* Editor Settings ini filename */

/** Editor per-project ini files - stored per project. */
FString                GEditorPerProjectIni;                                        /* Editor User Settings ini filename */

FString                GCompatIni;
FString                GLightmassIni;                                                /* Lightmass settings ini filename */
FString                GScalabilityIni;                                            /* Scalability settings ini filename */
FString                GHardwareIni;                                                /* Hardware ini filename */
FString                GInputIni;                                                    /* Input ini filename */
FString                GGameIni;                                                    /* Game ini filename */
FString                GGameUserSettingsIni;                                        /* User Game Settings ini filename */

其实这种用法,使用起来相对有些麻烦,而且会把自己的配置和引擎的配置混在一起,其实还有更加简单的使用这个配置的方法:

扩展使用

这个特性是可以扩展给自己定义的类使用的,在UClass定义时制定Config即可,像是这样的感觉:

UCLASS(config=GameUserSettings, configdonotcheckdefaults)
class ENGINE_API UGameUserSettings : public UObject

其实上面那些自带的引擎配置就是在引擎中预先定义好的[名称]-[配置文件名]对应组。

这里面在定义时,config=custom,这样自己定义配置文件名称也是可以的。如果不想自己的配置和引擎的配置混在一起变得乱七八糟的话,这是一个很好的选择。

这样的好处是所有标记为UProperty的属性加上config标记都会被自动载入,在执行SaveConfig后就可以直接保存,不需要和配置的逻辑打交道。定义时就像这样的感觉:

UPROPERTY(config, EditAnywhere, Category="MouseProperties”)
uint32 bEnableFOVScaling:1;

在文件名的分配上,如果使用custom的话,配置文件就会被保存到custom.ini的命名规则下。如果一时之间找不到配置文件,可以使用这个文件名进行搜索。

这一系列的配置还有其他几个选项:

perObjectConfig

使得配置变为针对每个Object的实例,而不是每个Class存一个配置块。

configdonotcheckdefaults

配置了这个的话,config在读取的时候就不会去读取default配置。

defaultconfig

配置只保存在default中

这里有一个概念就是Default,Default配置的读取是比较靠前的,通常保存在项目目录Config/[Custom]Default.ini中。这里有一个在测试时需要注意的,如果SaveConfig的值与Default值相同的话,那么就会不进行保存,该行配置会消失,因为与默认值一样了。

在进行配置文件操作和设定时,可以使用UpdateDefaultConfigFile()来写入到default值,而通常的配置可以使用SaveConfig()进行保存,因为SaveConfig是会自动进行Flush的,而另一个UpdateGlobal ConfigFile则局限性较强,但它可以确保写入路径是指向用户配置的。

要注意的是,如果在Shipping打包模式下,那么可以让用户和我们自己进行配置的ini文件将不会出现在项目目录中个,而是在”用户目录\AppData\Local\rg_unreal\Saved\Config\WindowsNoEditor[custom].ini”中。

如果觉得这样有些Low的话,我们就需要绕回去:

自定义路径

仔细查看Config系统的源码,我们可以看到,ini的加载是在UObject中进行指定的。如果没有定义PerObjectConfig的话,配置是在CDO阶段就完成了的。如果定义了PerObject的话则会在UObject:: PostLoad中进行配置加载。

但是系统本身的GetConfigName是无法被重载的,好在引擎有暴露其他的接口,我们要对其使用只要自己在BeginPlay之类的事件中自己进行读写就可以了。

其实要使用的函数在上面已经用到了,只是在调用的时候使用的是默认参数罢了。

SaveConfig(CPF_Config, *ConfPath);

这样调用的话就可以将当前类中的配置保存到指定的路径去了,不用指定后缀名Ini也是可以的。

不过,出于保险起见,最好是在Save之后,刷新一下缓存

GConfig->Flush(false, ConfPath)

要读取的话也是同理,先刷新缓存

GConfig->Flush(true, ConfPath)

其实如果配置的读写都是在引擎内完成的话,是没必要在读取的时候刷缓存的。

但如果有在引擎外部修改配置文件,并希望配置“实时”的反映到读取中的话,就需要在读取前刷新一下缓存。

读取的话使用

ReloadConfig(NULL, *ConfPath)

就可以了,这里使用到的ConfPath都是FString。

总结

基本上配置存取使用官方的配置类就可以了,这里有一点很强大的是,似乎所有可以UPROPERTY化的引擎定义变量都可以写入到Config中,已经测试过TArray和TMap可以正常的进行读写。

但是像是UObject这类的并没有进行测试……不过引擎的配置中有大量的使用UAsset的引用,应当是毫无问题的。

不过,配置文件虽然有读写功能,但是它的定位本身并不适合用来存档。如果有这方面的需求请使用[SaveGame类],蓝图与C++皆可使用。