Skip to content

Commit 6dfc145

Browse files
committed
Fixes an issue with components simulating physics and physics constraints when spawning prefab at runtime.
1 parent e435145 commit 6dfc145

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

Source/PrefabricatorRuntime/Private/Prefab/PrefabTools.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ namespace {
359359
}
360360

361361
UPrefabricatorAsset* PrefabAsset = Cast<UPrefabricatorAsset>(PrefabActor->PrefabComponent->PrefabAssetInterface.LoadSynchronous());
362+
USceneComponent* SceneComponent = Cast<USceneComponent>(ObjToSerialize);
362363

363364
if (!PrefabAsset) {
364365
return;
@@ -531,12 +532,28 @@ void FPrefabTools::LoadActorState(AActor* InActor, const FPrefabricatorActorData
531532
for (const FPrefabricatorComponentData& ComponentData : InActorData.Components) {
532533
if (UActorComponent** SearchResult = ComponentsByName.Find(ComponentData.ComponentName)) {
533534
UActorComponent* Component = *SearchResult;
535+
USceneComponent* SceneComponent = Cast<USceneComponent>(Component);
536+
537+
// JB: We store the world location in case we would be restoring a component simulating physics.
538+
// JB: This is necessary only for prefab spawned at runtime.
539+
FVector WorldLocation = FVector::ZeroVector;
540+
if (InActor->HasActorBegunPlay()) {
541+
if (SceneComponent)
542+
{
543+
WorldLocation = SceneComponent->GetComponentLocation();
544+
}
545+
}
546+
534547
bool bPreviouslyRegister;
535548
{
536549
//SCOPE_CYCLE_COUNTER(STAT_LoadStateFromPrefabAsset_UnregisterComponent);
537550
bPreviouslyRegister = Component->IsRegistered();
538551
if (InSettings.bUnregisterComponentsBeforeLoading && bPreviouslyRegister) {
539552
Component->UnregisterComponent();
553+
// JB: Some of the components (e.g., UPhysicsConstraintComponent) also require re-initialization.
554+
if (Component->HasBeenInitialized()) {
555+
Component->UninitializeComponent();
556+
}
540557
}
541558
}
542559

@@ -548,7 +565,14 @@ void FPrefabTools::LoadActorState(AActor* InActor, const FPrefabricatorActorData
548565
{
549566
//SCOPE_CYCLE_COUNTER(STAT_LoadStateFromPrefabAsset_RegisterComponent);
550567
if (InSettings.bUnregisterComponentsBeforeLoading && bPreviouslyRegister) {
568+
// JB: Register component will also initialize component if necessary.
551569
Component->RegisterComponent();
570+
// JB: Components that are simulating physics are detached from the actor on register.
571+
// JB: Restoring their relative location above will cause them to be spawned at a wrong location so we fix it.
572+
// JB: This is necessary only for prefab spawned at runtime.
573+
if (InActor->HasActorBegunPlay() && SceneComponent->IsSimulatingPhysics()) {
574+
SceneComponent->SetRelativeLocation(WorldLocation);
575+
}
552576
}
553577
}
554578
}
@@ -696,7 +720,8 @@ void FPrefabTools::LoadStateFromPrefabAsset(APrefabActor* PrefabActor, const FPr
696720
}
697721

698722
//JB: Spawning actors on top of each other may cause problems with PhysicX (as it needs to compute the overlaps).
699-
ChildActor = Service->SpawnActor(ActorClass, PrefabActor->GetActorTransform(), PrefabActor->GetLevel(), Template);
723+
FTransform WorldTransform = ActorItemData.RelativeTransform * PrefabActor->GetTransform();
724+
ChildActor = Service->SpawnActor(ActorClass, WorldTransform, PrefabActor->GetLevel(), Template);
700725
if (!Template) {
701726
LoadActorState(ChildActor, ActorItemData, InSettings);
702727
if (InState.IsValid()) {

0 commit comments

Comments
 (0)