The config ini changes in UE 5.5: Save, Load, Plugin
Conclusion
- In the case of the plugin
- Make a
Config
folder under the plugin folder, and makeDefault{PluginName}.ini
in there.- In plugins, we can use only the name of the plugin as the ini file name.
Default{PluginName}.ini
can be empty. It doesn’t need any special content.- Use the
PluginName
as the value of the specifierConfig
in theUClass
.
- Make a
- In the case of the module
- To make possible to load
- You can see the
Config
folder under your project folder. The Default ini file should exist there. If it does not, create one.
- You can see the
- To make possible to save
- The section
[SectionsToSave]
should exist in the Default ini file. If it does not, add it. - Add
bCanSaveAllSections=true
in the section[SectionsToSave]
. There is another way that you can specify explicitly which classes are allowed to be saved.
- The section
- To make possible to load
- You can use the “known” categories as the file name of ini file. But in this case, you should set the Default ini file to make it possible to save classes that belong to the plugin.
Preface
Official Documents
- Official Documents: Configuration Files
- 5.5 Release Note
- You can see the related content by searching with “
FConfigBranch
” on this page.
- You can see the related content by searching with “
Wiki
Unreal community wiki: Config Files, Read & Write to Config Files
Version
As the title suggests, this document is based on Unreal Engine version 5.5.
Goal
This document assumes that we are working only with specifiers of UCLASS
and text ini files, without any additional c++ code.
That is, there is only one function we will call at the c++ level, UObject::LoadConfig
GitHub Link
.
This is because I want code and resources that can work well on older versions of the engine.
However, in a detailed explanation, there will likely be mentions of various aspects of the engine source code.
Terms
In the engine code, it is also called an ini file or a Config file, but from now on, I will call it an ini file.
Sample Project
I uploaded an example project about this topic. Link
I created this project to use when I want to know the detailed behavior of the engine through debugging.
Long long time ago
Until 5.3
This will create a file name of SomeConfigFileName.ini
, and the Config values will be saved in it. In the example above, the value of ValueInObject will be saved.
In 5.4
I wrote a post about some limitations in customizing ini file names with config specifiers in UCLASS in 5.4.
However, in 5.5, we can’t use the method of adding User
or Editor
to the ini file name. If you do this, it will save but not load in 5.5.
Since UE5.5
It depends on whether it is an ini file for a module or an ini file for a plugin.
If you are not familiar with the words module or plugin, you can think of a module as something other than a plugin and just look at the module part.
In the case of the module
When using the “known” categories(=file name), which the engine provides
“known” categories(=file name)?
- Example:
Engine
,Game
,Input
… - Please see this page for the entire list.
How to
- Check if there is already a Default ini file in the Config folder directly under the project folder. If not, you will need to create it using Notepad or something similar.
- The file name is
Default{CategoryName}.ini
.- For example, if you use the
Game
category, it isDefaultGame.ini
.
- For example, if you use the
- The file name is
- Check if the ini file has a
[SectionsToSave]
section. If not, add it. Most likely, it won’t. - Add
bCanSaveAllSections=true
into the section[SectionsToSave]
.- The reason for adding this is that, for modules, the default value of
bCanSaveAllSections
isfalse
. To allow saving of all classes, we need to change this to true. I will explain in detail in the separate chapter below.
- The reason for adding this is that, for modules, the default value of
The result will look like this:
The cpp code would look like this. Let’s assume we’re using the Game
category. If you’ve used Config in previous versions, this should look familiar.
If you want to use a file name other than the categories provided by the engine
Compared to the case in the previous chapter, the only difference is that you always have to add a Default ini file.
- Create a Default ini file in the Config folder right under the project folder.
- If the file name you want to use is
MyConfigCategory.ini
, create it asDefaultMyConfigCategory.ini
.
- If the file name you want to use is
- Open the file and add the section
[SectionsToSave]
andbCanSaveAllSections=true
.
The result will look like this.
The cpp code would look like this.
In the case of the plugin
- Create a Config folder in the plugin folder.
- Create
Default{plugin name}.ini
in that folder.- For example, if the plugin name is MyPlugin, it would be
DefaultMyPlugin.ini
.
- For example, if the plugin name is MyPlugin, it would be
For plugins, this is all. It’s ok even if the ini file is empty.
For plugins, unlike modules, even if there is no [SectionsToSave]
section and bCanSaveAllSections=true
, all classes are saved and loaded.
This is because the default value of bCanSaveAllSections
for plugins is true
, which is different from modules. I will explain the details in a separate chapter below.
So, what you need to do is just make a file named Default{plugin name}.ini
in your Config folder.
Instead, there is a different limitation in a plugin. Currently, without additional c++ code, you can not use an ini file name that is neither a “known” category nor the name of the plugin in a plugin.
The use of the UCLASS specifier is no different, except that only the name of the plugin can be used, as mentioned. It would look like this:
Advanced: Adding which classes are allowed to be saved to the ini file explicitly
You can explicitly add classes that you want to allow to be saved to the [SectionsToSave]
section of the ini file. This way, even if the current value of bCanSaveAllSections
is false
, the class will be saved as a Config.
However, when add the class name, you must add it without the prefix U!
For example, if you want to add only USomeClass belonging to module MyModuleName to the ini, you can do it like this:
You can also add classes to plugins. However, in the case of plugins, the default value of bCanSaveAllSections
is true
, which is the opposite of the module, so if you want to prevent saving classes other than the specified class, you must also add bCanSaveAllSections=false
to [SectionsToSave]
.
For example, as shown below. Also, note that the prefix U is removed from the class name.
Additional explanation for those who are not familiar with it
- If you don’t know what a module is, for this chapter only, you can think of it as the project name.
- Additional explanation for the added
+Section=/Script/MyPluginName.SomeClass
part
- As written in the official documentation, the
+
symbol in front of Section means that it is added to an array.- The
/Script/
part, very roughly speaking, means that the content is about c++ code.- The name following
/Script/
is the module name or plugin name.- The name of the class follows after that, without the U prefix.
Details
Rough Summary
I’ll write a very rough summary of what I’ll cover in this chapter. Please keep in mind that this summary may not always be correct, as there are many small details and exceptions.
- Load
- Without the Default ini file, the Final ini file will not load.
- Save
- The ini file of the module inherits
/Engine/Config/Base.ini
. The value ofbCanSaveAllSections
inside[SectionsToSave]
of this file isfalse
. - The ini file of the plugin inherits
/Engine/Config/Base.ini
. The value ofbCanSaveAllSections
inside[SectionsToSave]
of this file istrue
. - When the value of
bCanSaveAllSections
isfalse
in the section[SectionsToSave]
, if you did not specify which class will be saved explicitly, it will not be saved. - When the value of
bCanSaveAllSections
istrue
in the section[SectionsToSave]
, all classes will be saved.
- The ini file of the module inherits
Concept and structure which you should know
BaseIniName and several types of ini files
Default ini file
When you create a new project in Unreal Engine, the following files are created under the Config
folder in your project folder.
DefaultEditor.ini
DefaultEngine.ini
DefaultGame.ini
DefaultInput.ini
I will call these as Default ini files from now on.
BaseIniName?
Here, the parts excluding the Default
part from Default ini files, that is, the Engine
, Game
, Input
… parts are called “categories” in the official documentation.
In the code, ‘‘‘BaseIniName’’’ is used as a variable or parameter name.
Because our interest in this post is the file name, we will use the term BaseIniName in this post.
Final ini file
If you’ve created a project and have ever turned the editor on and off,
You’ll also find a few ini files in your project folder in the /Saved/Config/WindowsEditor/
folder, like this:
Editor.ini
EditorPerProjectUserSettings.ini
GameUserSettings.ini
The filename here is missing the Default
part, and just BaseIniName.
This is where your data exists, both saved and loaded. Let’s call this Final ini file.
Location of Final ini file when packaging
If you packaged your project, the path to the Final ini file will be as follows.
If not Shipping, if you ran it from C:/MyPackageFolder/
If it’s the Shipping version
Also, if you look at the engine source code, you’ll see variable names like FinalCombinedLayers
, which are completely different from the Final ini file, so don’t get confused.
Base ini file
In fact, there are more ini files in the Unreal Engine folder.
- If you are using the launcher version,
- If you haven’t changed the engine installation folder,
You can see a lot of ini files in the C:/Program Files/Epic Games/UE_5.5/Engine/Config
folder. (In my case, 34.)
There is also BaseEditor.ini
. It has Base
in front of Editor.ini
.
I will call this kind of thing Base ini file from now on.
It is different from BaseIniName. Base ini file is an ini file with the string Base
added in front of BaseIniName.
(I know. Around here, it is a bit confusing.)
Hierarchy of ini file
How ini files are combined, in rough
In short, to make the content of the file where BaseIniName is Editor
and final ini file is Editor.ini
, the following files are involved.
BaseEditor.ini
: Folder/Engine/Config
in the engine, Base ini fileDefaultEditor.ini
: Folder/Config
in the project, Default ini fileEditor.ini
: Folder/Saved/Config/WindowsEditor/
in the project, Final ini file
The engine reads the above files in order and combines them to create the result about BaseIniName Editor
.
If there are different values for the same item, the later value will overwrite the previous value.
(Note that not all values are saved, only the contents that have changed from the default value of ClassDefaultObject are saved.)
But that’s not all.
Hierarchy of ini file - in the case of the module
If we list the places where ini files are read through debugging, this is what we get:
It reads from 80 locations.
In addition to the engine’s defaults, the project’s defaults, and the project’s saves, we can also change the contents of the ini file depending on your platform. Also, we can see some items that lead us to guess that it might be changed depending on the license of the engine. Additionally, we can see several items that look like some intermediate files of the engine.
If you want to see the source code for the part where this is created, see this footnote. 1
Hierarchy?
The variable name in the engine for the list in the example above is Hierarchy
. So in this post, we’ll call that list as Hierarchy. (Note that it’s in class FConfigBranch
, and technically, the type of Hierarchy
is class FConfigFileHierarchy
, which inherits from TMap<int32, FString>
).
Hierarchy of ini file - in the case of the plugin
In the case of the plugin, the rules are the same, but the content is different.
When reading an ini file belonging to a plugin, the list of Hierarchy that it attempts to load is like below.
It’s much shorter than a module!!!
If you want to see the source code of where this part is created, see this footnote 2
Hierarchy and final ini files are separate
But… Something seems to be missing, yes. In the above Hierarchy, there is no Final ini file, which is most important to us.
In the example above, Final ini file for MyIniNameInModule
must be in folder /Saved/Config/WindowsEditor/
, which is under the folder of the project folder, E:/GitHubDesktop/MyProjectName/
. In the case of the module, it should be MyIniNameInModule.ini
. In the case of the module, it should be MyIniNameInModule.ini
. In the case of the plugin, it should be MyIniNameInPlugin.ini
.
And our editor or PIE game saves config things into that ini file.
As per the example above, the path to the ini for the module and the ini for the plugin would be one of the following (the locations were explained before.
At now, let’s remember that Hierarchy and Final ini file are separate.
Why ini file not saved
The reason is that the result value of the bCanSaveAllSections
item in the [SectionsToSave]
section becomes false
, when all the ini files of Hierarchy and the final ini file are combined.
ini save behavior
First, the flow rules of the code are as follows. The engine has a class called FConfigFile
that contains the contents of the ini file. And,
- If the
bCanSaveAllSections
value ofFConfigFile
istrue
,- Any class can be recorded in the ini file.
- If the
bCanSaveAllSections
value ofFConfigFile
isfalse
,- Only the classes explicitly specified in
[SectionsToSave]
can be saved in the ini file.- If the class is not explicitly specified in
[SectionsToSave]
when saving, the contents for the class are deleted.
- If the class is not explicitly specified in
- Only the classes explicitly specified in
The default value of bCanSaveAllSections
when creating FConfigFile
is true
. And right after creation, the engine reads the value of bCanSaveAllSections
from the ini file and writes it here. (Actually, there is some additional processing, which will be covered later in this post.
Now, let’s look at it in more detail, per module and plugin.
Why ini file not saved, in the module
We can see this if we open the engine’s /Engine/Config/Base.ini
. It just says the following there. (If you actually open it, there are comments and other content, but I omitted them here.)
All modules’ ini files inherit this. Because, the first entry in the module’s Hierarchy is always /Engine/Config/Base.ini
.
Therefore, if you want to save something in the module’s ini file,
- At the later order of Hierarchy,
- We must overwrite the value of
bCanSaveAllSections
in the[SectionsToSave]
section withtrue
, or - We must add the name of the class explicitly.
- How to explicitly add a class name has been described previously.
- We must overwrite the value of
Just in case, I added bCanSaveAllSections=true
to the Final ini file and tested it. I saw that it worked properly. In this case, even if the value of bCanSaveAllSections
inherited from the previous files in the Hierarchy was false
, it was saved.3
Why ini file succeed to save, even if bCanSaveAllSections=true
is not added
Unlike modules, all plugin ini files inherit from the engine’s /Engine/Config/PluginBase.ini
. As you might expect, its contents are as follows. (Of course, if you open this file, you’ll find comments and other content, but I’ve omitted them here.)
So, contrary to modules, the default value of bCanSaveAllSections
in ini of the plugin is true
. If we want to restrict the classes that will be saved in the ini file in our plugin, we need to overwrite this value to false
.
Why ini file not loaded
ini load rule
- Before reading ini,
- Among the paths in Hierarchy,
- If there are no files that exist actually, except the first entry in Hierarchy,
- It does not load Final ini file.
Note that the first entry in Hierarchy, mentioned in point 3 above, is Engine/Config/Base.ini
for modules, and Engine/Config/PluginBase.ini
for plugins. What this file is is important for saving, but not for loading. In the contrary, it is important to remember that the existence of the file is always guaranteed, and it is excluded from counting the number of files loaded at the same time. In other words, except for this first entry, there must be at least one entry somewhere, otherwise final ini file will not load.
For the call stack for the ini load failure, see the following footnote:4
ini load failure in the module
As a result, if there is one file that needs to be added statically for a project in the module’s Hierarchy, it is the Default ini file, which will be placed under the Config folder in the project folder. So if we didn’t add this file, in most cases the Final ini file would not be able to be loaded.
In theory, adding a Base ini file for BaseIniName to the engine folder might make the final ini file load. However, unless you have very specific requirements for versioning conditions, it’s probably better for these files to exist in the project folder rather than the engine folder.
ini load failure in the plugin
The manner in which plugins read ini is slightly different from modules.
When using an ini file in a plugin, if the name of the ini file is in a “known” category, it behaves the same as a module.
On the other hand, in the plugin, if you are not using additional c++ code, and if you are not using the “known” category, the following restriction is coming.
- In the plugin, only the ini file with the same BaseIniName as the name of the plugin is available.
- Also, to load this ini file, the Default ini file for this must be added to the Config folder in the plugin folder.
- This is because of the rule we mentioned above.
For example, if the name of the plugin is MyPlugin
,
- If you add
DefaultMyPlugin.ini
to theConfig
folder in the plugin folder, as the Default ini file - Then, the Final ini file
MyPlugin.ini
will be loaded.
This is because, when the engine starts, it only loads the Default ini file based on the plugin’s name. See the following comments for the relevant source code and callstack: 5
More detail: GConfig, FConfigCacheIni, FConfigBranch
The specific location where the ini file is stored in the engine is the global variable GConfig
:
GitHub Link
The type of this is FConfigCacheIni
.
FConfigCacheIni
has many items of FConfigBranch
inside it, which contains the data corresponding to the BaseIniName. The engine loads the ini file, puts it into this FConfigBranch
for it to use, and when it needs to save the ini file, it saves the contents of this FConfigBranch
to a file. Please note that only the contents that are different from the default value will be saved. Items with the same value as ClassDefaultObject will not be saved.
Other things I want to record
Example of reading a plugin’s ini file inside engine source
You can see an example of reading a plugin’s ini file from the engine source in the ChaosVD
plugin.
GitHub Link
Because this plugin has bCanSaveAllSections=true
at the top of its DefaultChaosVD.ini
, you may think that you need to add bCanSaveAllSections=true to your plugin as well. However, for the reason mentioned earlier, you don’t need to add this.
Small Exception to bCanSaveAllSections
This is something I covered in a previous post. The engine sets the final value of bCanSaveAllSections for an ini file with the following code: (I’ve summarised the code a bit, you can see the full code at the GitHub Link )
In other words, it will save everything without restricting what is saved in the following situations.
bCanSaveAllSections
in the ini file istrue
- Or BaseIniName contains the string
User
- Or BaseIniName is not
Editor
and contains the stringEditor
.- For example,
Editor
is not ok, butEditorSettings
is ok.
- For example,
Different behavior of EditorLayout
Among the BaseIniNames, EditorLayout
behaves a little specially.
Firstly, it has a different location where it is saved. It is saved in the following folder
C:/Users/MyUserName/AppData/Local/UnrealEngine/5.5/Saved/Config/WindowsEditor/EditorLayout.ini
In the engine, there is a structure called FLayoutSaveRestore
that is responsible for saving and loading BaseIniName. FLayoutSaveRestore
primarily uses the Json format for saving and loading the editor’s layout. It also uses the ini format, but only as a secondary means of backwards compatibility.
In addition, unless you add some separate c++ code, if you save something in EditorLayout
, the saved content will be erased the next time the editor is closed.
Assuming the user has saved something in EditorLayout, let’s follow the steps below.
Load 6
- If there is an Editor layout saved in Json, the engine will use the content saved in Json.
- In this case, the ini file is not read, which means that the content of the ini for the
EditorLayout
inside GConfig will is empty. We assume that we have passed this case.
- In this case, the ini file is not read, which means that the content of the ini for the
- If no Editor Layout is stored as Json, the Editor Layout is read from the ini file and used.
Save 7
- Save as both Json and ini.
- If the engine used the data loading from the Json format, the ini content for the
EditorLayout
inside GConfig is empty. Engine adds the contents of our new Editor Layout to this empty content, and then overwrites it in the ini file forEditorLayout
.
- If the engine used the data loading from the Json format, the ini content for the
This is a typical data loss that occurs when saving without loading.
Therefore, do not use EditorLayout
for anything other than its intended purpose. I recommend that you use the EditorLayout
only through FLayoutSaveRestore
.
After ini fails to load, ini file is deleted in package builds only, if ini contents are not modified
This difference can be observed by looking at the behaviour of the Config for UCustomButBaseNameHasUser
in the sample project.
The original purpose was to test the case where the name of the ini file contains User
and at the same time the Default ini file does not exist. However, I noticed that the behaviour is different when in the editor and when in a package build. While this is unlikely to happen in the intended usage scenario, I wanted to make a note of it for reference in case I encounter a similar case.
The conditions that cause the difference, and the difference itself, are as follows.
- Set a string containing User in the BaseIniName, and not setting a Default ini file.
- After running the editor or the packaged build, change the value of the object and save the contents to an ini file.
- Close the editor or the packaged build.
- Run again the editor or the packaged build. At this point, the ini file is not loaded because there is no Default ini file.
- Close the Editor or the packaged build without doing anything. At this point,
- The ini file of the editor will remain as it was previously saved.
- The ini file of the package build is deleted.
Cause: Value of the variable Dirty
in FConfigFile InMemoryFile
This difference depends on the value of Dirty
in FConfigFile InMemoryFile
inside FConfigBranch
, which exists inside GConfig.
- The value of
Dirty
in theFConfigFile
isfalse
at construction time. - In the editor, the value of
Dirty
remainsfalse
if there are no changes. - However, in package builds, the value of
Dirty
is set totrue
right after the load.
The location ini file is deleted
This difference affects the saving process of ini files as follows.
- If the value of Dirty in InMemoryFile is false, the function exits at the beginning of the function.
- If the Dirty value of InMemoryFile is true, the engine processes what is saved in the ini file. If its length is zero, the engine deletes the file.
The difference in this saving process can be seen in the code of the static bool SaveBranch(FConfigBranch& Branch)
in Source/Runtime/Core/Private/Misc/ConfigCacheIni.cpp
.
GitHub Link
At the beginning of the code, at line 866, if Branch.InMemoryFile.Dirty
is true
, it exits.
Later in the code, if the length of the output to save is zero and bBuiltString
is false
, there is a part that removes the file.
The call stack at this point looked like this.
The location of the Dirty value of FConfigFile InMemoryFile changes right after loading
The reason why the value of Dirty
of InMemoryFile
becomes true
only in package builds after loading the ini is as follows.
- First, the value of the global variable
GDefaultReplayMethod
is different between the editor and the package build: GitHub Link - Based on the value of
GDefaultReplayMethod
, the value ofReplayMethod
, which isFConfigBranch
’s member variable, is set differently inFConfigBranch
constructor. GitHub Link - The value of
ReplayMethod
, which is theFConfigBranch
’s member variable, determines how the ini file is read from theFConfigContext::LoadIniFileHierarchy
function and written to theInMemoryFile
. This is where the difference occurs. GitHub Link
Let’s split the chapters once, and then continue with the explanation.
What Happens in FConfigContext::LoadIniFileHierarchy
To summarise, this is because FConfigFile::ApplyFile
doesn’t copy the value of Dirty
.
What happens in FConfigContext::LoadIniFileHierarchy
, unless Branch->ReplayMethod
is EBranchReplayMethod::NoReplay
, is roughly like this.
- It reads the contents of the ini file, and writes it to
Branch->CombinedStaticLayers
. - It copys the contents of
Branch->CombinedStaticLayers
toBranch->InMemoryFile
.
The function used to read the ini file here is different depending on the value of Branch->ReplayMethod, which is determined by whether it is the editor or the package build.
Either way, it will call FillFileFromBuffer in the ConfigCacheIni.cpp file.
And in this FillFileFromBuffer
function, the value of Dirty
is set to true
.8
For package builds, i.e., when Branch->ReplayMethod
is EBranchReplayMethod::DynamicLayerReplay
, the content read from the ini file is written directly to itself via FConfigFile::FillFileFromDisk, a member function of CombinedStaticLayers
.
But in the editor, that is, if Branch->ReplayMethod
is EBranchReplayMethod::FullReplay
,
- It adds a new
FConfigCommandStream
item toBranch->StaticLayers
. - Using the
FConfigCommandStream::FillFileFromDisk
function, it writes the contents read to the addedFConfigCommandStream
item, - And it uses
FConfigFile::ApplyFile
function to copy from theFConfigCommandStream
item toBranch->CombinedStaticLayers
.- But, the
FConfigFile::ApplyFile
function does not copy the value of theDirty
variable in theFConfigCommandStream
to theDirty
in theFConfigFile
. Because of this, theDirty
inBranch->CombinedStaticLayers
will remainfalse
if the engine goes through this route.
- But, the
Either way, the FConfigContext::LoadIniFileHierarchy function ends with the contents of Branch->CombinedStaticLayers copied to Branch->InMemoryFile.
And as mentioned at the beginning, whether or not the engine can arrive to the part where the engine deletes the file depends on what the Dirty value of FConfigBranch’s InMemoryFile is.
Note
I started this post because I thought that my future self would definitely get confused or make mistakes in this area again. To be honest, this is not the first time I have spent a long time debugging Config ini files since I started using Unreal Engine. It has happened many times. I will do in future some times. That is why I am writing this.
If you find anything wrong with this post, please let me know!
-
If you want to see how this Hierarchy is created, see below.
- Function
void FConfigContext::AddStaticLayersToHierarchy
GitHub Link - Global variable array
FConfigLayer GConfigLayers
GitHub Link
Here’s an example of the call stack when Hierarchy is created:
↩︎ - Function
-
In the caste of the plugin, creation of the Hierarchy is done by the same function
void FConfigContext::AddStaticLayersToHierarchy
GitHub Link as in the case of the module above. However, since the calling time and conditions are different, it is based onFConfigLayer GPluginLayers
GitHub Link instead ofFConfigLayer GConfigLayers
.This part is done through a separate process, much faster than the loading of the previous module plugin. The call stack is as follows:
↩︎ -
I felt like I had committed a great sin, so I removed it as soon as I tested it.
Why this is a huge sin is because this is a file that is not usually put into version control and is often changed by editors or packaged programs. If you put
bCanSaveAllSections=true
here and think your ini file is saving properly, and then later on, either in a packaged program, or in someone else’s place, or if you delete all your existing ini files and get new work from a new version control program, you will suddenly find that your ini file, which was saving fine up to that point, won’t save. It’ll be a pain to find out why, and when you do, you’ll probably blame yourself. ↩︎ -
The call stack when ini load fails is as below. Because
↩︎LoadIniFileHierarchy
returnsfalse
, it can not reach the part where the Final ini file is loaded inGenerateDestIniFile
. GitHub Link This is an example for modules, but it shouldn’t be much different for plugins: the highlighted part of the call stack below would be the same. -
Here is the code that loads the ini for the plugin: GitHub Link You can see that it only loads the ini file for the name of the plugin.
The call stack at this point is as follows:
↩︎ -
You can see the code for saving
EditorLayout
here: GitHub LinkIt saves the contents to GConfig and saves it as a separate file as Json.
The call stack at the time of saving is as follows.
↩︎ -
You can see the code for loading
EditorLayout
in this link.: GitHub Link If loading with json succeeds, it does not read the ini file.Below is the call stack when loading.
↩︎ -
This is where the
Dirty
value changes totrue
when loading the ini file.Code: GitHub Link
Whether it is run in the editor or in the package build, the point where the
Dirty
value changes totrue
is the same.The call stack looks slightly different when in the editor and the packaged build, but the overall shape is similar.
The call stack in the package build is as follows. Note that line number 988 in the call stack
FConfigContext::LoadIniFileHierarchy()
is incorrect. The correct location is line 973. This is probably due to compiler optimization.Below is the call stack in the editor.
↩︎