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::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker) { UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass()); if (BPClass != NULL) { BPClass->InstancePreReplication(ChangedPropertyTracker); } }
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; }
void UActorComponent::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const { UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass()); if (BPClass != NULL) { BPClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); } DOREPLIFETIME( UActorComponent, bIsActive ); DOREPLIFETIME( UActorComponent, bReplicates ); }
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(); } }
void UBlueprint::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const { UClass* GenClass = Cast<UClass>(GeneratedClass); if ( GenClass && GenClass->GetDefaultObject() ) { GenClass->GetDefaultObject()->GetAssetRegistryTags(OutTags); } Super::GetAssetRegistryTags(OutTags); FString ParentClassPackageName; if ( ParentClass ) { ParentClassPackageName = ParentClass->GetOutermost()->GetName(); } else { ParentClassPackageName = TEXT("None"); } //NumReplicatedProperties int32 NumReplicatedProperties = 0; UBlueprintGeneratedClass* BlueprintClass = Cast<UBlueprintGeneratedClass>(GenClass); if (BlueprintClass) { NumReplicatedProperties = BlueprintClass->NumReplicatedProperties; } OutTags.Add(FAssetRegistryTag("NumReplicatedProperties", FString::FromInt(NumReplicatedProperties), FAssetRegistryTag::TT_Numerical)); OutTags.Add(FAssetRegistryTag("ParentClassPackage", ParentClassPackageName, FAssetRegistryTag::TT_Hidden)); OutTags.Add(FAssetRegistryTag(GET_MEMBER_NAME_CHECKED(UBlueprint, BlueprintDescription), BlueprintDescription, FAssetRegistryTag::TT_Hidden)); uint32 ClassFlagsTagged = 0; if (BlueprintClass) { ClassFlagsTagged = BlueprintClass->GetClassFlags(); } else { ClassFlagsTagged = GetClass()->GetClassFlags(); } OutTags.Add( FAssetRegistryTag("ClassFlags", FString::FromInt(ClassFlagsTagged), FAssetRegistryTag::TT_Hidden) ); FKismetEditorUtilities::GetAssetRegistryTagsForBlueprint(this, OutTags); OutTags.Add( FAssetRegistryTag( "IsDataOnly", FBlueprintEditorUtils::IsDataOnlyBlueprint(this) ? TEXT("True") : TEXT("False"), FAssetRegistryTag::TT_Alphabetical ) ); }
FConnectionDrawingPolicy* FBlueprintProfilerPinConnectionFactory::CreateConnectionPolicy(const class UEdGraphSchema* Schema, int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const class FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const { FConnectionDrawingPolicy* NewPolicy = nullptr; if (InGraphObj) { EBlueprintProfilerHeatMapDisplayMode WireHeatMode = GetDefault<UBlueprintProfilerSettings>()->WireHeatMapDisplayMode; if (WireHeatMode != EBlueprintProfilerHeatMapDisplayMode::None) { UBlueprint* Blueprint = InGraphObj->GetTypedOuter<UBlueprint>(); UBlueprintGeneratedClass* BPGC = Blueprint ? Cast<UBlueprintGeneratedClass>(Blueprint->GeneratedClass) : nullptr; if (BPGC) { IBlueprintProfilerInterface& ProfilerModule = FModuleManager::LoadModuleChecked<IBlueprintProfilerInterface>("BlueprintProfiler"); TSharedPtr<FBlueprintExecutionContext> BlueprintContext = ProfilerModule.FindBlueprintContext(BPGC->GetPathName()); if (BlueprintContext.IsValid()) { NewPolicy = new FBlueprintProfilerConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements, WireHeatMode, InGraphObj, BlueprintContext); // When we have an active connection drawing policy, associate utility contexts with the active blueprint execution context. if (Blueprint->BlueprintType == BPTYPE_Normal) { ProfilerModule.AssociateUtilityContexts(BlueprintContext); } } } } } return NewPolicy; }
void AActor::PreEditChange(UProperty* PropertyThatWillChange) { Super::PreEditChange(PropertyThatWillChange); UObjectProperty* ObjProp = Cast<UObjectProperty>(PropertyThatWillChange); UBlueprintGeneratedClass* BPGC = Cast<UBlueprintGeneratedClass>(GetClass()); if ( BPGC != nullptr && ObjProp != nullptr ) { BPGC->UnbindDynamicDelegatesForProperty(this, ObjProp); } if ( ReregisterComponentsWhenModified() ) { UnregisterAllComponents(); } }
void AActor::PreEditChange(UProperty* PropertyThatWillChange) { Super::PreEditChange(PropertyThatWillChange); UObjectProperty* ObjProp = Cast<UObjectProperty>(PropertyThatWillChange); UBlueprintGeneratedClass* BPGC = Cast<UBlueprintGeneratedClass>(GetClass()); if ( BPGC != nullptr && ObjProp != nullptr ) { BPGC->UnbindDynamicDelegatesForProperty(this, ObjProp); } // During SIE, allow components to be unregistered here, and then reregistered and reconstructed in PostEditChangeProperty. if ((GEditor && GEditor->bIsSimulatingInEditor) || ReregisterComponentsWhenModified()) { UnregisterAllComponents(); } }
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); } } } }
void AActor::GetLifetimeReplicatedProps( TArray< FLifetimeProperty > & OutLifetimeProps ) const { UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass()); if (BPClass != NULL) { BPClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); } DOREPLIFETIME( AActor, Role ); DOREPLIFETIME( AActor, RemoteRole ); DOREPLIFETIME( AActor, Owner ); DOREPLIFETIME( AActor, bHidden ); DOREPLIFETIME( AActor, bTearOff ); DOREPLIFETIME( AActor, bCanBeDamaged ); DOREPLIFETIME( AActor, AttachmentReplication ); DOREPLIFETIME( AActor, Instigator ); DOREPLIFETIME_CONDITION( AActor, ReplicatedMovement, COND_SimulatedOrPhysics ); }
void FKismetConnectionDrawingPolicy::BuildExecutionRoadmap() { LatestTimeDiscovered = 0.0; // Only do highlighting in PIE or SIE if (!CanBuildRoadmap()) { return; } UBlueprint* TargetBP = FBlueprintEditorUtils::FindBlueprintForGraphChecked(GraphObj); UObject* ActiveObject = TargetBP->GetObjectBeingDebugged(); check(ActiveObject); // Due to CanBuildRoadmap // Redirect the target Blueprint when debugging with a macro graph visible if (TargetBP->BlueprintType == BPTYPE_MacroLibrary) { TargetBP = Cast<UBlueprint>(ActiveObject->GetClass()->ClassGeneratedBy); } TArray<UEdGraphNode*> SequentialNodesInGraph; TArray<double> SequentialNodeTimes; TArray<UEdGraphPin*> SequentialExecPinsInGraph; { const TSimpleRingBuffer<FKismetTraceSample>& TraceStack = FKismetDebugUtilities::GetTraceStack(); UBlueprintGeneratedClass* TargetClass = Cast<UBlueprintGeneratedClass>(TargetBP->GeneratedClass); FBlueprintDebugData& DebugData = TargetClass->GetDebugData(); for (int32 i = 0; i < TraceStack.Num(); ++i) { const FKismetTraceSample& Sample = TraceStack(i); if (UObject* TestObject = Sample.Context.Get()) { if (TestObject == ActiveObject) { UEdGraphPin* AssociatedPin = DebugData.FindExecPinFromCodeLocation(Sample.Function.Get(), Sample.Offset); if (UEdGraphNode* Node = DebugData.FindSourceNodeFromCodeLocation(Sample.Function.Get(), Sample.Offset, /*bAllowImpreciseHit=*/ false)) { if (GraphObj == Node->GetGraph()) { SequentialNodesInGraph.Add(Node); SequentialNodeTimes.Add(Sample.ObservationTime); SequentialExecPinsInGraph.Add(AssociatedPin); } else { // If the top-level source node is a macro instance node UK2Node_MacroInstance* MacroInstanceNode = Cast<UK2Node_MacroInstance>(Node); if (MacroInstanceNode) { // Attempt to locate the macro source node through the code mapping UEdGraphNode* MacroSourceNode = DebugData.FindMacroSourceNodeFromCodeLocation(Sample.Function.Get(), Sample.Offset); if (MacroSourceNode) { // If the macro source node is located in the current graph context if (GraphObj == MacroSourceNode->GetGraph()) { // Add it to the sequential node list SequentialNodesInGraph.Add(MacroSourceNode); SequentialNodeTimes.Add(Sample.ObservationTime); SequentialExecPinsInGraph.Add(AssociatedPin); } else { // The macro source node isn't in the current graph context, but we might have a macro instance node that is // in the current graph context, so obtain the set of macro instance nodes that are mapped to the code here. TArray<UEdGraphNode*> MacroInstanceNodes; DebugData.FindMacroInstanceNodesFromCodeLocation(Sample.Function.Get(), Sample.Offset, MacroInstanceNodes); // For each macro instance node in the set for (auto MacroInstanceNodeIt = MacroInstanceNodes.CreateConstIterator(); MacroInstanceNodeIt; ++MacroInstanceNodeIt) { // If the macro instance node is located in the current graph context MacroInstanceNode = Cast<UK2Node_MacroInstance>(*MacroInstanceNodeIt); if (MacroInstanceNode && GraphObj == MacroInstanceNode->GetGraph()) { // Add it to the sequential node list SequentialNodesInGraph.Add(MacroInstanceNode); SequentialNodeTimes.Add(Sample.ObservationTime); SequentialExecPinsInGraph.Add(AssociatedPin); // Exit the loop; we're done break; } } } } } } } } } } } // Run thru and apply bonus time const float InvNumNodes = 1.0f / (float)SequentialNodeTimes.Num(); for (int32 i = 0; i < SequentialNodesInGraph.Num(); ++i) { double& ObservationTime = SequentialNodeTimes[i]; const float PositionRatio = (SequentialNodeTimes.Num() - i) * InvNumNodes; const float PositionBonus = FMath::Pow(PositionRatio, TracePositionExponent) * TracePositionBonusPeriod; ObservationTime += PositionBonus; LatestTimeDiscovered = FMath::Max<double>(LatestTimeDiscovered, ObservationTime); } UEdGraphPin* LastExecPin = NULL; // Record the unique exec-pin to time pairings, keeping only the most recent // times for each pairing... reverse the "SequentialNodes" because right now // it is in stack order (with the last executed node first) for (int32 i = SequentialNodesInGraph.Num() - 1; i >= 1; --i) { UEdGraphNode* CurNode = SequentialNodesInGraph[i]; UEdGraphNode* NextNode = SequentialNodesInGraph[i-1]; // keep track of the last exec-pin executed by CurNode (these tracked // pins coincide with "WireTraceSite" op-codes that have been injected // prior to every "goto" statement... this way we have context for which // pin executed the jump) if (UEdGraphPin* AssociatedPin = SequentialExecPinsInGraph[i]) { LastExecPin = AssociatedPin; } // if this statement is a jump (from one node to another) if (CurNode != NextNode) { // if there was a wire-trace op-code inserted before this jump if (LastExecPin != NULL) { //ensure(LastExecPin->GetOwningNode() == CurNode); double NextNodeTime = SequentialNodeTimes[i-1]; FExecPairingMap& ExecPaths = PredecessorPins.FindOrAdd(NextNode); FTimePair& ExecTiming = ExecPaths.FindOrAdd(LastExecPin); // make sure that if we've already visited this exec-pin (like // in a for-loop or something), that we're replacing it with a // more recent execution time // // @TODO I don't see when this wouldn't be the case if (ExecTiming.ThisExecTime < NextNodeTime) { double CurNodeTime = SequentialNodeTimes[i]; ExecTiming.ThisExecTime = NextNodeTime; ExecTiming.PredExecTime = CurNodeTime; } } // if the nodes aren't graphically connected how could they be // executed back-to-back? well, this could be a pop back to a // sequence node from the end of one thread of execution, etc. else if (AreNodesGraphicallySequential(CurNode, NextNode)) { // only warn when the nodes are directly connected (this is all // for execution flow visualization after all) UE_LOG(LogConnectionDrawingPolicy, Warning, TEXT("Looks like a wire-trace was not injected before the jump from '%s' to '%s'."), *CurNode->GetNodeTitle(ENodeTitleType::FullTitle).ToString(), *NextNode->GetNodeTitle(ENodeTitleType::FullTitle).ToString()); } // clear the exec-pin (we're moving to a new node and want to find // it's executed out pin) LastExecPin = NULL; } // else, we're only collecting this data for tracing node-to-node // executions (so we don't care about this sequence of statements) } // Fade only when free-running (since we're using FApp::GetCurrentTime(), instead of FPlatformTime::Seconds) const double MaxTimeAhead = FMath::Min(FApp::GetCurrentTime() + 2*TracePositionBonusPeriod, LatestTimeDiscovered); //@TODO: Rough clamping; should be exposed as a parameter CurrentTime = FMath::Max(FApp::GetCurrentTime(), MaxTimeAhead); }
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; }
void FKismetConnectionDrawingPolicy::BuildExecutionRoadmap() { LatestTimeDiscovered = 0.0; // Only do highlighting in PIE or SIE if (!CanBuildRoadmap()) { return; } UBlueprint* TargetBP = FBlueprintEditorUtils::FindBlueprintForGraphChecked(GraphObj); UObject* ActiveObject = TargetBP->GetObjectBeingDebugged(); check(ActiveObject); // Due to CanBuildRoadmap // Redirect the target Blueprint when debugging with a macro graph visible if (TargetBP->BlueprintType == BPTYPE_MacroLibrary) { TargetBP = Cast<UBlueprint>(ActiveObject->GetClass()->ClassGeneratedBy); } TArray<UEdGraphNode*> SequentialNodesInGraph; TArray<double> SequentialNodeTimes; { const TSimpleRingBuffer<FKismetTraceSample>& TraceStack = FKismetDebugUtilities::GetTraceStack(); UBlueprintGeneratedClass* TargetClass = Cast<UBlueprintGeneratedClass>(TargetBP->GeneratedClass); FBlueprintDebugData& DebugData = TargetClass->GetDebugData(); for (int32 i = 0; i < TraceStack.Num(); ++i) { const FKismetTraceSample& Sample = TraceStack(i); if (UObject* TestObject = Sample.Context.Get()) { if (TestObject == ActiveObject) { if (UEdGraphNode* Node = DebugData.FindSourceNodeFromCodeLocation(Sample.Function.Get(), Sample.Offset, /*bAllowImpreciseHit=*/ false)) { if (GraphObj == Node->GetGraph()) { SequentialNodesInGraph.Add(Node); SequentialNodeTimes.Add(Sample.ObservationTime); } else { // If the top-level source node is a macro instance node UK2Node_MacroInstance* MacroInstanceNode = Cast<UK2Node_MacroInstance>(Node); if (MacroInstanceNode) { // Attempt to locate the macro source node through the code mapping UEdGraphNode* MacroSourceNode = DebugData.FindMacroSourceNodeFromCodeLocation(Sample.Function.Get(), Sample.Offset); if (MacroSourceNode) { // If the macro source node is located in the current graph context if (GraphObj == MacroSourceNode->GetGraph()) { // Add it to the sequential node list SequentialNodesInGraph.Add(MacroSourceNode); SequentialNodeTimes.Add(Sample.ObservationTime); } else { // The macro source node isn't in the current graph context, but we might have a macro instance node that is // in the current graph context, so obtain the set of macro instance nodes that are mapped to the code here. TArray<UEdGraphNode*> MacroInstanceNodes; DebugData.FindMacroInstanceNodesFromCodeLocation(Sample.Function.Get(), Sample.Offset, MacroInstanceNodes); // For each macro instance node in the set for (auto MacroInstanceNodeIt = MacroInstanceNodes.CreateConstIterator(); MacroInstanceNodeIt; ++MacroInstanceNodeIt) { // If the macro instance node is located in the current graph context MacroInstanceNode = Cast<UK2Node_MacroInstance>(*MacroInstanceNodeIt); if (MacroInstanceNode && GraphObj == MacroInstanceNode->GetGraph()) { // Add it to the sequential node list SequentialNodesInGraph.Add(MacroInstanceNode); SequentialNodeTimes.Add(Sample.ObservationTime); // Exit the loop; we're done break; } } } } } } } } } } } // Run thru and apply bonus time const float InvNumNodes = 1.0f / (float)SequentialNodeTimes.Num(); for (int32 i = 0; i < SequentialNodesInGraph.Num(); ++i) { double& ObservationTime = SequentialNodeTimes[i]; const float PositionRatio = (SequentialNodeTimes.Num() - i) * InvNumNodes; const float PositionBonus = FMath::Pow(PositionRatio, TracePositionExponent) * TracePositionBonusPeriod; ObservationTime += PositionBonus; LatestTimeDiscovered = FMath::Max<double>(LatestTimeDiscovered, ObservationTime); } // Record the unique node->node pairings, keeping only the most recent times for each pairing for (int32 i = SequentialNodesInGraph.Num() - 1; i >= 1; --i) { UEdGraphNode* CurNode = SequentialNodesInGraph[i]; double CurNodeTime = SequentialNodeTimes[i]; UEdGraphNode* NextNode = SequentialNodesInGraph[i-1]; double NextNodeTime = SequentialNodeTimes[i-1]; FExecPairingMap& Predecessors = PredecessorNodes.FindOrAdd(NextNode); // Update the timings if this is a more recent pairing FTimePair& Timings = Predecessors.FindOrAdd(CurNode); if (Timings.ThisExecTime < NextNodeTime) { Timings.PredExecTime = CurNodeTime; Timings.ThisExecTime = NextNodeTime; } } // Fade only when free-running (since we're using GCurrentTime, instead of FPlatformTime::Seconds) const double MaxTimeAhead = FMath::Min(GCurrentTime + 2*TracePositionBonusPeriod, LatestTimeDiscovered); //@TODO: Rough clamping; should be exposed as a parameter CurrentTime = FMath::Max(GCurrentTime, MaxTimeAhead); }
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; }
// Context used to aid debugging displays for nodes FKismetNodeInfoContext::FKismetNodeInfoContext(UEdGraph* SourceGraph) : ActiveObjectBeingDebugged(NULL) { // Only show pending latent actions in PIE/SIE mode SourceBlueprint = FBlueprintEditorUtils::FindBlueprintForGraph(SourceGraph); if (SourceBlueprint != NULL) { ActiveObjectBeingDebugged = SourceBlueprint->GetObjectBeingDebugged(); // Run thru debugged objects to see if any are objects with pending latent actions if (ActiveObjectBeingDebugged != NULL) { UBlueprintGeneratedClass* Class = CastChecked<UBlueprintGeneratedClass>((UObject*)(ActiveObjectBeingDebugged->GetClass())); FBlueprintDebugData const& ClassDebugData = Class->GetDebugData(); TSet<UObject*> LatentContextObjects; TArray<UK2Node_CallFunction*> FunctionNodes; SourceGraph->GetNodesOfClass<UK2Node_CallFunction>(FunctionNodes); // collect all the world context objects for all of the graph's latent nodes for (UK2Node_CallFunction const* FunctionNode : FunctionNodes) { UFunction* Function = FunctionNode->GetTargetFunction(); if ((Function == NULL) || !Function->HasMetaData(FBlueprintMetadata::MD_Latent)) { continue; } UObject* NodeWorldContext = ActiveObjectBeingDebugged; // if the node has a specific "world context" pin, attempt to get the value set for that first if (Function->HasMetaData(FBlueprintMetadata::MD_WorldContext)) { FString const WorldContextPinName = Function->GetMetaData(FBlueprintMetadata::MD_WorldContext); if (UEdGraphPin* ContextPin = FunctionNode->FindPin(WorldContextPinName)) { if (UObjectPropertyBase* ContextProperty = Cast<UObjectPropertyBase>(ClassDebugData.FindClassPropertyForPin(ContextPin))) { UObject* PropertyValue = ContextProperty->GetObjectPropertyValue_InContainer(ActiveObjectBeingDebugged); if (PropertyValue != NULL) { NodeWorldContext = PropertyValue; } } } } LatentContextObjects.Add(NodeWorldContext); } for (UObject* ContextObject : LatentContextObjects) { if (UWorld* World = GEngine->GetWorldFromContextObject(ContextObject, /*bChecked =*/false)) { FLatentActionManager& Manager = World->GetLatentActionManager(); TSet<int32> UUIDSet; Manager.GetActiveUUIDs(ActiveObjectBeingDebugged, /*out*/ UUIDSet); for (TSet<int32>::TConstIterator IterUUID(UUIDSet); IterUUID; ++IterUUID) { const int32 UUID = *IterUUID; if (UEdGraphNode* ParentNode = ClassDebugData.FindNodeFromUUID(UUID)) { TArray<FObjectUUIDPair>& Pairs = NodesWithActiveLatentActions.FindOrAdd(ParentNode); new (Pairs) FObjectUUIDPair(ContextObject, UUID); } } } } } // Covert the watched pin array into a set for (auto WatchedPinIt = SourceBlueprint->PinWatches.CreateConstIterator(); WatchedPinIt; ++WatchedPinIt) { UEdGraphPin* WatchedPin = *WatchedPinIt; UEdGraphNode* OwningNode = Cast<UEdGraphNode>(WatchedPin->GetOuter()); if (!ensure(OwningNode != NULL)) // shouldn't happen, but just in case a dead pin was added to the PinWatches array { continue; } check(OwningNode == WatchedPin->GetOwningNode()); WatchedPinSet.Add(WatchedPin); WatchedNodeSet.Add(OwningNode); } } }
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; }