Using PerObjectConfig

Hi,

had a couple of questions about PerObjectConfig.

  1. Is it supposed to work with classes derived from UObject or only AActor subclasses?

  2. Whats the proper way to create the objects specified in your config file?

From code the only way I could see would be to use GConfig to look up the names from the config file and then spawn Actors with the appropriate names?

From the editor would you just place an object and set its name to be something in the config file?

The reason I ask is that in UDK it was possible to manually type a bunch of configurations into a config file, and then at runtime get an array of objects initialised to your configurations via single unrealscript function call.

It was just an easy way to get a bunch of data into the game.

cheers

PerObjectConfig looks like some obscure Unreal Engine feature that no one talks about (this is the first result when searching “unreal engine PerObjectConfig” on Google). I myself lost many days trying to figure it out. I give an answer in the hope that it will spare some time to someone else.

I tested successfully this feature with the version 4.24.3.
Place an actor MyActor in the level.


UCLASS(Config = Game, PerObjectConfig)
class TEST2_API AMyActor : public AActor
{
    GENERATED_BODY()
protected:
    UPROPERTY(EditAnywhere, Config)
    FString SomeString;
public:
    AMyActor();
protected:
    virtual void BeginPlay() override
    {
        Super::BeginPlay();
        if (this->GetName() != TEXT("FooBar")) {
            FActorSpawnParameters Params;
            Params.Name = TEXT("FooBar");
            // Params.ObjectFlags = EObjectFlags::RF_Transient; // This line has no effect
            // The actor we placed (MyActor1) will spawn another MyActorr called FooBar
            this->GetWorld()->SpawnActor<AMyActor>(Params);
        }
    }
};

In order to config use the following (inside Config/DefaultGame.ini or another file set in the UCLASS macro)



[LevelName:PersistentLevel.MyActor_1 MyActor]
SomeString = "This is MyActor1"

[LevelName:PersistentLevel.FooBar MyActor]
SomeString = "This is FooBar"



Hit play and verify that it works also for the spawned actor:

As you can see the name of the section in the .ini file is quite different from what is told in the documentation [ObjectName ClassName].
For more details look at the method (UObject::LoadConfig) this is the one called when (automatically) loading documentation from configuration files.


const bool bPerObject = UsesPerObjectConfig(this);
// ...
if (bPerObject)
{
    FString PathNameString;
    UObject* Outermost = GetOutermost();

    // line 2171 at the time of writing
    if (Outermost == GetTransientPackage())
    {
        PathNameString = GetName();
    }
    else
    {
        GetPathName(Outermost, PathNameString);
        LongCommitName = Outermost->GetFName();
    }

    ClassSection = PathNameString + TEXT(" ") + GetClass()->GetName();

    OverridePerObjectConfigSection(ClassSection);
}

The issue is at the highlighted line: if the object is part of the transient package then its expected section name uses the GetName(), otherwise GetPathName(…). I tried without success setting EObjectFlags::RF_Transient in the Object flags of the spawned actor parameters.

Finally, to answer question 1, Yes it is supposed to work with UObject derived classes (I didn’t test it though). Just figure out what is object’s GetOutermost() result and the difference of per object section naming in case it is part of the transient package.