Exemplo n.º 1
1
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();
	}
}
Exemplo n.º 7
0
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();
}
Exemplo n.º 13
0
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;
	}
}