I have a 5.3/5.4 plugin that I’m trying to add 5.5 support to. I’m encountering an issue when reading config settings from the saved directory. When spawning an instance of the settings object, the members are all set to empty. In 5.3/5.4, they would be populated from the INI file.
My settings file is a UObject with some public data:
UCLASS(Config = MyPlugin)
class MYPLUGIN UCharacterSettings : public UObject
{
GENERATED_BODY()
public:
#if WITH_EDITOR
// Called when a property on this object has been modified externally
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
// The path of the last used Character file
UPROPERTY(Config)
FString CharacterFilePath;
}
I create a default instance of this whenever it is needed. The data is then read/modified, and re-saved. Strangely, in 5.5, the initial values are empty, but once they are set and saved, it does update the INI file correctly. It also retains the edited information when read later. Once the editor is restarted, it is all empty again.
// Get the currently stored settings
UCharacterSettings* CharacterSettings = GetMutableDefault<UCharacterSettings>();
// Do some stuff
// Save changes
CharacterSettings->SaveConfig();
I’ve also tried using the GetIni command, to read the data directly from the file. Prior to editing the settings data, it will also return empty. Once the data has been edited and saved, it does return the correct values until the editor is restarted.
I have tried manually calling LoadConfig() on the instance prior to reading from it, however this does not appear to make any difference. The file name appears to be correct when saving, so I don’t think it fails to load for that reason.
Does anyone have an idea about what may be causing this?
I ended up manually pre-loading the config file. This involved getting the path to my ini file, loading it into GConfig, then creating an instance of the settings object and calling load config on it.
I’m not sure this is the best solution, but it does resolve the problem for now.
// Get the INI path from <ProjectDir>/Save/Config/<Platform>/MyPlugin.ini
FString ConfigPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Config"), FPlatformProperties::PlatformName(), TEXT("MyPlugin.ini")));
// Attempt to load the config file
GConfig->LoadFile(ConfigPath);
// Populate settings object from loaded data
UCharacterSettings * CharacterSettings = GetMutableDefault<UCharacterSettings >();
UCharacterSettings ->LoadConfig();
I’ve made PR, you can either merge it or wait until some other kind of fix comes in, but with this change you don’t have to load every config file you are using explicitly, but it’s still a nice workaround.
A bit sad that without engine source there is not much else that can be done I guess, but once I found this I haven’t bothered spending any more time on the issue so who knows.
In case someone does not have github access (which would be weird tbh ):
Fix is to move the
if (KeyWithoutFlags != 0)
{
bReadAnyFile = true;
}
or (depending on your engine version)
if (HierarchyIt.Key != 0)
{
bReadAnyFile = true;
}
in ConfigContext.cpp before the // skip non-existant files if block, which gets hit all the time and starts the loop again.
EDIT: Yea loading works just fine but saving doesn’t which is just eh. I know it’s related to this, but idk why it matters only when that if is moved.
EDIT2: Ah ok, so because I allow it to load this line FinalFile.bCanSaveAllSections = bLocalSaveAllSections || bIsUserFile || bIsEditorSettingsFile; in ConfigContext.cpp is executed which changes the default boolean. So basically the config system is broken af atm.
Edit3: I just did this FinalFile.bCanSaveAllSections = true;//bLocalSaveAllSections || bIsUserFile || bIsEditorSettingsFile; in ConfigContext.cpp and am done with it. I have no idea why they would implement such a feature without a notice or option to specify to save all sections from the uobject. I don’t believe there are not hundreds of broken projects now. Anyway this works.