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); } } } } } }
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); } } } } } } }