// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "BlueprintGraphPrivatePCH.h" #include "KismetCompiler.h" ////////////////////////////////////////////////////////////////////////// // FKCHandler_VariableGet #define LOCTEXT_NAMESPACE "K2Node" class FKCHandler_VariableGet : public FNodeHandlingFunctor { public: FKCHandler_VariableGet(FKismetCompilerContext& InCompilerContext) : FNodeHandlingFunctor(InCompilerContext) { } virtual void RegisterNet(FKismetFunctionContext& Context, UEdGraphPin* Net) override { // This net is a variable read ResolveAndRegisterScopedTerm(Context, Net, Context.VariableReferences); } virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override { UK2Node_Variable* VarNode = Cast(Node); if (VarNode) { VarNode->CheckForErrors(CompilerContext.GetSchema(), Context.MessageLog); } // Report an error that the local variable could not be found if(VarNode->VariableReference.IsLocalScope() && VarNode->GetPropertyForVariable() == NULL) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromName(VarNode->VariableReference.GetMemberName())); if(VarNode->VariableReference.GetMemberScopeName() != Context.Function->GetName()) { Args.Add(TEXT("ScopeName"), FText::FromString(VarNode->VariableReference.GetMemberScopeName())); CompilerContext.MessageLog.Warning(*FText::Format(LOCTEXT("LocalVariableNotFoundInScope_Error", "Unable to find local variable with name '{VariableName}' for @@, scope expected: @@, scope found: {ScopeName}"), Args).ToString(), Node, Node->GetGraph()); } else { CompilerContext.MessageLog.Warning(*FText::Format(LOCTEXT("LocalVariableNotFound_Error", "Unable to find local variable with name '{VariableName}' for @@"), Args).ToString(), Node); } } FNodeHandlingFunctor::RegisterNets(Context, Node); } }; namespace K2Node_VariableGetImpl { /** * Shared utility method for retrieving a UK2Node_VariableGet's bare tooltip. * * @param VarName The name of the variable that the node represents. * @return A formatted text string, describing what the VariableGet node does. */ static FText GetBaseTooltip(FName VarName); } static FText K2Node_VariableGetImpl::GetBaseTooltip(FName VarName) { FFormatNamedArguments Args; Args.Add(TEXT("VarName"), FText::FromName(VarName)); return FText::Format(LOCTEXT("GetVariableTooltip", "Read the value of variable {VarName}"), Args); } UK2Node_VariableGet::UK2Node_VariableGet(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { } void UK2Node_VariableGet::AllocateDefaultPins() { if(GetVarName() != NAME_None) { if(CreatePinForVariable(EGPD_Output)) { CreatePinForSelf(); } } Super::AllocateDefaultPins(); } void UK2Node_VariableGet::ReallocatePinsDuringReconstruction(TArray& OldPins) { if(GetVarName() != NAME_None) { if(!CreatePinForVariable(EGPD_Output)) { if(!RecreatePinForVariable(EGPD_Output, OldPins)) { return; } } CreatePinForSelf(); } } FText UK2Node_VariableGet::GetPropertyTooltip(UProperty const* VariableProperty) { FName VarName = NAME_None; if (VariableProperty != nullptr) { VarName = VariableProperty->GetFName(); UClass* SourceClass = VariableProperty->GetOwnerClass(); // discover if the variable property is a non blueprint user variable bool const bIsNativeVariable = (SourceClass != nullptr) && (SourceClass->ClassGeneratedBy == nullptr); FName const TooltipMetaKey(TEXT("tooltip")); FText SubTooltip; if (bIsNativeVariable) { FText const PropertyTooltip = VariableProperty->GetToolTipText(); if (!PropertyTooltip.IsEmpty()) { // See if the native property has a tooltip SubTooltip = PropertyTooltip; FString TooltipName = FString::Printf(TEXT("%s.%s"), *VarName.ToString(), *TooltipMetaKey.ToString()); FText::FindText(*VariableProperty->GetFullGroupName(true), *TooltipName, SubTooltip); } } else if (UBlueprint* VarBlueprint = Cast(SourceClass->ClassGeneratedBy)) { FString UserTooltipData; if (FBlueprintEditorUtils::GetBlueprintVariableMetaData(VarBlueprint, VarName, /*InLocalVarScope =*/nullptr, TooltipMetaKey, UserTooltipData)) { SubTooltip = FText::FromString(UserTooltipData); } } if (!SubTooltip.IsEmpty()) { FFormatNamedArguments Args; Args.Add(TEXT("VarName"), FText::FromName(VarName)); Args.Add(TEXT("PropertyTooltip"), SubTooltip); return FText::Format(LOCTEXT("GetVariableProperty_Tooltip", "Read the value of variable {VarName}\n{PropertyTooltip}"), Args); } } return K2Node_VariableGetImpl::GetBaseTooltip(VarName); } FText UK2Node_VariableGet::GetBlueprintVarTooltip(FBPVariableDescription const& VarDesc) { FName const TooltipMetaKey(TEXT("tooltip")); int32 const MetaIndex = VarDesc.FindMetaDataEntryIndexForKey(TooltipMetaKey); bool const bHasTooltipData = (MetaIndex != INDEX_NONE); if (bHasTooltipData) { FString UserTooltipData = VarDesc.GetMetaData(TooltipMetaKey); FFormatNamedArguments Args; Args.Add(TEXT("VarName"), FText::FromName(VarDesc.VarName)); Args.Add(TEXT("UserTooltip"), FText::FromString(UserTooltipData)); return FText::Format(LOCTEXT("GetVariableProperty_Tooltip", "Read the value of variable {VarName}\n{UserTooltip}"), Args); } return K2Node_VariableGetImpl::GetBaseTooltip(VarDesc.VarName); } FText UK2Node_VariableGet::GetTooltipText() const { // @TODO: The variable name mutates as the user makes changes to the // underlying property, so until we can catch all those cases, we're // going to leave this optimization off //if (CachedTooltip.IsOutOfDate()) { if (UProperty* Property = GetPropertyForVariable()) { CachedTooltip = GetPropertyTooltip(Property); } else if (FBPVariableDescription const* VarDesc = GetBlueprintVarDescription()) { CachedTooltip = GetBlueprintVarTooltip(*VarDesc); } else { CachedTooltip = K2Node_VariableGetImpl::GetBaseTooltip(GetVarName()); } } return CachedTooltip; } FText UK2Node_VariableGet::GetNodeTitle(ENodeTitleType::Type TitleType) const { // If there is only one variable being read, the title can be made the variable name FString OutputPinName; int32 NumOutputsFound = 0; for (int32 PinIndex = 0; PinIndex < Pins.Num(); ++PinIndex) { UEdGraphPin* Pin = Pins[PinIndex]; if (Pin->Direction == EGPD_Output) { ++NumOutputsFound; OutputPinName = Pin->PinName; } } if (NumOutputsFound != 1) { return LOCTEXT("Get", "Get"); } // @TODO: The variable name mutates as the user makes changes to the // underlying property, so until we can catch all those cases, we're // going to leave this optimization off else //if (CachedNodeTitle.IsOutOfDate()) { FFormatNamedArguments Args; Args.Add(TEXT("PinName"), FText::FromString(OutputPinName)); // FText::Format() is slow, so we cache this to save on performance CachedNodeTitle = FText::Format(LOCTEXT("GetPinName", "Get {PinName}"), Args); } return CachedNodeTitle; } FNodeHandlingFunctor* UK2Node_VariableGet::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const { return new FKCHandler_VariableGet(CompilerContext); } #undef LOCTEXT_NAMESPACE