How to implement C++ classes that running at Editor Startup?

I like to create a script that checks engine settings on startup.

At my research I come to the EditorUtilitySubsystem from the Blutility module that can run Blueprints at startup Documentation.

After short tests (what works well) i tried to do build some of this script in pure c++. Than for the check later it’s only possible to at access to this in code not via BP Nodes and to expose own nodes (BlueprintCallable) is a unnecessary step.

RunSomethingOnStartupCode.h

#pragma once

#include "EditorUtilityObject.h"
#include "RunSomethingOnStartupCode.generated.h"

UCLASS()
class RUN_ON_STARTUP_TEST_PRJ_API URunSomethingOnStartupCode : public UEditorUtilityObject
{
	GENERATED_BODY()

	void Run();
};

RunSomethingOnStartupCode.cpp

#include "RunSomethingOnStartupCode.h"

void URunSomethingOnStartupCode::Run()
{
    UE_LOG(LogTemp, Warning, TEXT("Code test"));
}

To trigger this class I add a entry for it in the DefaultEditorPerProjectUserSettings.ini like for a BP variant. But i point to the class it self.

[/Script/Blutility.EditorUtilitySubsystem]
StartupObjects=/Script/RunOnStartupTestPrj.RunSomethingOnStartupCode

After compile and a engine restart i get following output:

LogEditorUtilityBlueprint: Warning: Missing function named ‘Run’: /Script/RunOnStartupTestPrj.RunSomethingOnStartupCode

In the implementation of the UEditorUtilitySubsystem::TryRun i have checked that the class get found and also the instance gets created. Looks like only the FuncMap don’t find the Run function implementation.

Has someone solved this issue already?

Additional approaches that i have tested:
Own ‘UEditorUtilityObject’ class that implement all necessary function like the original with ‘BlueprintNativeEvent’ that allow me to define a default implementation. But this ends in the same result.

Just in case anyone else is googling this. There are two important things that need to happen.

  1. Your Run() needs to be proceeded by UFUNCTION()

    UCLASS()
    class MYPROJ_API UMyEditorUtility : public UObject
    {
    GENERATED_BODY()

    public:

     UFUNCTION()
     void Run();
    

    };

  2. When you set the path to your class, ‘MyProject.MyClassName’ will actually point to the UClass object itself, rather than an instance of the object. You can point to the default object instance like this:

    [/Script/Blutility.EditorUtilitySubsystem]
    StartupObjects=/Script/MyProject.Default__MyEditorUtility

Note that ‘Default__’ has two underscores. Also note the ‘/’ at the start of the path, that’s important.

If you don’t know the path to the class you can find it in the content browser under ‘C++ classes’ and then right click → copy reference.

1 Like

Works like a charm, the ‘Default__’ is the main trick.