Spawn actors in multiple threads

I have a blueprint function that spawns an actor after several checks, and I want to spawn very many actors, so I want to do this in multiple threads. As I know, multithreading is only possible either with C++ or with plugins that can be installed only on certain UE version, and if development of the plugin stops, the money is lost. So I have written the following C++ code to spawn the actors in parallel for:

#pragma once

#include <CoreMinimal.h>
#include <UObject/NoExportTypes.h>
#include <Kismet/GameplayStatics.h>
#include <GameFramework/GameMode.h>
#include <Misc/OutputDeviceNull.h>
#include "(XXX).generated.h"

/**
 * 
 */
UCLASS(Blueprintable)
class (XXX)_API A(XXX)Spawner : public AActor
{
	GENERATED_BODY()

	UFUNCTION(BlueprintCallable)
	void Spawn(TSubclassOf<AActor> ActorClass, int32 Count)
	{
		ParallelFor(Count, [&](int32 i)
		{
			FOutputDeviceNull ar;
			Cast<AGameMode>(UGameplayStatics::GetGameMode(GetWorld()))->CallFunctionByNameWithArguments(TEXT("Spawn(XXX) ???"), ar, NULL, true);
		});
	}
};

What should I write instead of question marks if the function parameter is actor class reference? And will the blueprint function really work in multiple threads? @ClockworkOcean, @Everynone, please help!

Bump. The topic is actual.

Blueprint only runs on the main thread. It’s hard enough spawning objects on an async thread. Spawning actors is probably harder.

You’re probably trying to optimize too early and something that doesn’t need to be optimized…

Nothing. Don’t use CallFunctionByNameWithArguments to call functions. Make a custom game mode type in native with a blueprint implementable event with the parameters that you want to be able to pass in.

Hello! I have done in that way, and now the overridden function is called and produces the following errors:

Script Stack (1 frames) :
/Game/<ProjectName>/Core/7Pillars/MyGameMode.MyGameMode_C.SpawnResourceActor

[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:802][592]LogWindows: Error: appError called: Assertion failed: IsInAsyncLoadingThread() [File:D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 3150] 


[2024.09.07-20.05.38:803][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:803][592]LogWindows: Windows GetLastError: Операция успешно завершена. (0)
[2024.09.07-20.05.38:803][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
[2024.09.07-20.05.38:803][592]LogSpawn: Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)

(The rest of the log is not linked with this task.)
MyCppGameMode.cpp:

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyCppGameMode.h"

void AMyCppGameMode::Spawn<ClassName>_Implementation(TSubclassOf<AActor> Class)
{
}

MyCppGameMode.h:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameMode.h"
#include "MyCppGameMode.generated.h"

/**
 * 
 */
UCLASS(Blueprintable)
class <ProjectName>_API AMyCppGameMode : public AGameMode
{
	GENERATED_BODY()

	UFUNCTION(BlueprintCallable)
	void Spawn<ClassName>sCpp(TSubclassOf<AActor> Class, int32 Count)
	{
		ParallelFor(Count, [&](int32 i)
			{
				Spawn<ClassName>(Class);
			});
	}

public:
	UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "CPP Overridable", meta = (ForceAsFunction))
	void Spawn<ClassName>(TSubclassOf<AActor> Class);
};

How to fix this?

By not trying to spawn actors in an async process. That’s what this means Error: appError called: Assertion failed: IsInAsyncLoadingThread() , you’re not meant to do this. Only the AsyncLoadingThread (which you can’t add work to) is supposed to do this.

Warning: SpawnActor failed because we are running a ConstructionScript (<ClassName>_C)
This seems like a suspicious warning as well that you’re calling spawn from the wrong place in a blueprint even if you weren’t trying to do the async spawning.

Another way to optimize actor spawning is using soft references, when an actor is spawned make it load its decencies asynchronously, for example the static mesh and whatever materials it may need all loaded asynchronously with soft references/classes.

Hello @KaidoomDev! Can you explain this in a more detailed way? Maybe there is a manual how to do this?