208 lines
6.6 KiB
C++
208 lines
6.6 KiB
C++
// Copyright (c) 2026 Unreal Directive. Licensed under the MIT License.
|
|
|
|
#include "Nodes/K2Node_DirectiveUtilMapAppend.h"
|
|
|
|
#include "BlueprintActionDatabaseRegistrar.h"
|
|
#include "BlueprintNodeSpawner.h"
|
|
#include "EdGraph/EdGraph.h"
|
|
#include "EdGraph/EdGraphPin.h"
|
|
#include "EdGraphSchema_K2.h"
|
|
#include "Kismet2/CompilerResultsLog.h"
|
|
#include "Libraries/DirectiveUtilMapFunctionLibrary.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "K2Node_DirectiveUtilMapAppend"
|
|
|
|
namespace DirectiveUtilMapAppendPins
|
|
{
|
|
const FName TargetMap(TEXT("TargetMap"));
|
|
const FName SourceMap(TEXT("SourceMap"));
|
|
}
|
|
|
|
UK2Node_DirectiveUtilMapAppend::UK2Node_DirectiveUtilMapAppend()
|
|
{
|
|
FunctionReference.SetExternalMember(
|
|
GET_FUNCTION_NAME_CHECKED(UDirectiveUtilMapFunctionLibrary, Map_Append),
|
|
UDirectiveUtilMapFunctionLibrary::StaticClass());
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::AllocateDefaultPins()
|
|
{
|
|
Super::AllocateDefaultPins();
|
|
ConformMapPins();
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::PostReconstructNode()
|
|
{
|
|
Super::PostReconstructNode();
|
|
ConformMapPins();
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::NotifyPinConnectionListChanged(UEdGraphPin* Pin)
|
|
{
|
|
Super::NotifyPinConnectionListChanged(Pin);
|
|
|
|
if (IsAppendMapPin(Pin) && ConformMapPins())
|
|
{
|
|
GetGraph()->NotifyGraphChanged();
|
|
}
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const
|
|
{
|
|
Super::ValidateNodeDuringCompilation(MessageLog);
|
|
|
|
const UEdGraphPin* TargetMap = FindPin(DirectiveUtilMapAppendPins::TargetMap);
|
|
const UEdGraphPin* SourceMap = FindPin(DirectiveUtilMapAppendPins::SourceMap);
|
|
if (!TargetMap || !SourceMap || TargetMap->LinkedTo.IsEmpty() || SourceMap->LinkedTo.IsEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!HaveMatchingMapTypes(TargetMap->LinkedTo[0]->PinType, SourceMap->LinkedTo[0]->PinType))
|
|
{
|
|
MessageLog.Error(*LOCTEXT("MismatchedMapTypes", "Append requires matching map types on @@.").ToString(), this);
|
|
}
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
|
{
|
|
UClass* ActionKey = GetClass();
|
|
if (ActionRegistrar.IsOpenForRegistration(ActionKey))
|
|
{
|
|
UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
|
|
check(NodeSpawner);
|
|
ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner);
|
|
}
|
|
}
|
|
|
|
bool UK2Node_DirectiveUtilMapAppend::IsConnectionDisallowed(
|
|
const UEdGraphPin* MyPin,
|
|
const UEdGraphPin* OtherPin,
|
|
FString& OutReason) const
|
|
{
|
|
if (Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!IsAppendMapPin(MyPin) || !OtherPin || !IsConcreteMap(OtherPin->PinType))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FName SiblingName = MyPin->PinName == DirectiveUtilMapAppendPins::TargetMap
|
|
? DirectiveUtilMapAppendPins::SourceMap
|
|
: DirectiveUtilMapAppendPins::TargetMap;
|
|
const UEdGraphPin* SiblingPin = FindPin(SiblingName);
|
|
if (!SiblingPin)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FEdGraphPinType* SiblingType = &SiblingPin->PinType;
|
|
if (!SiblingPin->LinkedTo.IsEmpty())
|
|
{
|
|
SiblingType = &SiblingPin->LinkedTo[0]->PinType;
|
|
}
|
|
|
|
if (IsConcreteMap(*SiblingType) && !HaveMatchingMapTypes(*SiblingType, OtherPin->PinType))
|
|
{
|
|
OutReason = LOCTEXT("MapTypeMismatch", "Both maps must have the same key and value types.").ToString();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UK2Node_DirectiveUtilMapAppend::ConformMapPins()
|
|
{
|
|
UEdGraphPin* TargetMap = FindPin(DirectiveUtilMapAppendPins::TargetMap);
|
|
UEdGraphPin* SourceMap = FindPin(DirectiveUtilMapAppendPins::SourceMap);
|
|
if (!TargetMap || !SourceMap)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const FEdGraphPinType* ResolvedType = nullptr;
|
|
for (const UEdGraphPin* MapPin : {TargetMap, SourceMap})
|
|
{
|
|
if (!MapPin->LinkedTo.IsEmpty() && IsConcreteMap(MapPin->LinkedTo[0]->PinType))
|
|
{
|
|
ResolvedType = &MapPin->LinkedTo[0]->PinType;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const FEdGraphPinType PreviousTargetType = TargetMap->PinType;
|
|
const FEdGraphPinType PreviousSourceType = SourceMap->PinType;
|
|
if (ResolvedType)
|
|
{
|
|
ApplyMapType(*TargetMap, *ResolvedType);
|
|
ApplyMapType(*SourceMap, *ResolvedType);
|
|
}
|
|
else
|
|
{
|
|
ResetMapType(*TargetMap);
|
|
ResetMapType(*SourceMap);
|
|
}
|
|
|
|
return PreviousTargetType != TargetMap->PinType || PreviousSourceType != SourceMap->PinType;
|
|
}
|
|
|
|
bool UK2Node_DirectiveUtilMapAppend::IsAppendMapPin(const UEdGraphPin* Pin)
|
|
{
|
|
return Pin && (Pin->PinName == DirectiveUtilMapAppendPins::TargetMap || Pin->PinName == DirectiveUtilMapAppendPins::SourceMap);
|
|
}
|
|
|
|
bool UK2Node_DirectiveUtilMapAppend::IsConcreteMap(const FEdGraphPinType& PinType)
|
|
{
|
|
return PinType.IsMap()
|
|
&& PinType.PinCategory != UEdGraphSchema_K2::PC_Wildcard
|
|
&& PinType.PinValueType.TerminalCategory != UEdGraphSchema_K2::PC_Wildcard;
|
|
}
|
|
|
|
bool UK2Node_DirectiveUtilMapAppend::HaveMatchingMapTypes(
|
|
const FEdGraphPinType& First,
|
|
const FEdGraphPinType& Second)
|
|
{
|
|
return First.IsMap()
|
|
&& Second.IsMap()
|
|
&& First.PinCategory == Second.PinCategory
|
|
&& First.PinSubCategory == Second.PinSubCategory
|
|
&& First.PinSubCategoryObject == Second.PinSubCategoryObject
|
|
&& First.bIsWeakPointer == Second.bIsWeakPointer
|
|
&& First.bIsUObjectWrapper == Second.bIsUObjectWrapper
|
|
&& First.PinValueType.TerminalCategory == Second.PinValueType.TerminalCategory
|
|
&& First.PinValueType.TerminalSubCategory == Second.PinValueType.TerminalSubCategory
|
|
&& First.PinValueType.TerminalSubCategoryObject == Second.PinValueType.TerminalSubCategoryObject
|
|
&& First.PinValueType.bTerminalIsWeakPointer == Second.PinValueType.bTerminalIsWeakPointer
|
|
&& First.PinValueType.bTerminalIsUObjectWrapper == Second.PinValueType.bTerminalIsUObjectWrapper;
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::ApplyMapType(UEdGraphPin& Pin, const FEdGraphPinType& MapType)
|
|
{
|
|
Pin.PinType.PinCategory = MapType.PinCategory;
|
|
Pin.PinType.PinSubCategory = MapType.PinSubCategory;
|
|
Pin.PinType.PinSubCategoryObject = MapType.PinSubCategoryObject;
|
|
Pin.PinType.PinSubCategoryMemberReference = MapType.PinSubCategoryMemberReference;
|
|
Pin.PinType.PinValueType = MapType.PinValueType;
|
|
Pin.PinType.bIsWeakPointer = MapType.bIsWeakPointer;
|
|
Pin.PinType.bIsUObjectWrapper = MapType.bIsUObjectWrapper;
|
|
Pin.PinType.bSerializeAsSinglePrecisionFloat = MapType.bSerializeAsSinglePrecisionFloat;
|
|
}
|
|
|
|
void UK2Node_DirectiveUtilMapAppend::ResetMapType(UEdGraphPin& Pin)
|
|
{
|
|
Pin.PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
|
|
Pin.PinType.PinSubCategory = NAME_None;
|
|
Pin.PinType.PinSubCategoryObject = nullptr;
|
|
Pin.PinType.PinSubCategoryMemberReference = FSimpleMemberReference();
|
|
Pin.PinType.PinValueType = FEdGraphTerminalType();
|
|
Pin.PinType.PinValueType.TerminalCategory = UEdGraphSchema_K2::PC_Wildcard;
|
|
Pin.PinType.bIsWeakPointer = false;
|
|
Pin.PinType.bIsUObjectWrapper = false;
|
|
Pin.PinType.bSerializeAsSinglePrecisionFloat = false;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|