1031 lines
37 KiB
C++
1031 lines
37 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "K2Node_Event.h"
|
|
|
|
#include "Containers/EnumAsByte.h"
|
|
#include "Containers/Set.h"
|
|
#include "DiffResults.h"
|
|
#include "EdGraph/EdGraph.h"
|
|
#include "EdGraph/EdGraphPin.h"
|
|
#include "EdGraph/EdGraphSchema.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "EdGraphSchema_K2_Actions.h"
|
|
#include "Engine/Blueprint.h"
|
|
#include "EngineLogs.h"
|
|
#include "EventEntryHandler.h"
|
|
#include "FindInBlueprints.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "GraphEditorSettings.h"
|
|
#include "HAL/PlatformCrt.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#include "K2Node_CallFunction.h"
|
|
#include "K2Node_CreateDelegate.h"
|
|
#include "K2Node_FunctionEntry.h"
|
|
#include "K2Node_Self.h"
|
|
#include "Kismet2/BlueprintEditorUtils.h"
|
|
#include "Kismet2/CompilerResultsLog.h"
|
|
#include "KismetCompiler.h"
|
|
#include "KismetCompilerMisc.h"
|
|
#include "Logging/LogCategory.h"
|
|
#include "Logging/LogMacros.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "ObjectTools.h"
|
|
#include "Serialization/Archive.h"
|
|
#include "Styling/AppStyle.h"
|
|
#include "Templates/Casts.h"
|
|
#include "Templates/UnrealTemplate.h"
|
|
#include "Trace/Detail/Channel.h"
|
|
#include "UObject/BlueprintsObjectVersion.h"
|
|
#include "UObject/Class.h"
|
|
#include "UObject/Interface.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/ObjectPtr.h"
|
|
#include "UObject/ObjectVersion.h"
|
|
#include "UObject/Script.h"
|
|
#include "UObject/UnrealNames.h"
|
|
#include "UObject/WeakObjectPtrTemplates.h"
|
|
|
|
const FName UK2Node_Event::DelegateOutputName(TEXT("OutputDelegate"));
|
|
|
|
bool UK2Node_Event::IsCosmeticTickEvent() const
|
|
{
|
|
// Special case for EventTick/ReceiveTick that is conditionally executed by a separate bool rather than function flag.
|
|
static const FName EventTickName(TEXT("ReceiveTick"));
|
|
if (EventReference.GetMemberName() == EventTickName)
|
|
{
|
|
const UBlueprint* Blueprint = GetBlueprint();
|
|
if (Blueprint)
|
|
{
|
|
UClass* BPClass = Blueprint->GeneratedClass;
|
|
const AActor* DefaultActor = BPClass ? Cast<const AActor>(BPClass->GetDefaultObject()) : nullptr;
|
|
if (DefaultActor && !DefaultActor->AllowReceiveTickEventOnDedicatedServer())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "K2Node_Event"
|
|
|
|
UK2Node_Event::UK2Node_Event(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
FunctionFlags = 0;
|
|
}
|
|
|
|
void UK2Node_Event::Serialize(FArchive& Ar)
|
|
{
|
|
Super::Serialize(Ar);
|
|
|
|
Ar.UsingCustomVersion(FBlueprintsObjectVersion::GUID);
|
|
// Fix up legacy nodes that may not yet have a delegate pin
|
|
if(Ar.IsLoading())
|
|
{
|
|
if(Ar.UEVer() < VER_UE4_K2NODE_EVENT_MEMBER_REFERENCE)
|
|
{
|
|
EventReference.SetExternalMember(EventSignatureName_DEPRECATED, EventSignatureClass_DEPRECATED);
|
|
}
|
|
|
|
if (Ar.CustomVer(FBlueprintsObjectVersion::GUID) < FBlueprintsObjectVersion::OverridenEventReferenceFixup)
|
|
{
|
|
FixupEventReference();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UK2Node_Event::PostLoad()
|
|
{
|
|
UK2Node_EditablePinBase::PostLoad();
|
|
|
|
// Fix up legacy nodes that may not yet have a delegate pin
|
|
if (!FindPin(DelegateOutputName))
|
|
{
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Delegate, DelegateOutputName);
|
|
}
|
|
}
|
|
|
|
void UK2Node_Event::PostDuplicate(bool bDuplicateForPIE)
|
|
{
|
|
Super::PostDuplicate(bDuplicateForPIE);
|
|
if (!bDuplicateForPIE)
|
|
{
|
|
FixupEventReference();
|
|
}
|
|
}
|
|
|
|
FNodeHandlingFunctor* UK2Node_Event::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const
|
|
{
|
|
return new FKCHandler_EventEntry(CompilerContext);
|
|
}
|
|
|
|
|
|
FLinearColor UK2Node_Event::GetNodeTitleColor() const
|
|
{
|
|
return GetDefault<UGraphEditorSettings>()->EventNodeTitleColor;
|
|
}
|
|
|
|
FText UK2Node_Event::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
|
{
|
|
if (bOverrideFunction || (CustomFunctionName == NAME_None))
|
|
{
|
|
FText FunctionName = FText::FromName(EventReference.GetMemberName()); // If we fail to find the function, still want to write something on the node.
|
|
|
|
if (UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()))
|
|
{
|
|
FunctionName = UEdGraphSchema_K2::GetFriendlySignatureName(Function);
|
|
}
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("FunctionName"), FunctionName);
|
|
FText Title = FText::Format(NSLOCTEXT("K2Node", "Event_Name", "Event {FunctionName}"), Args);
|
|
|
|
if(TitleType == ENodeTitleType::FullTitle && EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) != nullptr && EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->IsChildOf(UInterface::StaticClass()))
|
|
{
|
|
const FText SignatureClassAsText = FBlueprintEditorUtils::GetFriendlyClassDisplayName(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()));
|
|
|
|
FFormatNamedArguments FullTitleArgs;
|
|
FullTitleArgs.Add(TEXT("Title"), Title);
|
|
FullTitleArgs.Add(TEXT("InterfaceClass"), SignatureClassAsText);
|
|
|
|
Title = FText::Format(LOCTEXT("EventFromInterface", "{Title}\nFrom {InterfaceClass}"), FullTitleArgs);
|
|
}
|
|
|
|
return Title;
|
|
}
|
|
else
|
|
{
|
|
return FText::FromName(CustomFunctionName);
|
|
}
|
|
}
|
|
|
|
FText UK2Node_Event::GetTooltipText() const
|
|
{
|
|
UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
if (CachedTooltip.IsOutOfDate(this) && (Function != nullptr))
|
|
{
|
|
CachedTooltip.SetCachedText(FText::FromString(ObjectTools::GetDefaultTooltipForFunction(Function)), this);
|
|
|
|
if (bOverrideFunction || (CustomFunctionName == NAME_None))
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("FunctionTooltip"), (FText&)CachedTooltip);
|
|
|
|
//@TODO: KISMETREPLICATION: Should do this for events with a custom function name, if it's a newly introduced replicating thingy
|
|
if (Function->HasAllFunctionFlags(FUNC_BlueprintCosmetic) || IsCosmeticTickEvent())
|
|
{
|
|
Args.Add(
|
|
TEXT("ClientString"),
|
|
NSLOCTEXT("K2Node", "ClientEvent", "\n\nCosmetic. This event is only for cosmetic, non-gameplay actions.")
|
|
);
|
|
// FText::Format() is slow, so we cache this to save on performance
|
|
CachedTooltip.SetCachedText(FText::Format(LOCTEXT("Event_SubtitledTooltip", "{FunctionTooltip}\n\n{ClientString}"), Args), this);
|
|
}
|
|
else if(Function->HasAllFunctionFlags(FUNC_BlueprintAuthorityOnly))
|
|
{
|
|
Args.Add(
|
|
TEXT("ClientString"),
|
|
NSLOCTEXT("K2Node", "ServerEvent", "Authority Only. This event only fires on the server.")
|
|
);
|
|
// FText::Format() is slow, so we cache this to save on performance
|
|
CachedTooltip.SetCachedText(FText::Format(LOCTEXT("Event_SubtitledTooltip", "{FunctionTooltip}\n\n{ClientString}"), Args), this);
|
|
}
|
|
else if (Function->HasMetaData(FBlueprintMetadata::MD_Latent))
|
|
{
|
|
Args.Add(
|
|
TEXT("LatentString"),
|
|
NSLOCTEXT("K2Node", "LatentFunction", "Latent. This node will complete at a later time. Latent nodes can only be placed in event graphs.")
|
|
);
|
|
// FText::Format() is slow, so we cache this to save on performance
|
|
CachedTooltip.SetCachedText(FText::Format(LOCTEXT("CallFunction_SubtitledTooltip", "{DefaultTooltip}\n\n{LatentString}"), Args), this);
|
|
}
|
|
}
|
|
}
|
|
|
|
return CachedTooltip;
|
|
}
|
|
|
|
FText UK2Node_Event::GetKeywords() const
|
|
{
|
|
FText Keywords;
|
|
|
|
UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
if (Function != nullptr)
|
|
{
|
|
Keywords = UK2Node_CallFunction::GetKeywordsForFunction( Function );
|
|
}
|
|
|
|
return Keywords;
|
|
}
|
|
|
|
FString UK2Node_Event::GetDocumentationLink() const
|
|
{
|
|
if ( UClass* EventSignatureClass = EventReference.GetMemberParentClass(GetBlueprintClassFromNode()))
|
|
{
|
|
return FString::Printf(TEXT("Shared/Types/%s%s"), EventSignatureClass->GetPrefixCPP(), *EventSignatureClass->GetName());
|
|
}
|
|
|
|
return FString();
|
|
}
|
|
|
|
FString UK2Node_Event::GetDocumentationExcerptName() const
|
|
{
|
|
return EventReference.GetMemberName().ToString();
|
|
}
|
|
|
|
void UK2Node_Event::PostReconstructNode()
|
|
{
|
|
UpdateDelegatePin();
|
|
|
|
Super::PostReconstructNode();
|
|
}
|
|
|
|
|
|
void UK2Node_Event::FixupEventReference(bool bForce /*= false*/)
|
|
{
|
|
if (bOverrideFunction && !HasAnyFlags(RF_Transient))
|
|
{
|
|
if (!EventReference.IsSelfContext())
|
|
{
|
|
UBlueprint* Blueprint = GetBlueprint();
|
|
UClass* BlueprintType = (Blueprint != nullptr) ? Blueprint->SkeletonGeneratedClass : nullptr;
|
|
|
|
UClass* ParentType = EventReference.GetMemberParentClass();
|
|
|
|
if (BlueprintType && (bForce || !ParentType || !(BlueprintType->IsChildOf(ParentType) || BlueprintType->ImplementsInterface(ParentType))))
|
|
{
|
|
FName EventName = EventReference.GetMemberName();
|
|
|
|
const UFunction* OverriddenFunc = BlueprintType->FindFunctionByName(EventName);
|
|
while (OverriddenFunc != nullptr)
|
|
{
|
|
if (UFunction* SuperFunc = OverriddenFunc->GetSuperFunction())
|
|
{
|
|
OverriddenFunc = SuperFunc;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (OverriddenFunc != nullptr)
|
|
{
|
|
UClass* SuperClass = OverriddenFunc->GetOwnerClass();
|
|
if (UBlueprint* SuperBlueprint = Cast<UBlueprint>(SuperClass->ClassGeneratedBy))
|
|
{
|
|
SuperClass = SuperBlueprint->GeneratedClass;
|
|
}
|
|
|
|
if (SuperClass != nullptr)
|
|
{
|
|
EventReference.SetExternalMember(EventName, SuperClass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UK2Node_Event::UpdateDelegatePin(bool bSilent)
|
|
{
|
|
UEdGraphPin* Pin = FindPinChecked(DelegateOutputName);
|
|
checkSlow(EGPD_Output == Pin->Direction);
|
|
|
|
const UObject* OldSignature = FMemberReference::ResolveSimpleMemberReference<UFunction>(Pin->PinType.PinSubCategoryMemberReference);
|
|
if (!OldSignature)
|
|
{
|
|
OldSignature = Pin->PinType.PinSubCategoryObject.Get();
|
|
}
|
|
|
|
UFunction* NewSignature = nullptr;
|
|
if(bOverrideFunction)
|
|
{
|
|
NewSignature = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
}
|
|
else if(UBlueprint* Blueprint = GetBlueprint())
|
|
{
|
|
NewSignature = Blueprint->SkeletonGeneratedClass
|
|
? Blueprint->SkeletonGeneratedClass->FindFunctionByName(CustomFunctionName)
|
|
: nullptr;
|
|
}
|
|
|
|
Pin->PinType.PinSubCategoryObject = nullptr;
|
|
FMemberReference::FillSimpleMemberReference<UFunction>(NewSignature, Pin->PinType.PinSubCategoryMemberReference);
|
|
|
|
if ((OldSignature != NewSignature) && !bSilent)
|
|
{
|
|
PinTypeChanged(Pin);
|
|
}
|
|
}
|
|
|
|
void UK2Node_Event::PinConnectionListChanged(UEdGraphPin* Pin)
|
|
{
|
|
if(Pin == FindPin(DelegateOutputName))
|
|
{
|
|
UpdateDelegatePin();
|
|
}
|
|
|
|
Super::PinConnectionListChanged(Pin);
|
|
}
|
|
|
|
FName UK2Node_Event::GetFunctionName() const
|
|
{
|
|
return bOverrideFunction ? EventReference.GetMemberName() : CustomFunctionName;
|
|
}
|
|
|
|
UFunction* UK2Node_Event::FindEventSignatureFunction() const
|
|
{
|
|
return EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
}
|
|
|
|
void UK2Node_Event::AllocateDefaultPins()
|
|
{
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Delegate, DelegateOutputName);
|
|
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
|
|
|
|
// If the function signature is currently invalid then try and fix the event reference
|
|
// in case the function has moved to some other valid location from the last compile
|
|
UFunction* Function = FindEventSignatureFunction();
|
|
|
|
if (!Function)
|
|
{
|
|
FixupEventReference(/*bForce*/ true);
|
|
Function = FindEventSignatureFunction();
|
|
}
|
|
|
|
if (Function)
|
|
{
|
|
CreatePinsForFunctionEntryExit(Function, /*bIsFunctionEntry=*/ true);
|
|
}
|
|
|
|
UpdateDelegatePin(true);
|
|
|
|
Super::AllocateDefaultPins();
|
|
}
|
|
|
|
void UK2Node_Event::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const
|
|
{
|
|
Super::ValidateNodeDuringCompilation(MessageLog);
|
|
|
|
UFunction* Function = nullptr;
|
|
if (bOverrideFunction)
|
|
{
|
|
Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
if (!Function)
|
|
{
|
|
// If we are overriding a function, but we can;t find the function we are overriding, that is a compile error
|
|
MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "MissingEventSig_ErrorFmt", "Missing Event '{0}' for @@"), FText::FromString(EventReference.GetMemberName().ToString())).ToString(), this);
|
|
}
|
|
else if(Function->HasAnyFunctionFlags(FUNC_Const|FUNC_BlueprintPure))
|
|
{
|
|
// The implicit writes of object parameters to the event graph frame can violate clustering rules, so this is
|
|
// noting some quite severe shortcomings in the blueprint compiler - but starting with a note while we address
|
|
// those:
|
|
MessageLog.Note(*FText::Format(NSLOCTEXT("KismetCompiler", "EventOverridingConst_Fmt", "@@: Event overriding '{0}', which is const, implicitly writes to this object. Please convert this to a function - ESPECIALLY if this event has Object parameters"), FText::FromString(EventReference.GetMemberName().ToString())).ToString(), this);
|
|
}
|
|
}
|
|
else if (UBlueprint* Blueprint = GetBlueprint())
|
|
{
|
|
Function = Blueprint->SkeletonGeneratedClass
|
|
? Blueprint->SkeletonGeneratedClass->FindFunctionByName(CustomFunctionName)
|
|
: nullptr;
|
|
}
|
|
|
|
FKismetCompilerUtilities::DetectValuesReturnedByRef(Function, this, MessageLog);
|
|
}
|
|
|
|
bool UK2Node_Event::NodeCausesStructuralBlueprintChange() const
|
|
{
|
|
// FBlueprintEditor::CanAddParentNode requires actual data in skel class
|
|
return true;
|
|
}
|
|
|
|
void UK2Node_Event::GetRedirectPinNames(const UEdGraphPin& Pin, TArray<FString>& RedirectPinNames) const
|
|
{
|
|
Super::GetRedirectPinNames(Pin, RedirectPinNames);
|
|
|
|
if ( RedirectPinNames.Num() > 0 )
|
|
{
|
|
const FString OldPinName = RedirectPinNames[0];
|
|
|
|
// first add functionname.param
|
|
RedirectPinNames.Add(FString::Printf(TEXT("%s.%s"), *EventReference.GetMemberName().ToString(), *OldPinName));
|
|
// if there is class, also add an option for class.functionname.param
|
|
if ( EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()) != nullptr )
|
|
{
|
|
if(const UClass* EventSignatureClass = EventReference.GetMemberParentClass(GetBlueprintClassFromNode()))
|
|
{
|
|
RedirectPinNames.Add(FString::Printf(TEXT("%s.%s.%s"), *EventSignatureClass->GetName(), *EventReference.GetMemberName().ToString(), *OldPinName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UK2Node_Event::IsFunctionEntryCompatible(const UK2Node_FunctionEntry* EntryNode) const
|
|
{
|
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
|
|
|
// Copy a set of the pin references for both nodes, so we can pare down lists
|
|
TArray<UEdGraphPin*> EventPins = Pins;
|
|
TArray<UEdGraphPin*> EntryPins = EntryNode->Pins;
|
|
|
|
// Prune the exec wires and inputs (delegate binding) from both sets
|
|
for(int32 i = 0; i < EventPins.Num(); i++)
|
|
{
|
|
const UEdGraphPin* CurPin = EventPins[i];
|
|
if( CurPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec
|
|
|| CurPin->PinType.PinSubCategory == UEdGraphSchema_K2::PSC_Self
|
|
|| CurPin->PinName == DelegateOutputName
|
|
|| CurPin->Direction == EGPD_Input
|
|
|| CurPin->ParentPin != nullptr )
|
|
{
|
|
EventPins.RemoveAt(i, 1);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
for(int32 i = 0; i < EntryPins.Num(); i++)
|
|
{
|
|
const UEdGraphPin* CurPin = EntryPins[i];
|
|
if( CurPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec
|
|
|| CurPin->PinType.PinSubCategory == UEdGraphSchema_K2::PSC_Self
|
|
|| CurPin->PinName == DelegateOutputName
|
|
|| CurPin->Direction == EGPD_Input
|
|
|| CurPin->ParentPin != nullptr )
|
|
{
|
|
EntryPins.RemoveAt(i, 1);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
// Early out: we don't have the same number of parameters
|
|
if( EventPins.Num() != EntryPins.Num() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Now check through the event's pins, and check for compatible pins, removing them if we find a match.
|
|
for( int32 i = 0; i < EventPins.Num(); i++ )
|
|
{
|
|
const UEdGraphPin* CurEventPin = EventPins[i];
|
|
|
|
bool bMatchFound = false;
|
|
for( int32 j = 0; j < EntryPins.Num(); j++ )
|
|
{
|
|
const UEdGraphPin* CurEntryPin = EntryPins[j];
|
|
if( CurEntryPin->PinName == CurEventPin->PinName )
|
|
{
|
|
// Check to make sure pins are of the same type
|
|
if( K2Schema->ArePinTypesCompatible(CurEntryPin->PinType, CurEventPin->PinType) )
|
|
{
|
|
// Found a match, remove it from the list
|
|
bMatchFound = true;
|
|
EntryPins.RemoveAt(j, 1);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Found a pin, but the type has changed, bail.
|
|
bMatchFound = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bMatchFound )
|
|
{
|
|
// Found a match, remove it from the event array
|
|
EventPins.RemoveAt(i, 1);
|
|
i--;
|
|
}
|
|
else
|
|
{
|
|
// Didn't find a match...bail!
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Checked for matches, if any pins remain in either array, they were unmatched.
|
|
return (EventPins.Num() == 0) && (EntryPins.Num() == 0);
|
|
}
|
|
|
|
bool UK2Node_Event::IsInterfaceEventNode() const
|
|
{
|
|
return (EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) != nullptr) && EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->IsChildOf(UInterface::StaticClass());
|
|
}
|
|
|
|
bool UK2Node_Event::IsCompatibleWithGraph(const UEdGraph* TargetGraph) const
|
|
{
|
|
bool bIsCompatible = Super::IsCompatibleWithGraph(TargetGraph);
|
|
if (bIsCompatible)
|
|
{
|
|
EGraphType const GraphType = TargetGraph->GetSchema()->GetGraphType(TargetGraph);
|
|
bIsCompatible = (GraphType == EGraphType::GT_Ubergraph);
|
|
}
|
|
|
|
return bIsCompatible;
|
|
}
|
|
|
|
bool UK2Node_Event::CanPasteHere(const UEdGraph* TargetGraph) const
|
|
{
|
|
// By default, to be safe, we don't allow events to be pasted, except under special circumstances (see below)
|
|
bool bDisallowPaste = !Super::CanPasteHere(TargetGraph);
|
|
if(!bDisallowPaste)
|
|
{
|
|
// Find the Blueprint that owns the target graph
|
|
UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(TargetGraph);
|
|
if(Blueprint && Blueprint->SkeletonGeneratedClass)
|
|
{
|
|
TSet<FName> ExistingNamesInUse;
|
|
TArray<FString> ExcludedEventNames;
|
|
TArray<UK2Node_Event*> ExistingEventNodes;
|
|
TArray<UClass*> ImplementedInterfaceClasses;
|
|
|
|
// Gather all names in use by the Blueprint class
|
|
FBlueprintEditorUtils::GetFunctionNameList(Blueprint, ExistingNamesInUse);
|
|
FBlueprintEditorUtils::GetClassVariableList(Blueprint, ExistingNamesInUse);
|
|
|
|
// Gather all existing event nodes
|
|
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(Blueprint, ExistingEventNodes);
|
|
|
|
// Gather any event names excluded by the Blueprint class
|
|
const FString ExclusionListKeyName = TEXT("KismetHideOverrides");
|
|
if(Blueprint->ParentClass->HasMetaData(*ExclusionListKeyName))
|
|
{
|
|
const FString& ExcludedEventNameString = Blueprint->ParentClass->GetMetaData(*ExclusionListKeyName);
|
|
ExcludedEventNameString.ParseIntoArray(ExcludedEventNames, TEXT(","), true);
|
|
}
|
|
|
|
// Gather all interfaces implemented by the Blueprint class
|
|
FBlueprintEditorUtils::FindImplementedInterfaces(Blueprint, true, ImplementedInterfaceClasses);
|
|
|
|
// If this is an internal event, don't paste this event
|
|
if(!bInternalEvent)
|
|
{
|
|
// If this is a function override
|
|
if(bOverrideFunction)
|
|
{
|
|
// If the function name is hidden by the parent class, don't paste this event
|
|
bDisallowPaste = EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) == Blueprint->ParentClass
|
|
&& ExcludedEventNames.Contains(EventReference.GetMemberName().ToString());
|
|
if(!bDisallowPaste)
|
|
{
|
|
TArray<UK2Node_Event*> DisabledEventNodesToStomp;
|
|
// If the event function is already handled in this Blueprint, don't paste this event
|
|
for(int32 i = 0; i < ExistingEventNodes.Num() && !bDisallowPaste; ++i)
|
|
{
|
|
bDisallowPaste = ExistingEventNodes[i]->bOverrideFunction /*&& ExistingEventNodes[i]->IsNodeEnabled() */&& AreEventNodesIdentical(this, ExistingEventNodes[i]);
|
|
|
|
if (bDisallowPaste && !ExistingEventNodes[i]->IsNodeEnabled())
|
|
{
|
|
DisabledEventNodesToStomp.Add(ExistingEventNodes[i]);
|
|
bDisallowPaste = false;
|
|
}
|
|
}
|
|
|
|
// We need to also check for 'const' BPIE methods that might already be implemented as functions with a read-only 'self' context (these were previously implemented as events)
|
|
if(!bDisallowPaste)
|
|
{
|
|
TArray<UBlueprint*> ParentBPStack;
|
|
UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->SkeletonGeneratedClass, ParentBPStack);
|
|
for(auto BPStackIt = ParentBPStack.CreateConstIterator(); BPStackIt && !bDisallowPaste; ++BPStackIt)
|
|
{
|
|
TArray<UK2Node_FunctionEntry*> ExistingFunctionEntryNodes;
|
|
FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_FunctionEntry>(*BPStackIt, ExistingFunctionEntryNodes);
|
|
for(auto NodeIt = ExistingFunctionEntryNodes.CreateConstIterator(); NodeIt && !bDisallowPaste; ++NodeIt)
|
|
{
|
|
UK2Node_FunctionEntry* ExistingFunctionEntryNode = *NodeIt;
|
|
bDisallowPaste = ExistingFunctionEntryNode->bEnforceConstCorrectness
|
|
&& ExistingFunctionEntryNode->FunctionReference.GetMemberName() == EventReference.GetMemberName();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!bDisallowPaste)
|
|
{
|
|
// If the signature class is not implemented by the Blueprint parent class or an interface, don't paste this event
|
|
bDisallowPaste = !Blueprint->ParentClass->IsChildOf(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()))
|
|
&& !ImplementedInterfaceClasses.Contains(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()));
|
|
if(bDisallowPaste)
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because the event signature class (%s) is incompatible with this Blueprint."), *GetFName().ToString(), EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) ? *EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->GetFName().ToString() : TEXT("NONE"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because the event function (%s) is already handled."), *GetFName().ToString(), *EventReference.GetMemberName().ToString());
|
|
}
|
|
|
|
if (!bDisallowPaste)
|
|
{
|
|
for (UK2Node_Event* EventNode : DisabledEventNodesToStomp)
|
|
{
|
|
EventNode->DestroyNode();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because the event function (%s) is hidden by the Blueprint parent class (%s)."), *GetFName().ToString(), *EventReference.GetMemberName().ToString(), EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) ? *EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->GetFName().ToString() : TEXT("NONE"));
|
|
}
|
|
}
|
|
else if(CustomFunctionName != NAME_None)
|
|
{
|
|
// If this name is already in use, we can't paste this event
|
|
bDisallowPaste = ExistingNamesInUse.Contains(CustomFunctionName);
|
|
|
|
if(!bDisallowPaste)
|
|
{
|
|
// Handle events that have a custom function name with an actual signature name/class that is not an override (e.g. AnimNotify events)
|
|
if(EventReference.GetMemberName() != NAME_None)
|
|
{
|
|
// If the signature class is not implemented by the Blueprint parent class or an interface, don't paste this event
|
|
bDisallowPaste = !Blueprint->ParentClass->IsChildOf(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()))
|
|
&& !ImplementedInterfaceClasses.Contains(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()));
|
|
if(bDisallowPaste)
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because the custom event function (%s) with event signature name (%s) has an event signature class (%s) that is incompatible with this Blueprint."), *GetFName().ToString(), *CustomFunctionName.ToString(), *EventReference.GetMemberName().ToString(), EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) ? *EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->GetFName().ToString() : TEXT("NONE"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because the custom event function (%s) is already handled."), *GetFName().ToString(), *CustomFunctionName.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because the event configuration is not specifically handled (EventSignatureName=%s, EventSignatureClass=%s)."), *GetFName().ToString(), *EventReference.GetMemberName().ToString(), EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) ? *EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->GetFName().ToString() : TEXT("NONE"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogBlueprint, Log, TEXT("Cannot paste event node (%s) directly because it is flagged as an internal event."), *GetFName().ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
return !bDisallowPaste;
|
|
}
|
|
|
|
FText UK2Node_Event::GetLocalizedNetString(uint32 FunctionFlags, bool Calling)
|
|
{
|
|
FText RPCString;
|
|
if (FunctionFlags & FUNC_Net)
|
|
{
|
|
if (FunctionFlags & FUNC_NetMulticast)
|
|
{
|
|
if (Calling)
|
|
{
|
|
RPCString = NSLOCTEXT("K2Node", "CustomEvent_ReplicatedMulticast", "Replicated To All (if server)");
|
|
}
|
|
else
|
|
{
|
|
RPCString = NSLOCTEXT("K2Node", "CustomEvent_ReplicatedMulticastFrom", "Replicated From Server\nExecutes On All");
|
|
}
|
|
}
|
|
else if (FunctionFlags & FUNC_NetServer)
|
|
{
|
|
if (Calling)
|
|
{
|
|
RPCString = NSLOCTEXT("K2Node", "CustomEvent_ReplicatedServer", "Replicated To Server (if owning client)");
|
|
}
|
|
else
|
|
{
|
|
RPCString = NSLOCTEXT("K2Node", "CustomEvent_ReplicatedServerFrom", "Replicated From Client\nExecutes On Server");
|
|
}
|
|
}
|
|
else if (FunctionFlags & FUNC_NetClient)
|
|
{
|
|
if (Calling)
|
|
{
|
|
RPCString = NSLOCTEXT("K2Node", "CustomEvent_ReplicatedClient", "Replicated To Owning Client (if server)");
|
|
}
|
|
else
|
|
{
|
|
RPCString = NSLOCTEXT("K2Node", "CustomEvent_ReplicatedClientFrom", "Replicated From Server\nExecutes on Owning Client");
|
|
}
|
|
}
|
|
|
|
if (FunctionFlags & FUNC_NetReliable)
|
|
{
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("RPCString"), RPCString);
|
|
RPCString = FText::Format(NSLOCTEXT("K2Node", "CustomEvent_ReplicatedReliable", "RELIABLE {RPCString}"), Args);
|
|
}
|
|
}
|
|
return RPCString;
|
|
}
|
|
|
|
void UK2Node_Event::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
|
|
{
|
|
Super::ExpandNode(CompilerContext, SourceGraph);
|
|
|
|
UEdGraphPin* OrgDelegatePin = FindPin(UK2Node_Event::DelegateOutputName);
|
|
if (OrgDelegatePin && OrgDelegatePin->LinkedTo.Num() > 0)
|
|
{
|
|
const UEdGraphSchema_K2* Schema = CompilerContext.GetSchema();
|
|
|
|
const FName FunctionName = GetFunctionName();
|
|
if(FunctionName == NAME_None)
|
|
{
|
|
CompilerContext.MessageLog.Error(*LOCTEXT("EventDelegateName_Error", "Event node @@ has no name of function.").ToString(), this);
|
|
}
|
|
|
|
UK2Node_Self* SelfNode = CompilerContext.SpawnIntermediateNode<UK2Node_Self>(this, SourceGraph);
|
|
SelfNode->AllocateDefaultPins();
|
|
|
|
UK2Node_CreateDelegate* CreateDelegateNode = CompilerContext.SpawnIntermediateNode<UK2Node_CreateDelegate>(this, SourceGraph);
|
|
CreateDelegateNode->AllocateDefaultPins();
|
|
CompilerContext.MovePinLinksToIntermediate(*OrgDelegatePin, *CreateDelegateNode->GetDelegateOutPin());
|
|
Schema->TryCreateConnection(SelfNode->FindPinChecked(UEdGraphSchema_K2::PN_Self), CreateDelegateNode->GetObjectInPin());
|
|
// When called UFunction is defined in the same class, it wasn't created yet (previously the Skeletal class was checked). So no "CreateDelegateNode->HandleAnyChangeWithoutNotifying();" is called.
|
|
CreateDelegateNode->SetFunction(FunctionName);
|
|
}
|
|
}
|
|
|
|
FName UK2Node_Event::GetCornerIcon() const
|
|
{
|
|
if (UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()))
|
|
{
|
|
if (bOverrideFunction || (CustomFunctionName == NAME_None))
|
|
{
|
|
//@TODO: KISMETREPLICATION: Should do this for events with a custom function name, if it's a newly introduced replicating thingy
|
|
if (Function->HasAllFunctionFlags(FUNC_BlueprintCosmetic) || IsCosmeticTickEvent())
|
|
{
|
|
return TEXT("Graph.Replication.ClientEvent");
|
|
}
|
|
else if(Function->HasAllFunctionFlags(FUNC_BlueprintAuthorityOnly))
|
|
{
|
|
return TEXT("Graph.Replication.AuthorityOnly");
|
|
}
|
|
else if (Function->HasMetaData(FBlueprintMetadata::MD_Latent))
|
|
{
|
|
return TEXT("Graph.Latent.LatentIcon");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(IsUsedByAuthorityOnlyDelegate())
|
|
{
|
|
return TEXT("Graph.Replication.AuthorityOnly");
|
|
}
|
|
|
|
if(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) != nullptr && EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->IsChildOf(UInterface::StaticClass()))
|
|
{
|
|
return TEXT("Graph.Event.InterfaceEventIcon");
|
|
}
|
|
|
|
return Super::GetCornerIcon();
|
|
}
|
|
|
|
FText UK2Node_Event::GetToolTipHeading() const
|
|
{
|
|
FText Heading = Super::GetToolTipHeading();
|
|
|
|
FText EventHeading = FText::GetEmpty();
|
|
if (UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()))
|
|
{
|
|
if (bOverrideFunction || (CustomFunctionName == NAME_None))
|
|
{
|
|
if (Function->HasAllFunctionFlags(FUNC_BlueprintCosmetic) || IsCosmeticTickEvent())
|
|
{
|
|
EventHeading = LOCTEXT("ClinetOnlyEvent", "Client Only");
|
|
}
|
|
else if(Function->HasAllFunctionFlags(FUNC_BlueprintAuthorityOnly))
|
|
{
|
|
EventHeading = LOCTEXT("ServerOnlyEvent", "Server Only");
|
|
}
|
|
else if (Function->HasMetaData(FBlueprintMetadata::MD_Latent))
|
|
{
|
|
EventHeading = LOCTEXT("LatentEvent", "Latent");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EventHeading.IsEmpty() && IsUsedByAuthorityOnlyDelegate())
|
|
{
|
|
EventHeading = LOCTEXT("ServerOnlyEvent", "Server Only");
|
|
}
|
|
else if(EventHeading.IsEmpty() && IsInterfaceEventNode())
|
|
{
|
|
EventHeading = LOCTEXT("InterfaceEvent", "Interface Event");
|
|
}
|
|
|
|
FText CompleteHeading = Super::GetToolTipHeading();
|
|
if (!CompleteHeading.IsEmpty() && !EventHeading.IsEmpty())
|
|
{
|
|
CompleteHeading = FText::Format(FText::FromString("{0}\n{1}"), EventHeading, CompleteHeading);
|
|
}
|
|
else if (!EventHeading.IsEmpty())
|
|
{
|
|
CompleteHeading = EventHeading;
|
|
}
|
|
return CompleteHeading;
|
|
}
|
|
|
|
void UK2Node_Event::GetNodeAttributes( TArray<TKeyValuePair<FString, FString>>& OutNodeAttributes ) const
|
|
{
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "Type" ), TEXT( "Event" ) ));
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "Class" ), GetClass()->GetName() ));
|
|
OutNodeAttributes.Add( TKeyValuePair<FString, FString>( TEXT( "Name" ), GetFunctionName().ToString() ));
|
|
}
|
|
|
|
FText UK2Node_Event::GetMenuCategory() const
|
|
{
|
|
FText FunctionCategory = LOCTEXT("AddEventCategory", "Add Event");
|
|
if (UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()))
|
|
{
|
|
FunctionCategory = UK2Node_CallFunction::GetDefaultCategoryForFunction(Function, FunctionCategory);
|
|
}
|
|
return FunctionCategory;
|
|
}
|
|
|
|
bool UK2Node_Event::HasDeprecatedReference() const
|
|
{
|
|
if (UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode()))
|
|
{
|
|
return Function->HasMetaData(FBlueprintMetadata::MD_DeprecatedFunction);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FEdGraphNodeDeprecationResponse UK2Node_Event::GetDeprecationResponse(EEdGraphNodeDeprecationType DeprecationType) const
|
|
{
|
|
FEdGraphNodeDeprecationResponse Response = Super::GetDeprecationResponse(DeprecationType);
|
|
if (DeprecationType == EEdGraphNodeDeprecationType::NodeHasDeprecatedReference)
|
|
{
|
|
// Only warn on override usage.
|
|
if (bOverrideFunction)
|
|
{
|
|
UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
if (ensureMsgf(Function != nullptr, TEXT("This node should not be able to report having a deprecated reference if the event override cannot be resolved.")))
|
|
{
|
|
// Check the deprecation type to override the severity
|
|
FString MessageType = Function->GetMetaData(FBlueprintMetadata::MD_DeprecatedFunction);
|
|
Response.MessageType = FBlueprintEditorUtils::GetDeprecatedMessageType(MessageType);
|
|
|
|
FText EventName = FText::FromName(GetFunctionName());
|
|
FText DetailedMessage = FText::FromString(Function->GetMetaData(FBlueprintMetadata::MD_DeprecationMessage));
|
|
Response.MessageText = FBlueprintEditorUtils::GetDeprecatedMemberUsageNodeWarning(EventName, DetailedMessage);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Allow the source event to be marked as deprecated in the class that defines it without warning, but use a note to visually indicate that the definition itself has been deprecated.
|
|
Response.MessageType = EEdGraphNodeDeprecationMessageType::Note;
|
|
Response.MessageText = LOCTEXT("DeprecatedEventMessage", "@@: This event has been marked as deprecated. It can be safely deleted if all references have been replaced or removed.");
|
|
}
|
|
}
|
|
|
|
return Response;
|
|
}
|
|
|
|
UObject* UK2Node_Event::GetJumpTargetForDoubleClick() const
|
|
{
|
|
if(EventReference.GetMemberParentClass(GetBlueprintClassFromNode()) != NULL && EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->ClassGeneratedBy != NULL && EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->ClassGeneratedBy->IsA(UBlueprint::StaticClass()))
|
|
{
|
|
UBlueprint* Blueprint = CastChecked<UBlueprint>(EventReference.GetMemberParentClass(GetBlueprintClassFromNode())->ClassGeneratedBy);
|
|
TArray<UEdGraph*> Graphs;
|
|
Blueprint->GetAllGraphs(Graphs);
|
|
for(auto It(Graphs.CreateConstIterator()); It; It++)
|
|
{
|
|
if((*It)->GetFName() == EventReference.GetMemberName())
|
|
{
|
|
return *It;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
FSlateIcon UK2Node_Event::GetIconAndTint(FLinearColor& OutColor) const
|
|
{
|
|
static FSlateIcon Icon(FAppStyle::GetAppStyleSetName(), "GraphEditor.Event_16x");
|
|
return Icon;
|
|
}
|
|
|
|
FString UK2Node_Event::GetFindReferenceSearchString_Impl(EGetFindReferenceSearchStringFlags InFlags) const
|
|
{
|
|
// If searching by class member, try to construct search term from the UFunction.
|
|
// This may fail if the function was not found or for whatever reason, its owning
|
|
// class is invalid. If it fails, proceed to search by name as fallback behavior.
|
|
if (EnumHasAnyFlags(InFlags, EGetFindReferenceSearchStringFlags::UseSearchSyntax) && !EnumHasAnyFlags(InFlags, EGetFindReferenceSearchStringFlags::Legacy))
|
|
{
|
|
// Resolve the function
|
|
if (const UFunction* Function = FFunctionFromNodeHelper::FunctionFromNode(this))
|
|
{
|
|
FString SearchTerm;
|
|
if (FindInBlueprintsHelpers::ConstructSearchTermFromFunction(Function, SearchTerm))
|
|
{
|
|
return SearchTerm;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Searching by just name. When overriding a function, try to find the function that it overrides to return its name.
|
|
if (bOverrideFunction || (CustomFunctionName == NAME_None))
|
|
{
|
|
// Attempt to find the function
|
|
if (const UFunction* Function = FFunctionFromNodeHelper::FunctionFromNode(this))
|
|
{
|
|
// Search by native name
|
|
const FString FunctionNativeName = Function->GetName();
|
|
return FString::Printf(TEXT("\"%s\""), *FunctionNativeName);
|
|
}
|
|
else
|
|
{
|
|
// If we fail to find the function, still want to search for its expected name, in quotes
|
|
return FString::Printf(TEXT("\"%s\""), *EventReference.GetMemberName().ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The function was not an override; its name is defined by this node.
|
|
// Return that name in quotes (treating special characters as part of name)
|
|
return FString::Printf(TEXT("\"%s\""), *CustomFunctionName.ToString());
|
|
}
|
|
}
|
|
|
|
void UK2Node_Event::FindDiffs(UEdGraphNode* OtherNode, struct FDiffResults& Results)
|
|
{
|
|
Super::FindDiffs(OtherNode, Results);
|
|
UK2Node_Event* OtherFunction = Cast<UK2Node_Event>(OtherNode);
|
|
|
|
if (OtherFunction)
|
|
{
|
|
if (FunctionFlags != OtherFunction->FunctionFlags)
|
|
{
|
|
FDiffSingleResult Diff;
|
|
Diff.Diff = EDiffType::NODE_PROPERTY;
|
|
Diff.Node1 = this;
|
|
Diff.Node2 = OtherNode;
|
|
Diff.DisplayString = LOCTEXT("DIF_EventFlags", "Event flags have changed");
|
|
Diff.Category = EDiffType::MODIFICATION;
|
|
|
|
Results.Add(Diff);
|
|
}
|
|
}
|
|
}
|
|
|
|
UEdGraphPin* UK2Node_Event::GetDelegatePin() const
|
|
{
|
|
return FindPinChecked(DelegateOutputName);
|
|
}
|
|
|
|
bool UK2Node_Event::AreEventNodesIdentical(const UK2Node_Event* InNodeA, const UK2Node_Event* InNodeB)
|
|
{
|
|
return InNodeA->EventReference.GetMemberName() == InNodeB->EventReference.GetMemberName()
|
|
&& InNodeA->EventReference.GetMemberParentClass(InNodeA->GetBlueprintClassFromNode()) == InNodeB->EventReference.GetMemberParentClass(InNodeB->GetBlueprintClassFromNode());
|
|
}
|
|
|
|
bool UK2Node_Event::HasExternalDependencies(TArray<class UStruct*>* OptionalOutput) const
|
|
{
|
|
const UBlueprint* SourceBlueprint = GetBlueprint();
|
|
|
|
UFunction* Function = EventReference.ResolveMember<UFunction>(GetBlueprintClassFromNode());
|
|
const UClass* SourceClass = Function ? Function->GetOwnerClass() : nullptr;
|
|
const bool bResult = (SourceClass != nullptr) && (SourceClass->ClassGeneratedBy.Get() != SourceBlueprint);
|
|
if (bResult && OptionalOutput)
|
|
{
|
|
OptionalOutput->AddUnique(Function);
|
|
}
|
|
|
|
const bool bSuperResult = Super::HasExternalDependencies(OptionalOutput);
|
|
return bSuperResult || bResult;
|
|
}
|
|
|
|
void UK2Node_Event::AddSearchMetaDataInfo(TArray<FSearchTagDataPair>& OutTaggedMetaData) const
|
|
{
|
|
Super::AddSearchMetaDataInfo(OutTaggedMetaData);
|
|
|
|
if (const UFunction* Function = FFunctionFromNodeHelper::FunctionFromNode(this))
|
|
{
|
|
// Index the native name of the function, this will be used in search queries rather than node title
|
|
const FString FunctionNativeName = Function->GetName();
|
|
OutTaggedMetaData.Add(FSearchTagDataPair(FFindInBlueprintSearchTags::FiB_NativeName, FText::FromString(FunctionNativeName)));
|
|
|
|
// Index the (ancestor) class or interface from which the function originates, can be self
|
|
if (const UClass* FuncOriginClass = FindInBlueprintsHelpers::GetFunctionOriginClass(Function))
|
|
{
|
|
const FString FuncOriginClassName = FuncOriginClass->GetPathName();
|
|
OutTaggedMetaData.Add(FSearchTagDataPair(FFindInBlueprintSearchTags::FiB_FuncOriginClass, FText::FromString(FuncOriginClassName)));
|
|
}
|
|
}
|
|
}
|
|
|
|
TSharedPtr<FEdGraphSchemaAction> UK2Node_Event::GetEventNodeAction(const FText& ActionCategory)
|
|
{
|
|
TSharedPtr<FEdGraphSchemaAction_K2Event> EventNodeAction = MakeShareable(new FEdGraphSchemaAction_K2Event(ActionCategory, GetNodeTitle(ENodeTitleType::EditableTitle), GetTooltipText(), 0));
|
|
EventNodeAction->NodeTemplate = this;
|
|
return EventNodeAction;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|