AActor::TeleportTo with bNoCheck does not teleport physics

Problem:

When teleporting via AActor::TeleportTo with { bNoCheck = true }, I noticed that the teleport was successful, but the actor did not appear to have moved.

This turned out to be because the (successfully teleported) component was subsequently sync’d back to the rigid body.

From this I noticed that the bNoCheck path in AActor::TeleportTo does not teleport physics, yet the other paths do. Is this intentional?

I suspect that bIsATest should probably not change the physics, but am surprised that bNoCheck alone results in an incomplete teleport.

FWIW: Currently, the teleport here is applied like this:

if (bIsATest || bNoCheck)
{
    ActorPrimComp->SetWorldLocationAndRotation(NewLocation, DestRotation);
}

I made the following tweak, and the problem went away. Not sure if it’s a good idea though, so am making this post :slight_smile:

if ( bIsATest || bNoCheck )
{
   const ETeleportType TeleportType = (bIsATest ? ETeleportType::None : ETeleportType::TeleportPhysics); 
   ActorPrimComp->SetWorldLocationAndRotation(NewLocation, DestRotation, false, nullptr, TeleportType);
}

[Attachment Removed]

Hi Haydxn,

I did some investigation on the history and usage of the AActor::TeleportTo() function. Its code is entirely from around 2014-2017, so it has been stable for quite some time now. On the other hand, I noticed that the last parameter with type “ETeleportType” was added in 2015 by CL 2596239 (GitHub commit ed449d9). Before that, all code paths in the TeleportTo() function called either MoveComponent() or SetWorldLocationAndRotation() with flag bSweep=false, meaning that the movement should not stop at a blocking collision, as expected for a “teleport” function. After the change, two code paths added ETeleportType::TeleportPhysics as the last parameter, which seems consistent, while the “if ( bIsATest || bNoCheck )” code path did not, making it use the default ETeleportType::None. This does seem odd to me, since we are talking about an explicit “teleport” function, and the “bNoCheck” flag should probably not change that aspect of the behavior.

Now, I searched for current engine functions that call AActor::TeleportTo() with bNoCheck=true (meaning that they don’t care if the final teleport destination results in the actor overlapping blocking geometry in the level), and here’s what I found:

UEditorEngine::AddExportTextActors()
UEditorEngine::MoveActorInFrontOfCamera()
UUnrealEdEngine::PasteActors()
UEditorActorSubsystem::ConvertBrushesToStaticMesh()
FLogVisualizer::UpdateCameraPosition()
ANavigationObjectBase::Validate()
FStaticMeshValidation::RunTest()
AFunctionalTest::GoToObservationPoint()
APlayerController::SetInitialLocationAndRotation()

Most of the functions above are used for Editor or test/validation functionality, and APlayerController::SetInitialLocationAndRotation() is only called for the spectator pawn. It seems quite possible that none of them actually cares about how the teleport affects physics, which would explain how not using ETeleportType::TeleportPhysics could go unnoticed.

On the other hand, I found [this [Content removed] from 7 years ago about this same issue. In the last message there, it seems that the engine devs acknowledged this as a bug, so there might be some other reason why the implementation was not changed (and now, the simple fact that AActor::TeleportTo() has been available for engine users and stable and for over 10 years might be a reason).

I am going to ask the opinion of some engine devs about this, but my recommendation for you is to avoid using this function for your use-case. I believe you can use USceneComponent::SetWorldLocationAndRotation() or AActor::SetActorLocationAndRotation() to achieve the same goal, and this will allow you to set ETeleportType directly.

Best regards,

Vitor

[Attachment Removed]