Filtering actors in plugin::StartupModule()

Hi folks

In my plugin I would like to iterate and filter actors in plugin::StartupModule(). Following 's example I’m doing this as a simplified test in a vanilla Toolbar Button plugin:

	auto World = GEditor->GetEditorWorldContext().World();
	for (TActorIterator<AStaticMeshActor> ActorItr(World); ActorItr; ++ActorItr)
	{
		AStaticMeshActor* Mesh = *ActorItr;
		UE_LOG(LogTemp, Warning, TEXT("%s"), *ActorItr->GetName())
	}

These lines do exactly what I need if I have them PluginButtonClicked() but for some reason there are no Actors logged if I place the same lines in StartupModule(). I suspect this relates to which context/worlds exists at the time of StartupModule(). My .uplugin has “LoadingPhase”: “PostEngineInit” which solved a previous nullptr issue.

I don’t want to do this in PluginButtonClicked() because I need a one-time expensive call to the Shotgun api which builds the data-model that drives my menu extenders. StartupModule() seems like the right place but perhaps there is a better option, perhaps something post-load but pre-click.

Any help much appreciated

PostEngineInit just means the Engine has been initialized, but not that a world has actually been created.

You can see a list of the various phases and their descriptions here.

It’s difficult to give you direction as I don’t know the requirements for your call. If you just need a valid world, you could look into hooking into something like OnPostWorldInitialization. But if you need to make that call every time someone adds/removes a Static Actor, then maybe doing it in a background or finding some hook for when an object is added to the world (I’m sure there is one - I just can’t remember one off the top of my head) would be better.

There no way to do so from module start up since all modules get loaded before world is initiated. You can detect when world is initiated by binding to this event:

You can also detect world destructions:

Keep in mind that in editor it will be triggered multiple times and contain different irreverent worlds, as Editor and PIE world is seperete and all previews are also creating own new world to display things, so use IsGameWorld to detect game world.

As i remember PIE world get destroyed once you turn off play mode and new one is created in another rime, this will also happen on level change even in game builds if im not mistaken so prepare your code for world swaps.

Thanks Matt, that’s exactly what I needed

In StartupModule()

FWorldDelegates::FWorldInitializationEvent::FDelegate OnWorldCreatedDelegate;
OnWorldCreatedDelegate = FWorldDelegates::FWorldInitializationEvent::FDelegate::CreateRaw(this, &FMyPlug::OnWorldCreated);
FDelegateHandle OnWorldCreatedDelegateHandle = FWorldDelegates::OnPostWorldInitialization.Add(OnWorldCreatedDelegate);

With

void FMyPlug::OnWorldCreated(UWorld* World, const UWorld::InitializationValues IVS) {

	for (TActorIterator<AStaticMeshActor> ActorItr(World); ActorItr; ++ActorItr)
	{
		AStaticMeshActor* Mesh = *ActorItr;
		UE_LOG(LogTemp, Warning, TEXT("%s"), *ActorItr->GetName())
	}

}

And the delegate somehow gets and passes the UWorld reference itself so no need for

auto World = GEditor->GetEditorWorldContext().World();

anymore.

I found a nice usage example here:

Funny how once you know the name of the thing you’re looking for, it all falls into place. Thanks for your help!

Awesome, thanks for the extra links, my solution is above and I’ll keep an eye out for world swaps