bool FComponentEditorUtils::CanCopyComponents(const TArray<UActorComponent*>& ComponentsToCopy) { bool bCanCopy = ComponentsToCopy.Num() > 0; if (bCanCopy) { for (int32 i = 0; i < ComponentsToCopy.Num() && bCanCopy; ++i) { // Check for the default scene root; that cannot be copied/duplicated UActorComponent* Component = ComponentsToCopy[i]; bCanCopy = Component != nullptr && Component->GetFName() != USceneComponent::GetDefaultSceneRootVariableName(); if (bCanCopy) { UClass* ComponentClass = Component->GetClass(); check(ComponentClass != nullptr); // Component class cannot be abstract and must also be tagged as BlueprintSpawnable bCanCopy = !ComponentClass->HasAnyClassFlags(CLASS_Abstract) && ComponentClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent); } } } return bCanCopy; }
void FEmitDefaultValueHelper::GenerateConstructor(FEmitterLocalContext& Context) { GenerateCustomDynamicClassInitialization(Context); auto BPGC = CastChecked<UBlueprintGeneratedClass>(Context.GetCurrentlyGeneratedClass()); const FString CppClassName = FEmitHelper::GetCppName(BPGC); UClass* SuperClass = BPGC->GetSuperClass(); const bool bSuperHasOnlyDefaultConstructor = SuperClass && SuperClass->HasMetaData(TEXT("OnlyDefaultConstructorDeclared")); Context.CurrentCodeType = FEmitterLocalContext::EGeneratedCodeType::CommonConstructor; Context.ResetPropertiesForInaccessibleStructs(); Context.AddLine(FString::Printf(TEXT("%s::%s(const FObjectInitializer& ObjectInitializer) : Super(%s)") , *CppClassName , *CppClassName , bSuperHasOnlyDefaultConstructor ? TEXT("") : TEXT("ObjectInitializer"))); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); // Call CustomDynamicClassInitialization Context.AddLine(FString::Printf(TEXT("if(HasAnyFlags(RF_ClassDefaultObject) && (%s::StaticClass() == GetClass()))"), *CppClassName)); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); Context.AddLine(FString::Printf(TEXT("%s::__CustomDynamicClassInitialization(CastChecked<UDynamicClass>(GetClass()));"), *CppClassName)); Context.DecreaseIndent(); Context.AddLine(TEXT("}")); // Components that must be fixed after serialization TArray<FString> NativeCreatedComponentProperties; { UObject* CDO = BPGC->GetDefaultObject(false); UObject* ParentCDO = BPGC->GetSuperClass()->GetDefaultObject(false); check(CDO && ParentCDO); Context.AddLine(TEXT("")); FString NativeRootComponentFallback; TSet<const UProperty*> HandledProperties; // Generate ctor init code for native class default subobjects that are always instanced (e.g. components). // @TODO (pkavan) - We can probably make this faster by generating code to index through the DSO array instead (i.e. in place of HandleInstancedSubobject which will generate a lookup call per DSO). TArray<UObject*> NativeDefaultObjectSubobjects; BPGC->GetDefaultObjectSubobjects(NativeDefaultObjectSubobjects); for (auto DSO : NativeDefaultObjectSubobjects) { if (DSO && DSO->GetClass()->HasAnyClassFlags(CLASS_DefaultToInstanced)) { // Determine if this is an editor-only subobject. bool bIsEditorOnlySubobject = false; if (const UActorComponent* ActorComponent = Cast<UActorComponent>(DSO)) { bIsEditorOnlySubobject = ActorComponent->IsEditorOnly(); } // Skip ctor code gen for editor-only subobjects, since they won't be used by the runtime. Any dependencies on editor-only subobjects will be handled later (see HandleInstancedSubobject). if (!bIsEditorOnlySubobject) { const FString VariableName = HandleInstancedSubobject(Context, DSO, false, true); // Keep track of which component can be used as a root, in case it's not explicitly set. if (NativeRootComponentFallback.IsEmpty()) { USceneComponent* SceneComponent = Cast<USceneComponent>(DSO); if (SceneComponent && !SceneComponent->GetAttachParent() && SceneComponent->CreationMethod == EComponentCreationMethod::Native) { NativeRootComponentFallback = VariableName; } } } } } // Check for a valid RootComponent property value; mark it as handled if already set in the defaults. bool bNeedsRootComponentAssignment = false; static const FName RootComponentPropertyName(TEXT("RootComponent")); const UObjectProperty* RootComponentProperty = FindField<UObjectProperty>(BPGC, RootComponentPropertyName); if (RootComponentProperty) { if (RootComponentProperty->GetObjectPropertyValue_InContainer(CDO)) { HandledProperties.Add(RootComponentProperty); } else if (!NativeRootComponentFallback.IsEmpty()) { Context.AddLine(FString::Printf(TEXT("RootComponent = %s;"), *NativeRootComponentFallback)); HandledProperties.Add(RootComponentProperty); } else { bNeedsRootComponentAssignment = true; } } // Generate ctor init code for the SCS node hierarchy (i.e. non-native components). SCS nodes may have dependencies on native DSOs, but not vice-versa. TArray<const UBlueprintGeneratedClass*> BPGCStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(BPGC, BPGCStack); if (bErrorFree) { TArray<FNonativeComponentData> ComponentsToInit; // Start at the base of the hierarchy so that dependencies are handled first. for (int32 i = BPGCStack.Num() - 1; i >= 0; --i) { if (BPGCStack[i]->SimpleConstructionScript) { for (auto Node : BPGCStack[i]->SimpleConstructionScript->GetRootNodes()) { if (Node) { const FString NativeVariablePropertyName = HandleNonNativeComponent(Context, Node, HandledProperties, NativeCreatedComponentProperties, nullptr, ComponentsToInit); if (bNeedsRootComponentAssignment && Node->ComponentTemplate && Node->ComponentTemplate->IsA<USceneComponent>() && !NativeVariablePropertyName.IsEmpty()) { // Only emit the explicit root component assignment statement if we're looking at the child BPGC that we're generating ctor code // for. In all other cases, the root component will already be set up by a chained parent ctor call, so we avoid stomping it here. if (i == 0) { Context.AddLine(FString::Printf(TEXT("RootComponent = %s;"), *NativeVariablePropertyName)); HandledProperties.Add(RootComponentProperty); } bNeedsRootComponentAssignment = false; } } } } } for (auto& ComponentToInit : ComponentsToInit) { ComponentToInit.EmitProperties(Context); } } // Generate ctor init code for generated Blueprint class property values that may differ from parent class defaults (or that otherwise belong to the generated Blueprint class). for (auto Property : TFieldRange<const UProperty>(BPGC)) { const bool bNewProperty = Property->GetOwnerStruct() == BPGC; const bool bIsAccessible = bNewProperty || !Property->HasAnyPropertyFlags(CPF_NativeAccessSpecifierPrivate); if (bIsAccessible && !HandledProperties.Contains(Property)) { OuterGenerate(Context, Property, TEXT(""), reinterpret_cast<const uint8*>(CDO), bNewProperty ? nullptr : reinterpret_cast<const uint8*>(ParentCDO), EPropertyAccessOperator::None, true); } } } Context.DecreaseIndent(); Context.AddLine(TEXT("}")); Context.CurrentCodeType = FEmitterLocalContext::EGeneratedCodeType::Regular; Context.ResetPropertiesForInaccessibleStructs(); Context.AddLine(FString::Printf(TEXT("void %s::PostLoadSubobjects(FObjectInstancingGraph* OuterInstanceGraph)"), *CppClassName)); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); Context.AddLine(TEXT("Super::PostLoadSubobjects(OuterInstanceGraph);")); for (auto& ComponentToFix : NativeCreatedComponentProperties) { Context.AddLine(FString::Printf(TEXT("if(ensure(%s))"), *ComponentToFix)); Context.AddLine(TEXT("{")); Context.IncreaseIndent(); Context.AddLine(FString::Printf(TEXT("%s->CreationMethod = EComponentCreationMethod::Native;"), *ComponentToFix)); Context.DecreaseIndent(); Context.AddLine(TEXT("}")); } Context.DecreaseIndent(); Context.AddLine(TEXT("}")); FDependenciesHelper::AddStaticFunctionsForDependencies(Context); FBackendHelperUMG::EmitWidgetInitializationFunctions(Context); }
void UK2Node_AddComponent::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const { Super::ValidateNodeDuringCompilation(MessageLog); UActorComponent* Template = GetTemplateFromNode(); if (Template) { UClass* TemplateClass = Template->GetClass(); if (!TemplateClass->IsChildOf(UActorComponent::StaticClass()) || TemplateClass->HasAnyClassFlags(CLASS_Abstract) || !TemplateClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent) ) { FFormatNamedArguments Args; Args.Add(TEXT("TemplateClass"), FText::FromString(TemplateClass->GetName())); Args.Add(TEXT("NodeTitle"), GetNodeTitle(ENodeTitleType::FullTitle)); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "InvalidComponentTemplate_Error", "Invalid class '{TemplateClass}' used as template by '{NodeTitle}' for @@"), Args).ToString(), this); } if (UChildActorComponent const* ChildActorComponent = Cast<UChildActorComponent const>(Template)) { UBlueprint const* Blueprint = GetBlueprint(); UClass const* ChildActorClass = ChildActorComponent->GetChildActorClass(); if (ChildActorClass == Blueprint->GeneratedClass) { UEdGraph const* ParentGraph = GetGraph(); UEdGraphSchema_K2 const* K2Schema = GetDefault<UEdGraphSchema_K2>(); if (K2Schema->IsConstructionScript(ParentGraph)) { FFormatNamedArguments Args; Args.Add(TEXT("ChildActorClass"), FText::FromString(ChildActorClass->GetName())); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "AddSelfComponent_Error", "@@ cannot add a '{ChildActorClass}' component in the construction script (could cause infinite recursion)."), Args).ToString(), this); } } else if (ChildActorClass != nullptr) { AActor const* ChildActor = Cast<AActor>(ChildActorClass->ClassDefaultObject); check(ChildActor != nullptr); USceneComponent* RootComponent = ChildActor->GetRootComponent(); if ((RootComponent != nullptr) && (RootComponent->Mobility == EComponentMobility::Static) && (ChildActorComponent->Mobility != EComponentMobility::Static)) { FFormatNamedArguments Args; Args.Add(TEXT("ChildActorClass"), FText::FromString(ChildActorClass->GetName())); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "AddStaticChildActorComponent_Error", "@@ cannot add a '{ChildActorClass}' component as it has static mobility, and the ChildActorComponent does not."), Args).ToString(), this); } } } } else { FFormatNamedArguments Args; Args.Add(TEXT("NodeTitle"), GetNodeTitle(ENodeTitleType::FullTitle)); MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "MissingComponentTemplate_Error", "Unknown template referenced by '{NodeTitle}' for @@"), Args).ToString(), this); } }
ComponentClassList.Add(NewSeparator); } TArray<FComponentClassComboEntryPtr> SortedClassList; AddBasicShapeComponents(SortedClassList); TArray<FName> InMemoryClasses; for (TObjectIterator<UClass> It; It; ++It) { UClass* Class = *It; // If this is a subclass of Actor Component, not abstract, and tagged as spawnable from Kismet if (Class->IsChildOf(UActorComponent::StaticClass())) { InMemoryClasses.Push(Class->GetFName()); if (!Class->HasAnyClassFlags(CLASS_Abstract) && Class->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent) && !FKismetEditorUtilities::IsClassABlueprintSkeleton(Class)) //@TODO: Fold this logic together with the one in UEdGraphSchema_K2::GetAddComponentClasses { TArray<FString> ClassGroupNames; Class->GetClassGroupNames(ClassGroupNames); if (ClassGroupNames.Contains(CommonClassGroup)) { FString ClassGroup = CommonClassGroup; FComponentClassComboEntryPtr NewEntry(new FComponentClassComboEntry(ClassGroup, Class, ClassGroupNames.Num() <= 1, EComponentCreateAction::SpawnExistingClass)); SortedClassList.Add(NewEntry); } if (ClassGroupNames.Num() && !ClassGroupNames[0].Equals(CommonClassGroup)) { const bool bIncludeInFilter = true; FString ClassGroup = ClassGroupNames[0];