void FBlueprintStatsModule::DumpBlueprintStats()
{
	TArray<FBlueprintStatRecord> Records;
	for (TObjectIterator<UBlueprint> BlueprintIt; BlueprintIt; ++BlueprintIt)
	{
		UBlueprint* Blueprint = *BlueprintIt;

		new (Records) FBlueprintStatRecord(Blueprint);
	}


	// Now merge them
	FBlueprintStatRecord Aggregate(NULL);
	for (const FBlueprintStatRecord& SourceRecord : Records)
	{
		Aggregate.MergeAnotherRecordIn(SourceRecord);
	}

	// Sort the lists
	Aggregate.NodeCount.ValueSort(TGreater<int32>());
	Aggregate.FunctionCount.ValueSort(TGreater<int32>());
	Aggregate.FunctionOwnerCount.ValueSort(TGreater<int32>());
	Aggregate.RemoteMacroCount.ValueSort(TGreater<int32>());

	// Print out the merged record
	UE_LOG(LogBlueprintStats, Log, TEXT("Blueprint stats for %d blueprints in %s"), Records.Num(), GGameName);
	UE_LOG(LogBlueprintStats, Log, TEXT("%s"), *Aggregate.ToString(true));
	UE_LOG(LogBlueprintStats, Log, TEXT("%s"), *Aggregate.ToString(false));
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));

	// Print out the node list
	UE_LOG(LogBlueprintStats, Log, TEXT("NodeClass,NumInstances"));
	for (const auto& NodePair : Aggregate.NodeCount)
	{
		UE_LOG(LogBlueprintStats, Log, TEXT("%s,%d"), *(NodePair.Key->GetName()), NodePair.Value);
	}
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));

	// Print out the function list
	UE_LOG(LogBlueprintStats, Log, TEXT("FunctionPath,ClassName,FunctionName,NumInstances"));
	for (const auto& FunctionPair : Aggregate.FunctionCount)
	{
		UFunction* Function = FunctionPair.Key;
		UE_LOG(LogBlueprintStats, Log, TEXT("%s,%s,%s,%d"), *(Function->GetPathName()), *(Function->GetOuterUClass()->GetName()), *(Function->GetName()), FunctionPair.Value);
	}
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));

	// Print out the macro list
	UE_LOG(LogBlueprintStats, Log, TEXT("MacroPath,MacroName,NumInstances"));
	for (const auto& MacroPair : Aggregate.RemoteMacroCount)
	{
		UEdGraph* MacroGraph = MacroPair.Key;
		UE_LOG(LogBlueprintStats, Log, TEXT("%s,%s,%d"), *(MacroGraph->GetPathName()), *(MacroGraph->GetName()), MacroPair.Value);
	}
	UE_LOG(LogBlueprintStats, Log, TEXT("\n"));
}
		static void SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr)
		{
			UK2Node_LatentGameplayTaskCall* AsyncTaskNode = CastChecked<UK2Node_LatentGameplayTaskCall>(NewNode);
			if (FunctionPtr.IsValid())
			{
				UFunction* Func = FunctionPtr.Get();
				UObjectProperty* ReturnProp = CastChecked<UObjectProperty>(Func->GetReturnProperty());
						
				AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
				AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass();
				AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass;
			}
		}
void UK2Node_Switch::CreateFunctionPin()
{
	// Set properties on the function pin
	const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
	UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, FunctionName.ToString());
	FunctionPin->bDefaultValueIsReadOnly = true;
	FunctionPin->bNotConnectable = true;
	FunctionPin->bHidden = true;

	UFunction* Function = FindField<UFunction>(FunctionClass, FunctionName);
	const bool bIsStaticFunc = Function->HasAllFunctionFlags(FUNC_Static);
	if (bIsStaticFunc)
	{
		// Wire up the self to the CDO of the class if it's not us
		if (UBlueprint* BP = GetBlueprint())
		{
			UClass* FunctionOwnerClass = Function->GetOuterUClass();
			if (!BP->SkeletonGeneratedClass->IsChildOf(FunctionOwnerClass))
			{
				FunctionPin->DefaultObject = FunctionOwnerClass->GetDefaultObject();
			}
		}
	}
}
void UK2Node_LatentAbilityCall::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
	// these nested loops are combing over the same classes/functions the
	// FBlueprintActionDatabase does; ideally we save on perf and fold this in
	// with FBlueprintActionDatabase, but we want to keep the modules separate
	for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
	{
		UClass* Class = *ClassIt;
		if (!Class->IsChildOf<UAbilityTask>() || Class->HasAnyClassFlags(CLASS_Abstract))
		{
			continue;
		}
		
		for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
		{
			UFunction* Function = *FuncIt;
			if (!Function->HasAnyFunctionFlags(FUNC_Static))
			{
				continue;
			}

			// to keep from needlessly instantiating a UBlueprintNodeSpawner, first   
			// check to make sure that the registrar is looking for actions of this type
			// (could be regenerating actions for a specific asset, and therefore the 
			// registrar would only accept actions corresponding to that asset)
			if (!ActionRegistrar.IsOpenForRegistration(Function))
			{
				continue;
			}

			UObjectProperty* ReturnProperty = Cast<UObjectProperty>(Function->GetReturnProperty());
			// see if the function is a static factory method for online proxies
			bool const bIsProxyFactoryMethod = (ReturnProperty != nullptr) && ReturnProperty->PropertyClass->IsChildOf<UAbilityTask>();
			
			if (bIsProxyFactoryMethod)
			{
				UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(Function);
				check(NodeSpawner != nullptr);
				NodeSpawner->NodeClass = GetClass();
				
				auto CustomizeAcyncNodeLambda = [](UEdGraphNode* NewNode, bool bIsTemplateNode, TWeakObjectPtr<UFunction> FunctionPtr)
				{
					UK2Node_LatentAbilityCall* AsyncTaskNode = CastChecked<UK2Node_LatentAbilityCall>(NewNode);
					if (FunctionPtr.IsValid())
					{
						UFunction* Func = FunctionPtr.Get();
						UObjectProperty* ReturnProp = CastChecked<UObjectProperty>(Func->GetReturnProperty());
						
						AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
						AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass();
						AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass;
					}
				};
				
				TWeakObjectPtr<UFunction> FunctionPtr = Function;
				NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(CustomizeAcyncNodeLambda, FunctionPtr);
				
				// @TODO: since this can't be folded into FBlueprintActionDatabase, we
				//        need a way to associate these spawners with a certain class
				ActionRegistrar.AddBlueprintAction(Function, NodeSpawner);
			}
		}
	}
}
示例#5
0
void UK2Node_Message::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
	Super::ExpandNode(CompilerContext, SourceGraph);

	const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();

	UEdGraphPin* ExecPin = Schema->FindExecutionPin(*this, EGPD_Input);
	const bool bExecPinConnected = ExecPin && (ExecPin->LinkedTo.Num() > 0);
	UEdGraphPin* ThenPin = Schema->FindExecutionPin(*this, EGPD_Output);
	const bool bThenPinConnected = ThenPin && (ThenPin->LinkedTo.Num() > 0);

	// Skip ourselves if our exec isn't wired up
	if (bExecPinConnected)
	{
		// Make sure our interface is valid
		if (FunctionReference.GetMemberParentClass(this) == NULL)
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalid_Error", "Message node @@ has an invalid interface.").ToString()), this);
			return;
		}

		UFunction* MessageNodeFunction = GetTargetFunction();
		if (MessageNodeFunction == NULL)
		{
			//@TODO: Why do this here in teh compiler, it's already done on AllocateDefaultPins() during on-load node reconstruction
			MessageNodeFunction = Cast<UFunction>(UK2Node::FindRemappedField(FunctionReference.GetMemberParentClass(this), FunctionReference.GetMemberName()));
		}

		if (MessageNodeFunction == NULL)
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeInvalidFunction_Error", "Unable to find function with name %s for Message node @@.").ToString(), *(FunctionReference.GetMemberName().ToString())), this);
			return;
		}

		// Check to make sure we have a target
		UEdGraphPin* MessageSelfPin = Schema->FindSelfPin(*this, EGPD_Input);
		if( !MessageSelfPin || MessageSelfPin->LinkedTo.Num() == 0 )
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("MessageNodeSelfPin_Error", "Message node @@ must have a valid target or reference to self.").ToString()), this);
			return;
		}

		// First, create an internal cast-to-interface node
		UK2Node_DynamicCast* CastToInterfaceNode = CompilerContext.SpawnIntermediateNode<UK2Node_DynamicCast>(this, SourceGraph);
		CastToInterfaceNode->TargetType = MessageNodeFunction->GetOuterUClass();
		CastToInterfaceNode->SetPurity(false);
		CastToInterfaceNode->AllocateDefaultPins();

		UEdGraphPin* CastToInterfaceResultPin = CastToInterfaceNode->GetCastResultPin();
		if( !CastToInterfaceResultPin )
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("InvalidInterfaceClass_Error", "Node @@ has an invalid target interface class").ToString(), this);
			return;
		}

		CastToInterfaceResultPin->PinType.PinSubCategoryObject = *CastToInterfaceNode->TargetType;

		if (ExecPin != nullptr)
		{
			UEdGraphPin* CastExecInput = CastToInterfaceNode->GetExecPin();
			check(CastExecInput != nullptr);

			// Wire up the connections
			CompilerContext.MovePinLinksToIntermediate(*ExecPin, *CastExecInput);
		}

		UEdGraphPin* CastToInterfaceSourceObjectPin = CastToInterfaceNode->GetCastSourcePin();
		CompilerContext.MovePinLinksToIntermediate(*MessageSelfPin, *CastToInterfaceSourceObjectPin);

		// Next, create the function call node
		UK2Node_CallFunction* FunctionCallNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
		FunctionCallNode->bIsInterfaceCall = true;
		FunctionCallNode->FunctionReference = FunctionReference;
		FunctionCallNode->AllocateDefaultPins();

		UEdGraphPin* CastToInterfaceValidPin = CastToInterfaceNode->GetValidCastPin();
		check(CastToInterfaceValidPin != nullptr);

		UEdGraphPin* LastOutCastFaildPin   = CastToInterfaceNode->GetInvalidCastPin();
		check(LastOutCastFaildPin != nullptr);
		UEdGraphPin* LastOutCastSuccessPin = CastToInterfaceValidPin;
		// Wire up the connections
		if (UEdGraphPin* CallFunctionExecPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Input))
		{
			CastToInterfaceValidPin->MakeLinkTo(CallFunctionExecPin);
			LastOutCastSuccessPin = Schema->FindExecutionPin(*FunctionCallNode, EGPD_Output);
		}
		
		// Self pin
		UEdGraphPin* FunctionCallSelfPin = Schema->FindSelfPin(*FunctionCallNode, EGPD_Input);
		CastToInterfaceResultPin->MakeLinkTo(FunctionCallSelfPin);

		UFunction* ArrayClearFunction = UKismetArrayLibrary::StaticClass()->FindFunctionByName(FName(TEXT("Array_Clear")));
		check(ArrayClearFunction);

		bool const bIsPureFunc = Super::IsNodePure();
		// Variable pins - Try to associate variable inputs to the message node with the variable inputs and outputs to the call function node
		for( int32 i = 0; i < Pins.Num(); i++ )
		{
			UEdGraphPin* CurrentPin = Pins[i];
			if( CurrentPin && (CurrentPin->PinType.PinCategory != Schema->PC_Exec) && (CurrentPin->PinName != Schema->PN_Self) )
			{
				// Try to find a match for the pin on the function call node
				UEdGraphPin* FunctionCallPin = FunctionCallNode->FindPin(CurrentPin->PinName);
				if( FunctionCallPin )
				{
					// Move pin links if the pin is connected...
					CompilerContext.MovePinLinksToIntermediate(*CurrentPin, *FunctionCallPin);

					// when cast fails all return values must be cleared.
					if (EEdGraphPinDirection::EGPD_Output == CurrentPin->Direction)
					{
						UEdGraphPin* VarOutPin = FunctionCallPin;
						if (bIsPureFunc)
						{
							// since we cannot directly use the output from the
							// function call node (since it is pure, and invoking
							// it with a null target would cause an error), we 
							// have to use a temporary variable in it's place...
							UK2Node_TemporaryVariable* TempVar = CompilerContext.SpawnIntermediateNode<UK2Node_TemporaryVariable>(this, SourceGraph);
							TempVar->VariableType = CurrentPin->PinType;
							TempVar->AllocateDefaultPins();

							VarOutPin = TempVar->GetVariablePin();
							// nodes using the function's outputs directly, now
							// use this TempVar node instead
							CompilerContext.MovePinLinksToIntermediate(*FunctionCallPin, *VarOutPin);

							// on a successful cast, the temp var is filled with
							// the function's value, on a failed cast, the var 
							// is filled with a default value (DefaultValueNode, 
							// below)... this is the node for the success case:
							UK2Node_AssignmentStatement* AssignTempVar = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph);
							AssignTempVar->AllocateDefaultPins();
							
							// assign the output from the pure function node to
							// the TempVar (either way, this message node is 
							// returning the TempVar's value, so on a successful 
							// cast we want it to have the function's result)
							UEdGraphPin* ValueInPin = AssignTempVar->GetValuePin();
							Schema->TryCreateConnection(FunctionCallPin, ValueInPin);
							AssignTempVar->PinConnectionListChanged(ValueInPin);

							UEdGraphPin* VarInPin = AssignTempVar->GetVariablePin();
							Schema->TryCreateConnection(VarOutPin, VarInPin);
							AssignTempVar->PinConnectionListChanged(VarInPin);
							// fold this AssignTempVar node into the cast's 
							// success execution chain
							Schema->TryCreateConnection(AssignTempVar->GetExecPin(), LastOutCastSuccessPin);
							LastOutCastSuccessPin = AssignTempVar->GetThenPin();
						}

						UK2Node* DefaultValueNode = NULL;
						UEdGraphPin* DefaultValueThenPin = NULL;
						if (CurrentPin->PinType.bIsArray)
						{
							UK2Node_CallArrayFunction* ClearArray = CompilerContext.SpawnIntermediateNode<UK2Node_CallArrayFunction>(this, SourceGraph);
							DefaultValueNode = ClearArray;
							ClearArray->SetFromFunction(ArrayClearFunction);
							ClearArray->AllocateDefaultPins();

							UEdGraphPin* ArrayPin = ClearArray->GetTargetArrayPin();
							check(ArrayPin);
							Schema->TryCreateConnection(ArrayPin, VarOutPin);
							ClearArray->PinConnectionListChanged(ArrayPin);

							DefaultValueThenPin = ClearArray->GetThenPin();
						} 
						else
						{
							UK2Node_AssignmentStatement* AssignDefaultValue = CompilerContext.SpawnIntermediateNode<UK2Node_AssignmentStatement>(this, SourceGraph);
							DefaultValueNode = AssignDefaultValue;
							AssignDefaultValue->AllocateDefaultPins();

							Schema->TryCreateConnection(AssignDefaultValue->GetVariablePin(), VarOutPin);
							AssignDefaultValue->PinConnectionListChanged(AssignDefaultValue->GetVariablePin());
							Schema->SetPinDefaultValueBasedOnType(AssignDefaultValue->GetValuePin());

							DefaultValueThenPin = AssignDefaultValue->GetThenPin();
						}

						UEdGraphPin* DefaultValueExecPin = DefaultValueNode->GetExecPin();
						check(DefaultValueExecPin);
						Schema->TryCreateConnection(DefaultValueExecPin, LastOutCastFaildPin);
						LastOutCastFaildPin = DefaultValueThenPin;
						check(LastOutCastFaildPin);
					}
				}
				else
				{
					UE_LOG(LogK2Compiler, Log, TEXT("%s"), *LOCTEXT("NoPinConnectionFound_Error", "Unable to find connection for pin!  Check AllocateDefaultPins() for consistency!").ToString());
				}
			}
		}

		if( bThenPinConnected )
		{
			check(LastOutCastFaildPin != nullptr);
			// Failure case for the cast runs straight through to the exit
			CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *LastOutCastFaildPin);

			check(LastOutCastSuccessPin != nullptr);
			// Copy all links from the invalid cast case above to the call function node
			CompilerContext.MovePinLinksToIntermediate(*ThenPin, *LastOutCastSuccessPin);
		}
	}

	// Break all connections to the original node, so it will be pruned
	BreakAllNodeLinks();
}