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; }
void UActorComponent::PostLoad() { Super::PostLoad(); if (GetLinkerUE4Version() < VER_UE4_ACTOR_COMPONENT_CREATION_METHOD) { if (IsTemplate()) { CreationMethod = EComponentCreationMethod::Native; } else if (bCreatedByConstructionScript_DEPRECATED) { CreationMethod = EComponentCreationMethod::SimpleConstructionScript; } else if (bInstanceComponent_DEPRECATED) { CreationMethod = EComponentCreationMethod::Instance; } if (CreationMethod == EComponentCreationMethod::SimpleConstructionScript) { UBlueprintGeneratedClass* Class = CastChecked<UBlueprintGeneratedClass>(GetOuter()->GetClass()); while (Class) { USimpleConstructionScript* SCS = Class->SimpleConstructionScript; if (SCS != nullptr && SCS->FindSCSNode(GetFName())) { break; } else { Class = Cast<UBlueprintGeneratedClass>(Class->GetSuperClass()); if (Class == nullptr) { CreationMethod = EComponentCreationMethod::UserConstructionScript; } } } } } if (CreationMethod == EComponentCreationMethod::SimpleConstructionScript) { if ((GetLinkerUE4Version() < VER_UE4_TRACK_UCS_MODIFIED_PROPERTIES) && !HasAnyFlags(RF_ClassDefaultObject)) { DetermineUCSModifiedProperties(); } } else { // For a brief period of time we were inadvertently storing these for all components, need to clear it out UCSModifiedProperties.Empty(); } }
FFindHeadersToInclude(FGatherConvertedClassDependencies& InDependencies) : FGatherConvertedClassDependenciesHelperBase(InDependencies) { FindReferences(Dependencies.GetActualStruct()); // special case - literal enum UBlueprintGeneratedClass* BPGC = Cast<UBlueprintGeneratedClass>(Dependencies.GetActualStruct()); UBlueprint* BP = BPGC ? Cast<UBlueprint>(BPGC->ClassGeneratedBy) : nullptr; if (BP) { TArray<UEdGraph*> Graphs; BP->GetAllGraphs(Graphs); for (UEdGraph* Graph : Graphs) { if (Graph) { TArray<UK2Node_EnumLiteral*> LiteralEnumNodes; Graph->GetNodesOfClass<UK2Node_EnumLiteral>(LiteralEnumNodes); for (UK2Node_EnumLiteral* LiteralEnumNode : LiteralEnumNodes) { UEnum* Enum = LiteralEnumNode ? LiteralEnumNode->Enum : nullptr; IncludeTheHeaderInBody(Enum); } } } } // Include classes of native subobjects if (BPGC) { UClass* NativeSuperClass = BPGC->GetSuperClass(); for (; NativeSuperClass && !NativeSuperClass->HasAnyClassFlags(CLASS_Native); NativeSuperClass = NativeSuperClass->GetSuperClass()) {} UObject* NativeCDO = NativeSuperClass ? NativeSuperClass->GetDefaultObject(false) : nullptr; if (NativeCDO) { TArray<UObject*> DefaultSubobjects; NativeCDO->GetDefaultSubobjects(DefaultSubobjects); for (UObject* DefaultSubobject : DefaultSubobjects) { IncludeTheHeaderInBody(DefaultSubobject ? DefaultSubobject->GetClass() : nullptr); } } } }
FString FEmitDefaultValueHelper::HandleNonNativeComponent(FEmitterLocalContext& Context, const USCS_Node* Node, TSet<const UProperty*>& OutHandledProperties, TArray<FString>& NativeCreatedComponentProperties, const USCS_Node* ParentNode, TArray<FNonativeComponentData>& ComponenntsToInit) { check(Node); check(Context.CurrentCodeType == FEmitterLocalContext::EGeneratedCodeType::CommonConstructor); FString NativeVariablePropertyName; UBlueprintGeneratedClass* BPGC = CastChecked<UBlueprintGeneratedClass>(Context.GetCurrentlyGeneratedClass()); if (UActorComponent* ComponentTemplate = Node->GetActualComponentTemplate(BPGC)) { const FString VariableCleanName = Node->VariableName.ToString(); const UObjectProperty* VariableProperty = FindField<UObjectProperty>(BPGC, *VariableCleanName); if (VariableProperty) { NativeVariablePropertyName = FEmitHelper::GetCppName(VariableProperty); OutHandledProperties.Add(VariableProperty); } else { NativeVariablePropertyName = VariableCleanName; } Context.AddCommonSubObject_InConstructor(ComponentTemplate, NativeVariablePropertyName); if (ComponentTemplate->GetOuter() == BPGC) { FNonativeComponentData NonativeComponentData; NonativeComponentData.NativeVariablePropertyName = NativeVariablePropertyName; NonativeComponentData.ComponentTemplate = ComponentTemplate; UClass* ComponentClass = ComponentTemplate->GetClass(); check(ComponentClass != nullptr); UObject* ObjectToCompare = ComponentClass->GetDefaultObject(false); if (ComponentTemplate->HasAnyFlags(RF_InheritableComponentTemplate)) { ObjectToCompare = Node->GetActualComponentTemplate(Cast<UBlueprintGeneratedClass>(BPGC->GetSuperClass())); } else { Context.AddLine(FString::Printf(TEXT("%s%s = CreateDefaultSubobject<%s>(TEXT(\"%s\"));") , (VariableProperty == nullptr) ? TEXT("auto ") : TEXT("") , *NativeVariablePropertyName , *FEmitHelper::GetCppName(ComponentClass) , *VariableCleanName)); NonativeComponentData.bSetNativeCreationMethod = true; NativeCreatedComponentProperties.Add(NativeVariablePropertyName); FString ParentVariableName; if (ParentNode) { const FString CleanParentVariableName = ParentNode->VariableName.ToString(); const UObjectProperty* ParentVariableProperty = FindField<UObjectProperty>(BPGC, *CleanParentVariableName); ParentVariableName = ParentVariableProperty ? FEmitHelper::GetCppName(ParentVariableProperty) : CleanParentVariableName; } else if (USceneComponent* ParentComponentTemplate = Node->GetParentComponentTemplate(CastChecked<UBlueprint>(BPGC->ClassGeneratedBy))) { ParentVariableName = Context.FindGloballyMappedObject(ParentComponentTemplate, USceneComponent::StaticClass()); } NonativeComponentData.ParentVariableName = ParentVariableName; NonativeComponentData.AttachToName = Node->AttachToName; } NonativeComponentData.ObjectToCompare = ObjectToCompare; ComponenntsToInit.Add(NonativeComponentData); } } // Recursively handle child nodes. for (auto ChildNode : Node->ChildNodes) { HandleNonNativeComponent(Context, ChildNode, OutHandledProperties, NativeCreatedComponentProperties, Node, ComponenntsToInit); } return NativeVariablePropertyName; }
EReplacementResult FBlueprintNativeCodeGenModule::IsTargetedForReplacement(const UObject* Object) const { if (Object == nullptr) { return EReplacementResult::DontReplace; } const UStruct* Struct = Cast<UStruct>(Object); const UEnum* Enum = Cast<UEnum>(Object); if (Struct == nullptr && Enum == nullptr) { return EReplacementResult::DontReplace; } EReplacementResult Result = EReplacementResult::ReplaceCompletely; if (const UClass* BlueprintClass = Cast<UClass>(Struct)) { if (UBlueprint* Blueprint = Cast<UBlueprint>(BlueprintClass->ClassGeneratedBy)) { static const FBoolConfigValueHelper NativizeAnimBPOnlyWhenNonReducibleFuncitons(TEXT("BlueprintNativizationSettings"), TEXT("bNativizeAnimBPOnlyWhenNonReducibleFuncitons")); if (NativizeAnimBPOnlyWhenNonReducibleFuncitons) { if (UAnimBlueprint* AnimBlueprint = Cast<UAnimBlueprint>(Blueprint)) { ensure(AnimBlueprint->bHasBeenRegenerated); if (AnimBlueprint->bHasAnyNonReducibleFunction == UBlueprint::EIsBPNonReducible::No) { UE_LOG(LogBlueprintCodeGen, Log, TEXT("AnimBP %s without non-reducible functions is excluded from nativization"), *GetPathNameSafe(Blueprint)); Result = EReplacementResult::GenerateStub; } } } const EBlueprintType UnconvertableBlueprintTypes[] = { //BPTYPE_Const, // WTF is a "const" Blueprint? BPTYPE_MacroLibrary, BPTYPE_LevelScript, }; EBlueprintType BlueprintType = Blueprint->BlueprintType; for (int32 TypeIndex = 0; TypeIndex < ARRAY_COUNT(UnconvertableBlueprintTypes); ++TypeIndex) { if (BlueprintType == UnconvertableBlueprintTypes[TypeIndex]) { Result = EReplacementResult::GenerateStub; } } static const FBoolConfigValueHelper DontNativizeDataOnlyBP(TEXT("BlueprintNativizationSettings"), TEXT("bDontNativizeDataOnlyBP")); if (DontNativizeDataOnlyBP) { if (FBlueprintEditorUtils::IsDataOnlyBlueprint(Blueprint)) { return EReplacementResult::DontReplace; } } for (UBlueprintGeneratedClass* ParentClassIt = Cast<UBlueprintGeneratedClass>(BlueprintClass->GetSuperClass()) ; ParentClassIt; ParentClassIt = Cast<UBlueprintGeneratedClass>(ParentClassIt->GetSuperClass())) { EReplacementResult ParentResult = IsTargetedForReplacement(ParentClassIt); if (ParentResult != EReplacementResult::ReplaceCompletely) { Result = EReplacementResult::GenerateStub; } } for (TAssetSubclassOf<UBlueprint> ExcludedBlueprintTypeAsset : ExcludedBlueprintTypes) { UClass* ExcludedBPClass = ExcludedBlueprintTypeAsset.Get(); if (!ExcludedBPClass) { ExcludedBPClass = ExcludedBlueprintTypeAsset.LoadSynchronous(); } if (ExcludedBPClass && Blueprint->IsA(ExcludedBPClass)) { Result = EReplacementResult::GenerateStub; } } } } auto IsObjectFromDeveloperPackage = [](const UObject* Obj) -> bool { return Obj && Obj->GetOutermost()->HasAllPackagesFlags(PKG_Developer); }; auto IsDeveloperObject = [&](const UObject* Obj) -> bool { if (Obj) { if (IsObjectFromDeveloperPackage(Obj)) { return true; } const UStruct* StructToTest = Obj->IsA<UStruct>() ? CastChecked<const UStruct>(Obj) : Obj->GetClass(); for (; StructToTest; StructToTest = StructToTest->GetSuperStruct()) { if (IsObjectFromDeveloperPackage(StructToTest)) { return true; } } } return false; }; if (Object && (IsEditorOnlyObject(Object) || IsDeveloperObject(Object))) { UE_LOG(LogBlueprintCodeGen, Warning, TEXT("Object %s depends on Editor or Development stuff. It shouldn't be cooked."), *GetPathNameSafe(Object)); return EReplacementResult::DontReplace; } // check blacklists: // we can't use FindObject, because we may be converting a type while saving if (Enum && ExcludedAssetTypes.Find(Enum->GetPathName()) != INDEX_NONE) { Result = EReplacementResult::GenerateStub; } while (Struct) { if (ExcludedAssetTypes.Find(Struct->GetPathName()) != INDEX_NONE) { Result = EReplacementResult::GenerateStub; } Struct = Struct->GetSuperStruct(); } if (ExcludedAssets.Contains(Object->GetOutermost())) { Result = EReplacementResult::GenerateStub; } return Result; }
UObject* FBlueprintNativeCodeGenModule::FindReplacedNameAndOuter(UObject* Object, FName& OutName) const { OutName = NAME_None; UObject* Outer = nullptr; UActorComponent* ActorComponent = Cast<UActorComponent>(Object); if (ActorComponent) { //if is child of a BPGC and not child of a CDO UBlueprintGeneratedClass* BPGC = nullptr; for (UObject* OuterObject = ActorComponent->GetOuter(); OuterObject && !BPGC; OuterObject = OuterObject->GetOuter()) { if (OuterObject->HasAnyFlags(RF_ClassDefaultObject)) { return Outer; } BPGC = Cast<UBlueprintGeneratedClass>(OuterObject); } for (UBlueprintGeneratedClass* SuperBPGC = BPGC; SuperBPGC && (OutName == NAME_None); SuperBPGC = Cast<UBlueprintGeneratedClass>(SuperBPGC->GetSuperClass())) { if (SuperBPGC->InheritableComponentHandler) { FComponentKey FoundKey = SuperBPGC->InheritableComponentHandler->FindKey(ActorComponent); if (FoundKey.IsValid()) { OutName = FoundKey.IsSCSKey() ? FoundKey.GetSCSVariableName() : ActorComponent->GetFName(); Outer = BPGC->GetDefaultObject(false); break; } } if (SuperBPGC->SimpleConstructionScript) { for (auto Node : SuperBPGC->SimpleConstructionScript->GetAllNodes()) { if (Node->ComponentTemplate == ActorComponent) { OutName = Node->VariableName; if (OutName != NAME_None) { Outer = BPGC->GetDefaultObject(false); break; } } } } } } if (Outer && (EReplacementResult::ReplaceCompletely == IsTargetedForReplacement(Object->GetClass()))) { UE_LOG(LogBlueprintCodeGen, Log, TEXT("Object '%s' has replaced name '%s' and outer: '%s'"), *GetPathNameSafe(Object), *OutName.ToString(), *GetPathNameSafe(Outer)); return Outer; } return nullptr; }
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; }