[{"data":1,"prerenderedAt":344},["ShallowReactive",2],{"\u002F2017-06-06-ue4-config-usage":3},{"id":4,"title":5,"body":6,"date":320,"description":12,"extension":321,"meta":322,"navigation":325,"path":337,"seo":338,"stem":339,"tags":340,"__hash__":343},"blogs\u002F_legacy\u002F2017\u002F2017-06-06-ue4-config-usage.md","UE4中Config的使用",{"type":7,"value":8,"toc":311},"minimark",[9,13,16,20,23,26,62,65,107,110,121,124,127,138,141,147,150,156,159,162,165,171,182,185,188,194,197,200,220,227,230,233,236,239,242,245,248,254,257,260,266,269,275,278,281,284,290,293,296,299,302],[10,11,12],"p",{},"UE4中本身有一套非常成熟的INI文件配置机制，对于简单的属性配置，可以直接进行借用。",[10,14,15],{},"当前使用的UE4版本为4.15.2。",[17,18,19],"h2",{"id":19},"引擎配置",[10,21,22],{},"整个Config机制在引擎中最常见的地方就是引擎的配置本身了，项目配置与引擎配置，Localize的配置……这些都是通过这个机制进行的。",[10,24,25],{},"引擎自带的配置分类有以下这些：",[27,28,29,32,35,38,41,44,47,50,53,56,59],"blockquote",{},[10,30,31],{},"Compat（兼容性）",[10,33,34],{},"DeviceProfiles（设备概述文件）",[10,36,37],{},"Editor（编辑器）",[10,39,40],{},"EditorGameAgnostic（编辑器游戏不可知论）",[10,42,43],{},"EditorKeyBindings（编辑器按键绑定）",[10,45,46],{},"EditorUserSettings（编辑器用户设置）",[10,48,49],{},"Engine(引擎)",[10,51,52],{},"Game(游戏)",[10,54,55],{},"Input（输入）",[10,57,58],{},"Lightmass",[10,60,61],{},"Scalability（可扩展性）",[10,63,64],{},"配置文件是有加载优先的，按照官方文档提供的顺序，越靠后的值会覆盖前面的值。",[27,66,67,70,73,84,90,99],{},[10,68,69],{},"Engine\u002FConfig\u002FBase.ini",[10,71,72],{},"Engine\u002FConfig\u002FBaseEngine.ini",[10,74,75,76,80,81,83],{},"Engine\u002FConfig\u002F",[77,78,79],"span",{},"Platform","\u002F",[77,82,79],{},"Engine.ini",[10,85,86,89],{},[77,87,88],{},"ProjectDirectory","\u002FConfig\u002FDefaultEngine.ini",[10,91,92,94,95,80,97,83],{},[77,93,88],{},"\u002FConfig\u002F",[77,96,79],{},[77,98,79],{},[10,100,101,103,104,106],{},[77,102,88],{},"\u002FSaved\u002FConfig\u002F",[77,105,79],{},"\u002FEngine.ini",[10,108,109],{},"这个加载次序是以Engine配置为基础的。",[10,111,112,113,120],{},"关于这部分的详细可以参照[",[114,115,119],"a",{"href":116,"rel":117},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FProgramming\u002FBasics\u002FConfigurationFiles\u002Findex.html",[118],"nofollow","官方文档","]。",[17,122,123],{"id":123},"自主调用",[10,125,126],{},"使用GConfig就可以对这个配置系统中的值进行查询和写入，要对配置进行读取的话可以使用：",[128,129,134],"pre",{"className":130,"code":132,"language":133},[131],"language-text","if(!GConfig) return;\n\nFString ValueReceived;\n  GConfig->GetString(\n  TEXT(\"\u002FScript\u002FEngine.WorldInfo\"),\n  TEXT(\"GlobalDefaultGameType\"),\n  ValueReceived,\n  GGameIni\n);\n","text",[135,136,132],"code",{"__ignoreMap":137},"",[10,139,140],{},"而写入的话，可以使用：",[128,142,145],{"className":143,"code":144,"language":133},[131],"if (!GConfig) return;\nGConfig->SetInt(\n  TEXT(\"sectionname\"),\n  TEXT(\"key\"),\n  100,\n  GGameUserSettingsIni\n  );\nGConfig->Flush(false, GGameUserSettingsIni);\n",[135,146,144],{"__ignoreMap":137},[10,148,149],{},"这里使用的Get\u002FSet是一系列函数，对应引擎内部的不同值，第四个参数是配置的名称，与上面给出的配置分类是对应的，应该，没有仔细的考证过。可以看到GGameUserSettingsIni附近有很多这样的定义：",[128,151,154],{"className":152,"code":153,"language":133},[131],"FString                GEngineIni;                                                    \u002F* Engine ini filename *\u002F\n\n\u002F** Editor ini file locations - stored per engine version (shared across all projects). Migrated between versions on first run. *\u002F\nFString                GEditorIni;                                                    \u002F* Editor ini filename *\u002F\nFString                GEditorKeyBindingsIni;                                        \u002F* Editor Key Bindings ini file *\u002F\nFString                GEditorLayoutIni;                                            \u002F* Editor UI Layout ini filename *\u002F\nFString                GEditorSettingsIni;                                            \u002F* Editor Settings ini filename *\u002F\n\n\u002F** Editor per-project ini files - stored per project. *\u002F\nFString                GEditorPerProjectIni;                                        \u002F* Editor User Settings ini filename *\u002F\n\nFString                GCompatIni;\nFString                GLightmassIni;                                                \u002F* Lightmass settings ini filename *\u002F\nFString                GScalabilityIni;                                            \u002F* Scalability settings ini filename *\u002F\nFString                GHardwareIni;                                                \u002F* Hardware ini filename *\u002F\nFString                GInputIni;                                                    \u002F* Input ini filename *\u002F\nFString                GGameIni;                                                    \u002F* Game ini filename *\u002F\nFString                GGameUserSettingsIni;                                        \u002F* User Game Settings ini filename *\u002F\n",[135,155,153],{"__ignoreMap":137},[10,157,158],{},"其实这种用法，使用起来相对有些麻烦，而且会把自己的配置和引擎的配置混在一起，其实还有更加简单的使用这个配置的方法：",[17,160,161],{"id":161},"扩展使用",[10,163,164],{},"这个特性是可以扩展给自己定义的类使用的，在UClass定义时制定Config即可，像是这样的感觉：",[128,166,169],{"className":167,"code":168,"language":133},[131],"UCLASS(config=GameUserSettings, configdonotcheckdefaults)\nclass ENGINE_API UGameUserSettings : public UObject\n",[135,170,168],{"__ignoreMap":137},[10,172,173,174,177,178,181],{},"其实上面那些自带的引擎配置就是在引擎中预先定义好的",[77,175,176],{},"名称","-",[77,179,180],{},"配置文件名","对应组。",[10,183,184],{},"这里面在定义时，config=custom，这样自己定义配置文件名称也是可以的。如果不想自己的配置和引擎的配置混在一起变得乱七八糟的话，这是一个很好的选择。",[10,186,187],{},"这样的好处是所有标记为UProperty的属性加上config标记都会被自动载入，在执行SaveConfig后就可以直接保存，不需要和配置的逻辑打交道。定义时就像这样的感觉：",[128,189,192],{"className":190,"code":191,"language":133},[131],"UPROPERTY(config, EditAnywhere, Category=\"MouseProperties”)\nuint32 bEnableFOVScaling:1;\n",[135,193,191],{"__ignoreMap":137},[10,195,196],{},"在文件名的分配上，如果使用custom的话，配置文件就会被保存到custom.ini的命名规则下。如果一时之间找不到配置文件，可以使用这个文件名进行搜索。",[10,198,199],{},"这一系列的配置还有其他几个选项：",[27,201,202,205,208,211,214,217],{},[10,203,204],{},"perObjectConfig",[10,206,207],{},"使得配置变为针对每个Object的实例，而不是每个Class存一个配置块。",[10,209,210],{},"configdonotcheckdefaults",[10,212,213],{},"配置了这个的话，config在读取的时候就不会去读取default配置。",[10,215,216],{},"defaultconfig",[10,218,219],{},"配置只保存在default中",[10,221,222,223,226],{},"这里有一个概念就是Default，Default配置的读取是比较靠前的，通常保存在项目目录Config\u002F",[77,224,225],{},"Custom","Default.ini中。这里有一个在测试时需要注意的，如果SaveConfig的值与Default值相同的话，那么就会不进行保存，该行配置会消失，因为与默认值一样了。",[10,228,229],{},"在进行配置文件操作和设定时，可以使用UpdateDefaultConfigFile()来写入到default值，而通常的配置可以使用SaveConfig()进行保存，因为SaveConfig是会自动进行Flush的，而另一个UpdateGlobal ConfigFile则局限性较强，但它可以确保写入路径是指向用户配置的。",[10,231,232],{},"要注意的是，如果在Shipping打包模式下，那么可以让用户和我们自己进行配置的ini文件将不会出现在项目目录中个，而是在\"用户目录\\AppData\\Local\\rg_unreal\\Saved\\Config\\WindowsNoEditor[custom].ini\"中。",[10,234,235],{},"如果觉得这样有些Low的话，我们就需要绕回去：",[17,237,238],{"id":238},"自定义路径",[10,240,241],{},"仔细查看Config系统的源码，我们可以看到，ini的加载是在UObject中进行指定的。如果没有定义PerObjectConfig的话，配置是在CDO阶段就完成了的。如果定义了PerObject的话则会在UObject:: PostLoad中进行配置加载。",[10,243,244],{},"但是系统本身的GetConfigName是无法被重载的，好在引擎有暴露其他的接口，我们要对其使用只要自己在BeginPlay之类的事件中自己进行读写就可以了。",[10,246,247],{},"其实要使用的函数在上面已经用到了，只是在调用的时候使用的是默认参数罢了。",[128,249,252],{"className":250,"code":251,"language":133},[131],"SaveConfig(CPF_Config, *ConfPath);\n",[135,253,251],{"__ignoreMap":137},[10,255,256],{},"这样调用的话就可以将当前类中的配置保存到指定的路径去了，不用指定后缀名Ini也是可以的。",[10,258,259],{},"不过，出于保险起见，最好是在Save之后，刷新一下缓存",[128,261,264],{"className":262,"code":263,"language":133},[131],"GConfig->Flush(false, ConfPath)\n",[135,265,263],{"__ignoreMap":137},[10,267,268],{},"要读取的话也是同理，先刷新缓存",[128,270,273],{"className":271,"code":272,"language":133},[131],"GConfig->Flush(true, ConfPath)\n",[135,274,272],{"__ignoreMap":137},[10,276,277],{},"其实如果配置的读写都是在引擎内完成的话，是没必要在读取的时候刷缓存的。",[10,279,280],{},"但如果有在引擎外部修改配置文件，并希望配置“实时”的反映到读取中的话，就需要在读取前刷新一下缓存。",[10,282,283],{},"读取的话使用",[128,285,288],{"className":286,"code":287,"language":133},[131],"ReloadConfig(NULL, *ConfPath)\n",[135,289,287],{"__ignoreMap":137},[10,291,292],{},"就可以了，这里使用到的ConfPath都是FString。",[17,294,295],{"id":295},"总结",[10,297,298],{},"基本上配置存取使用官方的配置类就可以了，这里有一点很强大的是，似乎所有可以UPROPERTY化的引擎定义变量都可以写入到Config中，已经测试过TArray和TMap可以正常的进行读写。",[10,300,301],{},"但是像是UObject这类的并没有进行测试……不过引擎的配置中有大量的使用UAsset的引用，应当是毫无问题的。",[10,303,304,305,310],{},"不过，配置文件虽然有读写功能，但是它的定位本身并不适合用来存档。如果有这方面的需求请使用[",[114,306,309],{"href":307,"rel":308},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FGameplay\u002FSaveGame\u002Findex.html",[118],"SaveGame类","]，蓝图与C++皆可使用。",{"title":137,"searchDepth":312,"depth":313,"links":314},2,3,[315,316,317,318,319],{"id":19,"depth":312,"text":19},{"id":123,"depth":312,"text":123},{"id":161,"depth":312,"text":161},{"id":238,"depth":312,"text":238},{"id":295,"depth":312,"text":295},"2017-06-06","md",{"layout":323,"status":324,"published":325,"author":326,"author_login":328,"author_email":329,"wordpress_id":330,"wordpress_url":331,"date_gmt":332,"excerpt":333},"post","publish",true,{"display_name":327,"login":328,"email":329,"url":137},"风铃","flinkor","flinkor@foxmail.com",1777,"\u002F\u002F?p=1777","2017-06-06 12:12:22 +0000",{"type":7,"value":334},[335],[10,336,12],{},"\u002F2017-06-06-ue4-config-usage",{"title":5,"description":12},"_legacy\u002F2017\u002F2017-06-06-ue4-config-usage",[341,342],"UE4","Config","5PE0D-8QY1nKGtyz-G-TzQvrRF7I9D4LT4XxU3vOAks",1788763179961]