void UActorRecording::StartRecordingNewComponents(ULevelSequence* CurrentSequence, float CurrentSequenceTime) { if (GetActorToRecord() != nullptr) { // find the new component(s) TInlineComponentArray<USceneComponent*> NewComponents; TArray<USceneComponent*> SceneComponents; GetSceneComponents(SceneComponents); for(USceneComponent* SceneComponent : SceneComponents) { if(ValidComponent(SceneComponent)) { TWeakObjectPtr<USceneComponent> WeakSceneComponent(SceneComponent); int32 FoundIndex = TrackedComponents.Find(WeakSceneComponent); if(FoundIndex == INDEX_NONE) { // new component! NewComponents.Add(SceneComponent); } } } ProcessNewComponentArray(NewComponents); UMovieScene* MovieScene = CurrentSequence->GetMovieScene(); check(MovieScene); FAnimationRecordingSettings ComponentAnimationSettings = AnimationSettings; ComponentAnimationSettings.bRemoveRootAnimation = false; ComponentAnimationSettings.bRecordInWorldSpace = false; const USequenceRecorderSettings* Settings = GetDefault<USequenceRecorderSettings>(); if (!bRecordToPossessable) { FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(Guid); check(Spawnable); AActor* ObjectTemplate = CastChecked<AActor>(Spawnable->GetObjectTemplate()); for (USceneComponent* SceneComponent : NewComponents) { // new component, so we need to add this to our BP if it didn't come from SCS FName NewName; if (SceneComponent->CreationMethod != EComponentCreationMethod::SimpleConstructionScript) { // Give this component a unique name within its parent NewName = *FString::Printf(TEXT("Dynamic%s"), *SceneComponent->GetFName().GetPlainNameString()); NewName.SetNumber(1); while (FindObjectFast<UObject>(ObjectTemplate, NewName)) { NewName.SetNumber(NewName.GetNumber() + 1); } USceneComponent* TemplateRoot = ObjectTemplate->GetRootComponent(); USceneComponent* AttachToComponent = nullptr; // look for a similar attach parent in the current structure USceneComponent* AttachParent = SceneComponent->GetAttachParent(); if(AttachParent != nullptr) { // First off, check if we're attached to a component that has already been duplicated into this object // If so, the name lookup will fail, so we use a direct reference if (TWeakObjectPtr<USceneComponent>* DuplicatedComponent = DuplicatedDynamicComponents.Find(AttachParent)) { AttachToComponent = DuplicatedComponent->Get(); } // If we don't have an attachment parent duplicated already, perform a name lookup if (!AttachToComponent) { FName AttachName = SceneComponent->GetAttachParent()->GetFName(); TInlineComponentArray<USceneComponent*> AllChildren; ObjectTemplate->GetComponents(AllChildren); for (USceneComponent* Child : AllChildren) { CA_SUPPRESS(28182); // Dereferencing NULL pointer. 'Child' contains the same NULL value as 'AttachToComponent' did. if (Child->GetFName() == AttachName) { AttachToComponent = Child; break; } } } } if (!AttachToComponent) { AttachToComponent = ObjectTemplate->GetRootComponent(); } USceneComponent* NewTemplateComponent = Cast<USceneComponent>(StaticDuplicateObject(SceneComponent, ObjectTemplate, NewName, RF_AllFlags & ~RF_Transient)); NewTemplateComponent->AttachToComponent(AttachToComponent, FAttachmentTransformRules::KeepRelativeTransform, SceneComponent->GetAttachSocketName()); ObjectTemplate->AddInstanceComponent(NewTemplateComponent); DuplicatedDynamicComponents.Add(SceneComponent, NewTemplateComponent); } else { NewName = SceneComponent->GetFName(); } StartRecordingComponentProperties(NewName, SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings); bNewComponentAddedWhileRecording = true; } SyncTrackedComponents(); } else { for (USceneComponent* SceneComponent : NewComponents) { // new component, start recording StartRecordingComponentProperties(SceneComponent->GetFName(), SceneComponent, GetActorToRecord(), CurrentSequence, CurrentSequenceTime, ComponentAnimationSettings); } SyncTrackedComponents(); } } }
PyObject *py_ue_add_instance_component(ue_PyUObject * self, PyObject * args) { ue_py_check(self); PyObject *py_component; if (!PyArg_ParseTuple(args, "O:add_instance_component", &py_component)) { return nullptr; } AActor *actor = ue_py_check_type<AActor>(self); if (!actor) { return PyErr_Format(PyExc_Exception, "uobject is not an AActor"); } UActorComponent *component = ue_py_check_type<UActorComponent>(py_component); if (!component) { return PyErr_Format(PyExc_Exception, "argument is not a UActorComponent"); } actor->AddInstanceComponent(component); Py_RETURN_NONE; }
UActorComponent* FComponentEditorUtils::DuplicateComponent(UActorComponent* TemplateComponent) { check(TemplateComponent); UActorComponent* NewCloneComponent = nullptr; AActor* Actor = TemplateComponent->GetOwner(); if (!TemplateComponent->IsEditorOnly() && Actor) { Actor->Modify(); UClass* ComponentClass = TemplateComponent->GetClass(); FName NewComponentName = *FComponentEditorUtils::GenerateValidVariableName(ComponentClass, Actor); bool bKeepWorldLocationOnAttach = false; const bool bTemplateTransactional = TemplateComponent->HasAllFlags(RF_Transactional); TemplateComponent->SetFlags(RF_Transactional); NewCloneComponent = DuplicateObject<UActorComponent>(TemplateComponent, Actor, NewComponentName ); if (!bTemplateTransactional) { TemplateComponent->ClearFlags(RF_Transactional); } USceneComponent* NewSceneComponent = Cast<USceneComponent>(NewCloneComponent); if (NewSceneComponent) { // Ensure the clone doesn't think it has children NewSceneComponent->AttachChildren.Empty(); // If the clone is a scene component without an attach parent, attach it to the root (can happen when duplicating the root component) if (!NewSceneComponent->GetAttachParent()) { USceneComponent* RootComponent = Actor->GetRootComponent(); check(RootComponent); // ComponentToWorld is not a UPROPERTY, so make sure the clone has calculated it properly before attachment NewSceneComponent->UpdateComponentToWorld(); NewSceneComponent->AttachTo(RootComponent, NAME_None, EAttachLocation::KeepWorldPosition); } } NewCloneComponent->OnComponentCreated(); // Add to SerializedComponents array so it gets saved Actor->AddInstanceComponent(NewCloneComponent); // Register the new component NewCloneComponent->RegisterComponent(); // Rerun construction scripts Actor->RerunConstructionScripts(); } return NewCloneComponent; }