GUnrealEd is NULL in StartupModule

at least as of UE 5.2.1:

You cannot rely on setting the plugin’s loading phase to PostEngineInit to guarantee the existence of GEditor inside StartupModule()!

Plugins will load at the earliest loading phase in their chain of dependencies, meaning the actual loading phase used by a plugin can become earlier than the loading phase set in the .uplugin settings!

i.e. GEditor may not exist (yet) when the plugin is initialized.

Example

  1. Suppose we have a Plugin A which loads in Default.
  2. A new Plugin B is added that depends on Plugin A. Plugin B loads in PreDefault.
  3. Now Plugin A will be loaded in PreDefault, along with Plugin B.
  4. Plugin A may suddenly and mysteriously start breaking as a result.

This can be rather surprising and is hard to figure out what’s wrong if you weren’t thinking about Plugin A when changing Plugin B’s loading phase or dependencies.

Workaround

A more reliable way to access GEditor on module startup is to listen on the PostEngineInit delegate explicitly using FCoreDelegates::OnPostEngineInit.

 FCoreDelegates::OnPostEngineInit.AddRaw(this, &FMyModule::OnPostEngineInit);

Do note that if the loading phase is PostEngineInit, then the OnPostEngineInit delegate will have already fired! so your OnPostEngineInit callback will not be executed in that case.

If you’re not worried about this, you can simply use an earlier loading phase, e.g. "Default" and always use the delegate, as the loading phase cannot get later than what’s specified in .uplugin, only earlier, IIUC.

void FMyModule::OnStartup() {
  // wait for GEditor to be ready
  FCoreDelegates::OnPostEngineInit.AddRaw(this, &FMyModule::OnPostEngineInit);
}

However if you want to ensure fewer surprises when changing loading phases in the future, you can wait for GEditor if it’s missing, or run your init immediately if GEditor is already around:

void FMyModule::OnStartup() {
  if (GEditor) {
    OnPostEngineInit(); // GEditor ready, init immediately
  } else {
    // wait for GEditor to be ready
    FCoreDelegates::OnPostEngineInit.AddRaw(this, &FMyModule::OnPostEngineInit);
  }
}

With this you should be able to adjust dependencies and loading phases without creating as many load order issues in other plugins.

edit: Also see this good suggestion from @Engelard:

3 Likes