SpawnActor fails, but still returns valid Pointer?

This is odd.

I’m Spawning an Actor using UGameplayStatics::BeginDeferredActorSpawnFromClass(). I’ve set this up so that it fails if there is any collision on the spawned actor.

Spawning ultimately fails, because there is encroaching geometry (which is what I want) - but the GameplayStatics function still returns a pointer to a valid new actor? How is that possible?

I checked the log, and the following line is printed:

SpawnActor failed because of collision at the spawn location [%s] for [%s]

When checking the Source Code, this appears in LevelActor.cpp - line 419:

	if (EncroachingBlockingGeometry(Template, FinalRootLocation, FinalRootRotation))
	{
		// a native component is colliding, that's enough to reject spawning
		UE_LOG(LogSpawn, Log, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *FinalRootLocation.ToString(), *Class->GetName());
		return nullptr;
	}

As you can see, the Spawn SHOULD be returning nullptr as soon as it prints this message, but it doesn’t! How am I supposed to check whether my actor was properly spawned or not?

Okay I’ve worked out why. Because I’m using deferred spawning, the actor is actually created then destroyed in the Actors own PostActorConstruction function.

That seems incredibly inefficient to spawn the actor anyway even though the code knows it can’t spawn. Why is this done?

It seems as though line 416 in LevelActor.cpp isn’t functioning as it should be.
EncroachingBlockingGeometry(Template, FinalRootLocation, FinalRootRotation)

Alright so further investigation, I tried with regular old GetWorld()->SpawnActor() and it STILL spawns then destroys the actors?!

Line 416 in LevelActor.cpp doesn’t work at all!

Final post. The following check in LevelActor.cpp ALWAYS passes, no matter what actor you try to spawn. This definitely feels like a bug.

	if (EncroachingBlockingGeometry(Template, FinalRootLocation, FinalRootRotation))
	{
		// a native component is colliding, that's enough to reject spawning
		UE_LOG(LogSpawn, Log, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *FinalRootLocation.ToString(), *Class->GetName());
		return nullptr;
	}

Hey -

Can you provide the full code you’re using for this test? How are you testing if the pointer is valid after spawn? Please provide full steps to help reproduce the behavior you’re seeing locally.

Hey , this is the code I’m using to Spawn the Actor:

AActor* SpawnedObj = UGameplayStatics::BeginDeferredActorSpawnFromClass(this, CurrentlySelectedItem.ActorToSpawn.Get(), SpawnTransform, CurrentlySelectedItem.SpawnHandlingMethod, nullptr);
		if (SpawnedObj)
		{
			SpawnedObject = SpawnedObj;
			UE_LOG(LogST_Spawn, All, TEXT("%s Spawned Object: %s"), *GetNameSafe(this), *GetNameSafe(SpawnedObject.Get()));

			NumSpawnsAttempted = 0;

			SimulateSpawn();
			if (bNotifyClientsOnSpawn)
			{
				Multi_SimulateSpawn();
			}

			if (SpawnTracking == ESpawnTracking::ST_NoTracking)
			{
				const float NextDelay = GetNextSpawnDelay();
				GetWorldTimerManager().SetTimer(Handle_SpawnTimer, this, &AST_SpawnPoint::OnTrySpawn, NextDelay, false, NextDelay);
			}
			else
			{
				GetWorldTimerManager().ClearTimer(Handle_SpawnTimer);
				GetWorldTimerManager().SetTimer(Handle_CheckSpawnedObject, this, &AST_SpawnPoint::OnCheckSpawnedObject, CheckItemDelay, true, CheckItemDelay);
			}

			// Main Exit Point if Nothing Goes Wrong
			CurrentlySelectedItem = FST_SpawnParams();
			return;
		}
		else
		{
			// Code NEVER Get's here even if the Spawn Failed!

			UE_LOG(LogST_Spawn, All, TEXT("Spawn Failed!");
		}

I tried to create a repro case based on the sample code using:

TSubclassOf<AMyActor2> TestActor;
	FTransform SpawnTransform;
	SpawnTransform.SetLocation(FVector(0, 0, 0));
	SpawnTransform.SetRotation(FQuat(0, 0, 0, 0));
	SpawnTransform.SetScale3D(FVector(1, 1, 1));
	ESpawnActorCollisionHandlingMethod CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding;
	AMyActor2* RenamedThing = Cast<AMyActor2>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, TestActor, SpawnTransform, CollisionHandlingOverride, nullptr));

This failed to create a new object when called with the output log stating “BeginSpawningActorFromClass: can not spawn an actor from a NULL class”

I also tried using GetWorld()->SpawnActor with this setup:

FActorSpawnParameters SpawnParameters;
	SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding;
	FRotator NewRot = FRotator(0, 0, 0);
	FVector NewVec = FVector(0, 0, 0);
	UWorld* MyWorld = GetWorld();
	AMyActor2* RenamedThing = MyWorld->SpawnActor<AMyActor2>(AMyActor2::StaticClass(), NewVec, NewRot, SpawnParameters);

This also failed to create a new object due to MyActor2 overlapping with existing actors in the level (“SpawnActor failed because of collision at the spawn location [X=0.000 Y=0.000 Z=0.000]”).

I followed the provided code in both setups with:

if (RenamedThing)
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage(-1, 4.f, FColor::Magenta, TEXT("Spawn Succeeded"));
		}
	}
	else
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage(-1, 4.f, FColor::Magenta, TEXT("Spawn Failed"));
		}
	}

In both cases, I received the else statement of “Spawn Failed” when the code was called. If you’re able to recreate this issue in a sample project, could you provide the project itself to help me see the behavior you’re seeing.

Hey -

We have not heard back from you in a few days, so we are marking this post as Resolved for tracking purposes. If you are still experiencing the issue you reported, please respond to this message with additional information and we will follow up.

Cheers