UActorComponent* AActor::AddComponent(FName TemplateName, bool bManualAttachment, const FTransform& RelativeTransform, const UObject* ComponentTemplateContext) { UActorComponent* Template = nullptr; UBlueprintGeneratedClass* BlueprintGeneratedClass = Cast<UBlueprintGeneratedClass>((ComponentTemplateContext != nullptr) ? ComponentTemplateContext->GetClass() : GetClass()); while(BlueprintGeneratedClass != nullptr) { Template = BlueprintGeneratedClass->FindComponentTemplateByName(TemplateName); if(nullptr != Template) { break; } BlueprintGeneratedClass = Cast<UBlueprintGeneratedClass>(BlueprintGeneratedClass->GetSuperClass()); } bool bIsSceneComponent = false; UActorComponent* NewActorComp = CreateComponentFromTemplate(Template); if(NewActorComp != nullptr) { // Call function to notify component it has been created NewActorComp->OnComponentCreated(); // The user has the option of doing attachment manually where they have complete control or via the automatic rule // that the first component added becomes the root component, with subsequent components attached to the root. USceneComponent* NewSceneComp = Cast<USceneComponent>(NewActorComp); if(NewSceneComp != nullptr) { if (!bManualAttachment) { if (RootComponent == nullptr) { RootComponent = NewSceneComp; } else { NewSceneComp->AttachTo(RootComponent); } } NewSceneComp->SetRelativeTransform(RelativeTransform); bIsSceneComponent = true; } // Register component, which will create physics/rendering state, now component is in correct position NewActorComp->RegisterComponent(); UWorld* World = GetWorld(); if (!bRunningUserConstructionScript && World && bIsSceneComponent) { UPrimitiveComponent* NewPrimitiveComponent = Cast<UPrimitiveComponent>(NewActorComp); if (NewPrimitiveComponent && ACullDistanceVolume::CanBeAffectedByVolumes(NewPrimitiveComponent)) { World->UpdateCullDistanceVolumes(this, NewPrimitiveComponent); } } } return NewActorComp; }
UActorComponent* UActorBlueprintLibrary::AttachComponentOfClass(UObject* WorldContextObject, TSubclassOf<UActorComponent> ComponentClass, AActor* Owner, FName ComponentName, USceneComponent* AttachTo, FName SocketName) { if (!Owner) { return nullptr; } UActorComponent* Component = NewObject<UActorComponent>(Owner, *ComponentClass, ComponentName); if (!Component) { return nullptr; } Component->RegisterComponent(); Component->OnComponentCreated(); USceneComponent* SceneComponent = Cast<USceneComponent>(Component); if (SceneComponent) { SceneComponent->SetWorldLocation(Owner->GetActorLocation()); SceneComponent->SetWorldRotation(Owner->GetActorRotation()); USceneComponent* AttachToComponent = AttachTo ? AttachTo : Owner->GetRootComponent(); SceneComponent->AttachToComponent(AttachToComponent, FAttachmentTransformRules::KeepWorldTransform, SocketName); } return Component; }
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; }
PyObject *py_ue_register_component(ue_PyUObject *self, PyObject * args) { ue_py_check(self); if (!self->ue_object->IsA<UActorComponent>()) { return PyErr_Format(PyExc_Exception, "uobject is not a component"); } UActorComponent *component = (UActorComponent *)self->ue_object; component->RegisterComponent(); Py_INCREF(Py_None); return Py_None; }
PyObject *py_ue_add_actor_component(ue_PyUObject * self, PyObject * args) { ue_py_check(self); PyObject *obj; char *name; if (!PyArg_ParseTuple(args, "Os:add_actor_component", &obj, &name)) { return NULL; } if (!self->ue_object->IsA<AActor>()) { return PyErr_Format(PyExc_Exception, "uobject is not an AActor"); } AActor *actor = (AActor *)self->ue_object; if (!ue_is_pyuobject(obj)) { return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } ue_PyUObject *py_obj = (ue_PyUObject *)obj; if (!py_obj->ue_object->IsA<UClass>()) { return PyErr_Format(PyExc_Exception, "argument is not a class"); } UActorComponent *component = NewObject<UActorComponent>(actor, (UClass *)py_obj->ue_object, FName(UTF8_TO_TCHAR(name))); if (!component) return PyErr_Format(PyExc_Exception, "unable to create component"); if (actor->GetWorld()) { component->RegisterComponent(); } PyObject *ret = (PyObject *)ue_get_python_wrapper(component); if (!ret) return PyErr_Format(PyExc_Exception, "uobject is in invalid state"); Py_INCREF(ret); return ret; }
void FComponentEditorUtils::PasteComponents(TArray<UActorComponent*>& OutPastedComponents, AActor* TargetActor, USceneComponent* TargetComponent) { check(TargetActor); // Get the text from the clipboard FString TextToImport; FPlatformMisc::ClipboardPaste(TextToImport); // Get a new component object factory for the clipboard content TSharedRef<FComponentObjectTextFactory> Factory = FComponentObjectTextFactory::Get(TextToImport); TargetActor->Modify(); USceneComponent* TargetParent = TargetComponent ? TargetComponent->GetAttachParent() : nullptr; for (auto& NewObjectPair : Factory->NewObjectMap) { // Get the component object instance UActorComponent* NewActorComponent = NewObjectPair.Value; check(NewActorComponent); // Relocate the instance from the transient package to the Actor and assign it a unique object name FString NewComponentName = FComponentEditorUtils::GenerateValidVariableName(NewActorComponent->GetClass(), TargetActor); NewActorComponent->Rename(*NewComponentName, TargetActor, REN_DontCreateRedirectors | REN_DoNotDirty); if (auto NewSceneComponent = Cast<USceneComponent>(NewActorComponent)) { // Default to attaching to the target component's parent if possible, otherwise attach to the root USceneComponent* NewComponentParent = TargetParent ? TargetParent : TargetActor->GetRootComponent(); // Check to see if there's an entry for the current component in the set of parent components if (Factory->ParentMap.Contains(NewObjectPair.Key)) { // Get the parent component name FName ParentName = Factory->ParentMap[NewObjectPair.Key]; if (Factory->NewObjectMap.Contains(ParentName)) { // The parent should by definition be a scene component NewComponentParent = CastChecked<USceneComponent>(Factory->NewObjectMap[ParentName]); } } //@todo: Fix pasting when the pasted component was a root //NewSceneComponent->UpdateComponentToWorld(); if (NewComponentParent) { // Reattach the current node to the parent node NewSceneComponent->AttachTo(NewComponentParent, NAME_None/*, EAttachLocation::KeepWorldPosition*/); } else { // There is no root component and this component isn't the child of another component in the map, so make it the root TargetActor->SetRootComponent(NewSceneComponent); } } TargetActor->AddInstanceComponent(NewActorComponent); NewActorComponent->RegisterComponent(); OutPastedComponents.Add(NewActorComponent); } // Rerun construction scripts TargetActor->RerunConstructionScripts(); }
PyObject *py_ue_add_actor_component(ue_PyUObject * self, PyObject * args) { ue_py_check(self); PyObject *obj; char *name; PyObject *py_parent = nullptr; if (!PyArg_ParseTuple(args, "Os|O:add_actor_component", &obj, &name, &py_parent)) { return NULL; } if (!self->ue_object->IsA<AActor>()) { return PyErr_Format(PyExc_Exception, "uobject is not an AActor"); } AActor *actor = (AActor *)self->ue_object; if (!ue_is_pyuobject(obj)) { return PyErr_Format(PyExc_Exception, "argument is not a UObject"); } ue_PyUObject *py_obj = (ue_PyUObject *)obj; if (!py_obj->ue_object->IsA<UClass>()) { return PyErr_Format(PyExc_Exception, "argument is not a UClass"); } UClass *u_class = (UClass *)py_obj->ue_object; if (!u_class->IsChildOf<UActorComponent>()) { return PyErr_Format(PyExc_Exception, "argument is not a UClass derived from UActorComponent"); } USceneComponent *parent_component = nullptr; if (py_parent) { parent_component = ue_py_check_type<USceneComponent>(py_parent); if (!parent_component) { return PyErr_Format(PyExc_Exception, "argument is not a USceneComponent"); } } UActorComponent *component = NewObject<UActorComponent>(actor, u_class, FName(UTF8_TO_TCHAR(name)), RF_Public); if (!component) return PyErr_Format(PyExc_Exception, "unable to create component"); if (py_parent && component->IsA<USceneComponent>()) { USceneComponent *scene_component = (USceneComponent *)component; scene_component->SetupAttachment(parent_component); } if (actor->GetWorld() && !component->IsRegistered()) { component->RegisterComponent(); } if (component->bWantsInitializeComponent && !component->HasBeenInitialized() && component->IsRegistered()) component->InitializeComponent(); Py_RETURN_UOBJECT(component); }
UActorComponent* AActor::AddComponent(FName TemplateName, bool bManualAttachment, const FTransform& RelativeTransform, const UObject* ComponentTemplateContext) { UActorComponent* Template = NULL; UBlueprintGeneratedClass* BlueprintGeneratedClass = Cast<UBlueprintGeneratedClass>((ComponentTemplateContext != NULL) ? ComponentTemplateContext->GetClass() : GetClass()); while(BlueprintGeneratedClass != NULL) { Template = BlueprintGeneratedClass->FindComponentTemplateByName(TemplateName); if(NULL != Template) { break; } BlueprintGeneratedClass = Cast<UBlueprintGeneratedClass>(BlueprintGeneratedClass->GetSuperClass()); } UActorComponent* NewActorComp = CreateComponentFromTemplate(Template); if(NewActorComp != NULL) { // The user has the option of doing attachment manually where they have complete control or via the automatic rule // that the first component added becomes the root component, with subsequent components attached to the root. USceneComponent* NewSceneComp = Cast<USceneComponent>(NewActorComp); bool bDeferRegisterStaticComponent = false; EComponentMobility::Type OriginalMobility = EComponentMobility::Movable; if(NewSceneComp != NULL) { // Components with Mobility set to EComponentMobility::Static or EComponentMobility::Stationary can't be properly set up in UCS (all changes will be rejected // due to EComponentMobility::Static flag) so we're going to temporarily change the flag and defer the registration until UCS has finished. bDeferRegisterStaticComponent = bRunningUserConstructionScript && NewSceneComp->Mobility != EComponentMobility::Movable; OriginalMobility = NewSceneComp->Mobility; if (bDeferRegisterStaticComponent) { NewSceneComp->Mobility = EComponentMobility::Movable; } if (!bManualAttachment) { if (RootComponent == NULL) { RootComponent = NewSceneComp; } else { NewSceneComp->AttachTo(RootComponent); } } NewSceneComp->SetRelativeTransform(RelativeTransform); } // Call function to notify component it has been created NewActorComp->OnComponentCreated(); if (bDeferRegisterStaticComponent) { // Defer registration until after UCS has completed. FDeferRegisterStaticComponents::Get().DeferStaticComponent(this, NewSceneComp, OriginalMobility); } else { // Register component, which will create physics/rendering state, now component is in correct position NewActorComp->RegisterComponent(); } } return NewActorComp; }