void UGatherTextFromMetaDataCommandlet::GatherTextFromUObject(UField* const Field)
{
	const int32 MetaDataCount = 3;
	const FString MetaDataKeys[MetaDataCount] =
	{	TEXT("ToolTip"),			TEXT("DisplayName"),			TEXT("Category")			};
	const FString AssociatedNamespaces[MetaDataCount] =
	{	TEXT("UObjectToolTips"),	TEXT("UObjectDisplayNames"),	TEXT("UObjectCategories")	};

	// Gather for object.
	{
		for(int32 i = 0; i < MetaDataCount; ++i)
		{
			const FString& MetaDataValue = Field->GetMetaData(*MetaDataKeys[i]);
			if(!(MetaDataValue.IsEmpty()))
			{
				const FString Namespace = AssociatedNamespaces[i];
				FLocItem LocItem(MetaDataValue);
				FContext Context;
				Context.Key =	MetaDataKeys[i] == TEXT("Category")
							?	MetaDataValue
							:	Field->GetFullGroupName(true) + TEXT(".") + Field->GetName();
				Context.SourceLocation = TEXT("Run-time MetaData");
				ManifestInfo->AddEntry(TEXT("EntryDescription"), Namespace, LocItem, Context);
			}
		}
	}

	// For enums, also gather for enum values.
	{
		UEnum* Enum = Cast<UEnum>(Field);
		if(Enum)
		{
			const int32 ValueCount = Enum->NumEnums();
			for(int32 i = 0; i < ValueCount; ++i)
			{
				for(int32 j = 0; j < MetaDataCount; ++j)
				{
					const FString& MetaDataValue = Enum->GetMetaData(*MetaDataKeys[j], i);
					if(!(MetaDataValue.IsEmpty()))
					{
						const FString Namespace = AssociatedNamespaces[j];
						FLocItem LocItem(MetaDataValue);
						FContext Context;
						Context.Key =	MetaDataKeys[j] == TEXT("Category")
									?	MetaDataValue
									:	Enum->GetFullGroupName(true) + TEXT(".") + Enum->GetName() + TEXT(".") + Enum->GetEnumName(i);
						Context.SourceLocation = TEXT("Run-time MetaData");
						ManifestInfo->AddEntry(TEXT("EntryDescription"), Namespace, LocItem, Context);
					}
				}
			}
		}
	}
}
예제 #2
0
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		// Cast the node and get all the input pins
		UK2Node_Select* SelectNode = Cast<UK2Node_Select>(Node);
		TArray<UEdGraphPin*> OptionPins;
		SelectNode->GetOptionPins(OptionPins);
		UEdGraphPin* IndexPin = SelectNode->GetIndexPin();

		// Get the kismet term for the (Condition or Index) that will determine which option to use
		UEdGraphPin* PinToTry = FEdGraphUtilities::GetNetFromPin(IndexPin);
		FBPTerminal** ConditionTerm = Context.NetMap.Find(PinToTry);

		// Get the kismet term for the return value
		UEdGraphPin* ReturnPin = SelectNode->GetReturnValuePin();
		FBPTerminal** ReturnTerm = Context.NetMap.Find(ReturnPin);

		// Don't proceed if there is no return value or there is no selection
		if (ConditionTerm != NULL && ReturnTerm != NULL)
		{
			FName ConditionalFunctionName = "";
			UClass* ConditionalFunctionClass = NULL;
			SelectNode->GetConditionalFunction(ConditionalFunctionName, &ConditionalFunctionClass);
			UFunction* ConditionFunction = FindField<UFunction>(ConditionalFunctionClass, ConditionalFunctionName);

			// Find the local boolean for use in the equality call function below (BoolTerm = result of EqualEqual_IntInt or NotEqual_BoolBool)
			FBPTerminal* BoolTerm = BoolTermMap.FindRef(SelectNode);

			// We need to keep a pointer to the previous IfNot statement so it can be linked to the next conditional statement
			FBlueprintCompiledStatement* PrevIfNotStatement = NULL;

			// Keep an array of all the unconditional goto statements so we can clean up their jumps after the noop statement is created
			TArray<FBlueprintCompiledStatement*> GotoStatementList;

			// Loop through all the options
			for (int32 OptionIdx = 0; OptionIdx < OptionPins.Num(); OptionIdx++)
			{
				// Create a CallFunction statement with the condition function from the Select class
				FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
				Statement.Type = KCST_CallFunction;
				Statement.FunctionToCall = ConditionFunction;
				Statement.FunctionContext = NULL;
				Statement.bIsParentContext = false;
				// BoolTerm will be the return value of the condition statement
				Statement.LHS = BoolTerm;
				// The condition passed into the Select node
				Statement.RHS.Add(*ConditionTerm);
				// Create a local int for use in the equality call function below (LiteralTerm = the right hand side of the EqualEqual_IntInt or NotEqual_BoolBool statement)
				FBPTerminal* LiteralTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
				LiteralTerm->bIsLiteral = true;
				LiteralTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int;
				LiteralTerm->Name = FString::Printf(TEXT("%d"), OptionIdx);
				Statement.RHS.Add(LiteralTerm);
				// If there is a previous IfNot statement, hook this one to that one for jumping
				if (PrevIfNotStatement)
				{
					Statement.bIsJumpTarget = true;
					PrevIfNotStatement->TargetLabel = &Statement;
				}

				// Create a GotoIfNot statement using the BoolTerm from above as the condition
				FBlueprintCompiledStatement* IfNotStatement = &Context.AppendStatementForNode(Node);
				IfNotStatement->Type = KCST_GotoIfNot;
				IfNotStatement->LHS = BoolTerm;

				// Create an assignment statement
				FBlueprintCompiledStatement& AssignStatement = Context.AppendStatementForNode(Node);
				AssignStatement.Type = KCST_Assignment;
				AssignStatement.LHS = *ReturnTerm;
				// Get the kismet term from the option pin
				UEdGraphPin* OptionPinToTry = FEdGraphUtilities::GetNetFromPin(OptionPins[OptionIdx]);
				FBPTerminal** OptionTerm = Context.NetMap.Find(OptionPinToTry);
				if (!OptionTerm)
				{
					Context.MessageLog.Error(*LOCTEXT("Error_UnregisterOptionPin", "Unregister option pin @@").ToString(), OptionPins[OptionIdx]);
					return;
				}
				AssignStatement.RHS.Add(*OptionTerm);

				// Create an unconditional goto to exit the node
				FBlueprintCompiledStatement& GotoStatement = Context.AppendStatementForNode(Node);
				GotoStatement.Type = KCST_UnconditionalGoto;
				GotoStatementList.Add(&GotoStatement);

				// If this is the last IfNot statement, hook the jump to an error message
				if (OptionIdx == OptionPins.Num() - 1)
				{
					// Create a CallFunction statement for doing a print string of our error message
					FBlueprintCompiledStatement& PrintStatement = Context.AppendStatementForNode(Node);
					PrintStatement.Type = KCST_CallFunction;
					PrintStatement.bIsJumpTarget = true;
					FName PrintStringFunctionName = "";
					UClass* PrintStringFunctionClass = NULL;
					SelectNode->GetPrintStringFunction(PrintStringFunctionName, &PrintStringFunctionClass);
					UFunction* PrintFunction = FindField<UFunction>(PrintStringFunctionClass, PrintStringFunctionName);
					PrintStatement.FunctionToCall = PrintFunction;
					PrintStatement.FunctionContext = NULL;
					PrintStatement.bIsParentContext = false;

					// Create a local int for use in the equality call function below (LiteralTerm = the right hand side of the EqualEqual_IntInt or NotEqual_BoolBool statement)
					FBPTerminal* LiteralStringTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
					LiteralStringTerm->bIsLiteral = true;
					LiteralStringTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String;

					FString SelectionNodeType(TEXT("NONE"));
					if (IndexPin)
					{
						UEnum* EnumObject = Cast<UEnum>(IndexPin->PinType.PinSubCategoryObject.Get());
						if (EnumObject != NULL)
						{
							SelectionNodeType = EnumObject->GetName();
						}
						else
						{
							// Not an enum, so just use the basic type
							SelectionNodeType = IndexPin->PinType.PinCategory;
						}
					}

					const UEdGraph* OwningGraph = Context.MessageLog.FindSourceObjectTypeChecked<UEdGraph>( SelectNode->GetGraph() );
					LiteralStringTerm->Name =
						FString::Printf(*LOCTEXT("SelectNodeIndexWarning", "Graph %s: Selection Node of type %s failed! Out of bounds indexing of the options. There are only %d options available.").ToString(),
						(OwningGraph) ? *OwningGraph->GetFullName() : TEXT("NONE"),
						*SelectionNodeType,
						OptionPins.Num());
					PrintStatement.RHS.Add(LiteralStringTerm);

					// Hook the IfNot statement's jump target to this statement
					IfNotStatement->TargetLabel = &PrintStatement;
				}

				PrevIfNotStatement = IfNotStatement;
			}

			// Create a noop to jump to so the unconditional goto statements can exit the node after successful assignment
			FBlueprintCompiledStatement& NopStatement = Context.AppendStatementForNode(Node);
			NopStatement.Type = KCST_Nop;
			NopStatement.bIsJumpTarget = true;
			// Loop through the unconditional goto statements and fix their jump targets
			for (auto It = GotoStatementList.CreateConstIterator(); It; It++)
			{
				(*It)->TargetLabel = &NopStatement;
			}
		}
	}
void UGatherTextFromMetaDataCommandlet::GatherTextFromUObject(UField* const Field, const FGatherParameters& Arguments)
{
	// Gather for object.
	{
		if( !Field->HasMetaData( TEXT("DisplayName") ) )
		{
			Field->SetMetaData( TEXT("DisplayName"), *FName::NameToDisplayString( Field->GetName(), Field->IsA( UBoolProperty::StaticClass() ) ) );
		}

		for(int32 i = 0; i < Arguments.InputKeys.Num(); ++i)
		{
			FFormatNamedArguments PatternArguments;
			PatternArguments.Add( TEXT("FieldPath"), FText::FromString( Field->GetFullGroupName(false) ) );

			if( Field->HasMetaData( *Arguments.InputKeys[i] ) )
			{
				const FString& MetaDataValue = Field->GetMetaData(*Arguments.InputKeys[i]);
				if( !MetaDataValue.IsEmpty() )
				{
					PatternArguments.Add( TEXT("MetaDataValue"), FText::FromString(MetaDataValue) );

					const FString Namespace = Arguments.OutputNamespaces[i];
					FLocItem LocItem(MetaDataValue);
					FManifestContext Context;
					Context.Key = FText::Format(Arguments.OutputKeys[i], PatternArguments).ToString();
					Context.SourceLocation = FString::Printf(TEXT("From metadata for key %s of member %s in %s"), *Arguments.InputKeys[i], *Field->GetName(), *Field->GetFullGroupName(true));
					GatherManifestHelper->AddSourceText(Namespace, LocItem, Context);
				}
			}
		}
	}

	// For enums, also gather for enum values.
	{
		UEnum* Enum = Cast<UEnum>(Field);
		if(Enum)
		{
			const int32 ValueCount = Enum->NumEnums();
			for(int32 i = 0; i < ValueCount; ++i)
			{
				if( !Enum->HasMetaData(TEXT("DisplayName"), i) )
				{
					Enum->SetMetaData(TEXT("DisplayName"), *FName::NameToDisplayString(Enum->GetEnumName(i), false), i);
				}

				for(int32 j = 0; j < Arguments.InputKeys.Num(); ++j)
				{
					FFormatNamedArguments PatternArguments;
					PatternArguments.Add( TEXT("FieldPath"), FText::FromString( Enum->GetFullGroupName(false) + TEXT(".") + Enum->GetEnumName(i) ) );

					if( Enum->HasMetaData(*Arguments.InputKeys[j], i) )
					{
						const FString& MetaDataValue = Enum->GetMetaData(*Arguments.InputKeys[j], i);
						if( !MetaDataValue.IsEmpty() )
						{
							PatternArguments.Add( TEXT("MetaDataValue"), FText::FromString(MetaDataValue) );

							const FString Namespace = Arguments.OutputNamespaces[j];
							FLocItem LocItem(MetaDataValue);
							FManifestContext Context;
							Context.Key = FText::Format(Arguments.OutputKeys[j], PatternArguments).ToString();
							Context.SourceLocation = FString::Printf(TEXT("From metadata for key %s of enum value %s of enum %s in %s"), *Arguments.InputKeys[j], *Enum->GetEnumName(i), *Enum->GetName(), *Enum->GetFullGroupName(true));
							GatherManifestHelper->AddSourceText(Namespace, LocItem, Context);
						}
					}
				}
			}
		}
	}
}