void UChildActorComponent::CreateChildActor() { // Kill spawned actor if we have one DestroyChildActor(); // This is no longer needed if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } // If we have a class to spawn. if(ChildActorClass != nullptr) { UWorld* World = GetWorld(); if(World != nullptr) { // Before we spawn let's try and prevent cyclic disaster bool bSpawn = true; AActor* Actor = GetOwner(); while (Actor && bSpawn) { if (Actor->GetClass() == ChildActorClass) { bSpawn = false; UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName()); } Actor = Actor->ParentComponentActor.Get(); } if (bSpawn) { FActorSpawnParameters Params; Params.bNoCollisionFail = true; Params.bDeferConstruction = true; // We defer construction so that we set ParentComponentActor prior to component registration so they appear selected Params.bAllowDuringConstructionScript = true; Params.OverrideLevel = GetOwner()->GetLevel(); Params.Name = ChildActorName; if (!HasAllFlags(RF_Transactional)) { Params.ObjectFlags &= ~RF_Transactional; } // Spawn actor of desired class FVector Location = GetComponentLocation(); FRotator Rotation = GetComponentRotation(); ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params); // If spawn was successful, if(ChildActor != nullptr) { ChildActorName = ChildActor->GetFName(); // Remember which actor spawned it (for selection in editor etc) ChildActor->ParentComponentActor = GetOwner(); ChildActor->AttachRootComponentTo(this); // Parts that we deferred from SpawnActor ChildActor->FinishSpawning(ComponentToWorld); } } } } }
void UChildActorComponent::OnRegister() { Super::OnRegister(); if (ChildActor) { if (ChildActor->GetClass() != ChildActorClass) { DestroyChildActor(); CreateChildActor(); } else { ChildActorName = ChildActor->GetFName(); USceneComponent* ChildRoot = ChildActor->GetRootComponent(); if (ChildRoot && ChildRoot->GetAttachParent() != this) { // attach new actor to this component // we can't attach in CreateChildActor since it has intermediate Mobility set up // causing spam with inconsistent mobility set up // so moving Attach to happen in Register ChildRoot->AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); } // Ensure the components replication is correctly initialized SetIsReplicated(ChildActor->GetIsReplicated()); } } else if (ChildActorClass) { CreateChildActor(); } }
void UChildActorComponent::OnComponentDestroyed(bool bDestroyingHierarchy) { Super::OnComponentDestroyed(bDestroyingHierarchy); const UWorld* const MyWorld = GetWorld(); DestroyChildActor(MyWorld && !MyWorld->IsGameWorld()); }
void UChildActorComponent::OnRegister() { Super::OnRegister(); if (ChildActor) { if (ChildActor->GetClass() != ChildActorClass) { DestroyChildActor(); CreateChildActor(); } else { ChildActorName = ChildActor->GetFName(); USceneComponent* ChildRoot = ChildActor->GetRootComponent(); if (ChildRoot && ChildRoot->GetAttachParent() != this) { // attach new actor to this component // we can't attach in CreateChildActor since it has intermediate Mobility set up // causing spam with inconsistent mobility set up // so moving Attach to happen in Register ChildRoot->AttachTo(this, NAME_None, EAttachLocation::SnapToTarget); } } } else if (ChildActorClass) { CreateChildActor(); } }
void UChildActorComponent::OnUnregister() { Super::OnUnregister(); const UWorld* const MyWorld = GetWorld(); DestroyChildActor(MyWorld && !MyWorld->IsGameWorld()); }
void UChildActorComponent::SetChildActorClass(TSubclassOf<AActor> Class) { ChildActorClass = Class; if (IsRegistered()) { DestroyChildActor(); CreateChildActor(); } }
void UChildActorComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { Super::PostEditChangeProperty(PropertyChangedEvent); static const FName NAME_ChildActorClass = GET_MEMBER_NAME_CHECKED(UChildActorComponent, ChildActorClass); if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == NAME_ChildActorClass) { DestroyChildActor(); CreateChildActor(); } }
void UChildActorComponent::PostLoad() { Super::PostLoad(); // For a period of time the parent component property on Actor was not a UPROPERTY so this value was not set if (ChildActor) { FActorParentComponentSetter::Set(ChildActor, this); } // Since the template could have been changed we need to respawn the child actor // Don't do this if there is no linker which implies component was created via duplication if (ChildActorTemplate && GetLinker()) { DestroyChildActor(); } }
void UChildActorComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { static const FName NAME_ChildActorClass = GET_MEMBER_NAME_CHECKED(UChildActorComponent, ChildActorClass); if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == NAME_ChildActorClass) { ChildActorName = NAME_None; // If this was created by construction script, the post edit change super call will destroy it anyways if (!IsCreatedByConstructionScript()) { DestroyChildActor(); CreateChildActor(); } } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UChildActorComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UChildActorComponent, ChildActorClass)) { ChildActorName = NAME_None; if (!IsTemplate()) { UChildActorComponent* Archetype = CastChecked<UChildActorComponent>(GetArchetype()); ChildActorTemplate = (Archetype->ChildActorClass == ChildActorClass ? Archetype->ChildActorTemplate : nullptr); } // If this was created by construction script, the post edit change super call will destroy it anyways if (!IsCreatedByConstructionScript()) { DestroyChildActor(); CreateChildActor(); } } Super::PostEditChangeProperty(PropertyChangedEvent); }
void UChildActorComponent::OnUnregister() { Super::OnUnregister(); DestroyChildActor(); }
void UChildActorComponent::OnComponentDestroyed(bool bDestroyingHierarchy) { Super::OnComponentDestroyed(bDestroyingHierarchy); DestroyChildActor(); }
void UChildActorComponent::OnComponentDestroyed() { Super::OnComponentDestroyed(); DestroyChildActor(); }
void UChildActorComponent::CreateChildActor() { // Kill spawned actor if we have one DestroyChildActor(); // If we have a class to spawn. if(ChildActorClass != nullptr) { UWorld* World = GetWorld(); if(World != nullptr) { // Before we spawn let's try and prevent cyclic disaster bool bSpawn = true; AActor* MyOwner = GetOwner(); AActor* Actor = MyOwner; while (Actor && bSpawn) { if (Actor->GetClass() == ChildActorClass) { bSpawn = false; UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName()); } if (UChildActorComponent* ParentComponent = Actor->GetParentComponent()) { Actor = ParentComponent->GetOwner(); } else { Actor = nullptr; } } if (bSpawn) { FActorSpawnParameters Params; Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; Params.bDeferConstruction = true; // We defer construction so that we set ParentComponent prior to component registration so they appear selected Params.bAllowDuringConstructionScript = true; Params.OverrideLevel = (MyOwner ? MyOwner->GetLevel() : nullptr); Params.Name = ChildActorName; if (!HasAllFlags(RF_Transactional)) { Params.ObjectFlags &= ~RF_Transactional; } // Spawn actor of desired class FVector Location = GetComponentLocation(); FRotator Rotation = GetComponentRotation(); ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params); // If spawn was successful, if(ChildActor != nullptr) { ChildActorName = ChildActor->GetFName(); // Remember which component spawned it (for selection in editor etc) FActorParentComponentSetter::Set(ChildActor, this); // Parts that we deferred from SpawnActor const FComponentInstanceDataCache* ComponentInstanceData = (CachedInstanceData ? CachedInstanceData->ComponentInstanceData : nullptr); ChildActor->FinishSpawning(ComponentToWorld, false, ComponentInstanceData); ChildActor->AttachRootComponentTo(this, NAME_None, EAttachLocation::SnapToTarget); } } } } // This is no longer needed if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } }
void UChildActorComponent::CreateChildActor() { AActor* MyOwner = GetOwner(); if (MyOwner && !MyOwner->HasAuthority()) { AActor* ChildClassCDO = (ChildActorClass ? ChildActorClass->GetDefaultObject<AActor>() : nullptr); if (ChildClassCDO && ChildClassCDO->GetIsReplicated()) { // If we belong to an actor that is not authoritative and the child class is replicated then we expect that Actor will be replicated across so don't spawn one return; } } // Kill spawned actor if we have one DestroyChildActor(); // If we have a class to spawn. if(ChildActorClass != nullptr) { UWorld* World = GetWorld(); if(World != nullptr) { // Before we spawn let's try and prevent cyclic disaster bool bSpawn = true; AActor* Actor = MyOwner; while (Actor && bSpawn) { if (Actor->GetClass() == ChildActorClass) { bSpawn = false; UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName()); } Actor = Actor->GetParentActor(); } if (bSpawn) { FActorSpawnParameters Params; Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; Params.bDeferConstruction = true; // We defer construction so that we set ParentComponent prior to component registration so they appear selected Params.bAllowDuringConstructionScript = true; Params.OverrideLevel = (MyOwner ? MyOwner->GetLevel() : nullptr); Params.Name = ChildActorName; Params.Template = ChildActorTemplate; if (!HasAllFlags(RF_Transactional)) { Params.ObjectFlags &= ~RF_Transactional; } // Spawn actor of desired class ConditionalUpdateComponentToWorld(); FVector Location = GetComponentLocation(); FRotator Rotation = GetComponentRotation(); ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params); // If spawn was successful, if(ChildActor != nullptr) { ChildActorName = ChildActor->GetFName(); // Remember which component spawned it (for selection in editor etc) FActorParentComponentSetter::Set(ChildActor, this); // Parts that we deferred from SpawnActor const FComponentInstanceDataCache* ComponentInstanceData = (CachedInstanceData ? CachedInstanceData->ComponentInstanceData : nullptr); ChildActor->FinishSpawning(ComponentToWorld, false, ComponentInstanceData); ChildActor->AttachToComponent(this, FAttachmentTransformRules::SnapToTargetNotIncludingScale); SetIsReplicated(ChildActor->GetIsReplicated()); } } } } // This is no longer needed if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } }