2014-04-23 20:18:55 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "BlueprintGraphPrivatePCH.h"
2014-05-29 17:11:10 -04:00
# include "Engine/LevelScriptBlueprint.h"
2014-09-17 05:39:56 -04:00
# include "Kismet/KismetSystemLibrary.h"
# include "Kismet/KismetArrayLibrary.h"
2014-03-14 14:13:41 -04:00
# include "GraphEditorActions.h"
2014-05-20 19:00:53 -04:00
# include "GraphEditorSettings.h"
2014-03-14 14:13:41 -04:00
# include "ScopedTransaction.h"
# include "ComponentAssetBroker.h"
# include "Kismet2/KismetEditorUtilities.h"
# include "Kismet2/KismetDebugUtilities.h"
2014-06-16 14:46:44 -04:00
# include "KismetCompiler.h"
2014-03-14 14:13:41 -04:00
# include "ComponentAssetBroker.h"
# include "AssetData.h"
# include "Editor/UnrealEd/Public/EdGraphUtilities.h"
# include "DefaultValueHelper.h"
# include "ObjectEditorUtils.h"
# include "ActorEditorUtils.h"
# include "K2ActionMenuBuilder.h"
2014-04-23 20:18:55 -04:00
# include "AssetRegistryModule.h"
2014-05-29 17:06:50 -04:00
# include "Blueprint/AIBlueprintHelperLibrary.h"
2014-03-14 14:13:41 -04:00
2014-05-29 16:42:22 -04:00
# include "K2Node_CastByteToEnum.h"
# include "K2Node_ClassDynamicCast.h"
# include "K2Node_GetEnumeratorName.h"
# include "K2Node_GetEnumeratorNameAsString.h"
# include "K2Node_Tunnel.h"
2014-06-30 16:03:48 -04:00
# include "K2Node_SetFieldsInStruct.h"
2014-05-29 16:42:22 -04:00
2014-09-21 20:35:48 -04:00
2014-03-14 14:13:41 -04:00
//////////////////////////////////////////////////////////////////////////
// FBlueprintMetadata
const FName FBlueprintMetadata : : MD_AllowableBlueprintVariableType ( TEXT ( " BlueprintType " ) ) ;
const FName FBlueprintMetadata : : MD_NotAllowableBlueprintVariableType ( TEXT ( " NotBlueprintType " ) ) ;
const FName FBlueprintMetadata : : MD_BlueprintSpawnableComponent ( TEXT ( " BlueprintSpawnableComponent " ) ) ;
const FName FBlueprintMetadata : : MD_IsBlueprintBase ( TEXT ( " IsBlueprintBase " ) ) ;
2014-07-07 18:15:11 -04:00
const FName FBlueprintMetadata : : MD_RestrictedToClasses ( TEXT ( " RestrictedToClasses " ) ) ;
2014-03-14 14:13:41 -04:00
const FName FBlueprintMetadata : : MD_Protected ( TEXT ( " BlueprintProtected " ) ) ;
const FName FBlueprintMetadata : : MD_Latent ( TEXT ( " Latent " ) ) ;
const FName FBlueprintMetadata : : MD_UnsafeForConstructionScripts ( TEXT ( " UnsafeDuringActorConstruction " ) ) ;
const FName FBlueprintMetadata : : MD_FunctionCategory ( TEXT ( " Category " ) ) ;
const FName FBlueprintMetadata : : MD_DeprecatedFunction ( TEXT ( " DeprecatedFunction " ) ) ;
const FName FBlueprintMetadata : : MD_DeprecationMessage ( TEXT ( " DeprecationMessage " ) ) ;
const FName FBlueprintMetadata : : MD_CompactNodeTitle ( TEXT ( " CompactNodeTitle " ) ) ;
2014-05-09 18:59:04 -04:00
const FName FBlueprintMetadata : : MD_FriendlyName ( TEXT ( " FriendlyName " ) ) ;
2014-03-14 14:13:41 -04:00
const FName FBlueprintMetadata : : MD_ExposeOnSpawn ( TEXT ( " ExposeOnSpawn " ) ) ;
const FName FBlueprintMetadata : : MD_DefaultToSelf ( TEXT ( " DefaultToSelf " ) ) ;
const FName FBlueprintMetadata : : MD_WorldContext ( TEXT ( " WorldContext " ) ) ;
2014-09-10 16:39:25 -04:00
const FName FBlueprintMetadata : : MD_CallableWithoutWorldContext ( TEXT ( " CallableWithoutWorldContext " ) ) ;
2014-03-14 14:13:41 -04:00
const FName FBlueprintMetadata : : MD_AutoCreateRefTerm ( TEXT ( " AutoCreateRefTerm " ) ) ;
2014-09-10 15:23:52 -04:00
const FName FBlueprintMetadata : : MD_ShowWorldContextPin ( TEXT ( " ShowWorldContextPin " ) ) ;
2014-03-14 14:13:41 -04:00
const FName FBlueprintMetadata : : MD_Private ( TEXT ( " BlueprintPrivate " ) ) ;
const FName FBlueprintMetadata : : MD_BlueprintInternalUseOnly ( TEXT ( " BlueprintInternalUseOnly " ) ) ;
const FName FBlueprintMetadata : : MD_NeedsLatentFixup ( TEXT ( " NeedsLatentFixup " ) ) ;
const FName FBlueprintMetadata : : MD_LatentCallbackTarget ( TEXT ( " LatentCallbackTarget " ) ) ;
const FName FBlueprintMetadata : : MD_AllowPrivateAccess ( TEXT ( " AllowPrivateAccess " ) ) ;
const FName FBlueprintMetadata : : MD_ExposeFunctionCategories ( TEXT ( " ExposeFunctionCategories " ) ) ;
const FName FBlueprintMetadata : : MD_CannotImplementInterfaceInBlueprint ( TEXT ( " CannotImplementInterfaceInBlueprint " ) ) ;
const FName FBlueprintMetadata : : MD_ProhibitedInterfaces ( TEXT ( " ProhibitedInterfaces " ) ) ;
const FName FBlueprintMetadata : : MD_FunctionKeywords ( TEXT ( " Keywords " ) ) ;
const FName FBlueprintMetadata : : MD_ExpandEnumAsExecs ( TEXT ( " ExpandEnumAsExecs " ) ) ;
const FName FBlueprintMetadata : : MD_CommutativeAssociativeBinaryOperator ( TEXT ( " CommutativeAssociativeBinaryOperator " ) ) ;
const FName FBlueprintMetadata : : MD_MaterialParameterCollectionFunction ( TEXT ( " MaterialParameterCollectionFunction " ) ) ;
const FName FBlueprintMetadata : : MD_Tooltip ( TEXT ( " Tooltip " ) ) ;
2014-07-24 13:30:26 -04:00
const FName FBlueprintMetadata : : MD_CallInEditor ( TEXT ( " CallInEditor " ) ) ;
2014-08-21 23:21:25 -04:00
const FName FBlueprintMetadata : : MD_DataTablePin ( TEXT ( " DataTablePin " ) ) ;
2014-10-01 12:14:30 -04:00
const FName FBlueprintMetadata : : MD_NativeMakeFunction ( TEXT ( " HasNativeMake " ) ) ;
const FName FBlueprintMetadata : : MD_NativeBreakFunction ( TEXT ( " HasNativeBreak " ) ) ;
2014-10-09 12:04:45 -04:00
const FName FBlueprintMetadata : : MD_DynamicOutputType ( TEXT ( " DeterminesOutputType " ) ) ;
const FName FBlueprintMetadata : : MD_DynamicOutputParam ( TEXT ( " DynamicOutputParam " ) ) ;
2014-03-14 14:13:41 -04:00
//////////////////////////////////////////////////////////////////////////
# define LOCTEXT_NAMESPACE "KismetSchema"
2014-09-08 12:56:34 -04:00
UEdGraphSchema_K2 : : FPinTypeTreeInfo : : FPinTypeTreeInfo ( const FText & InFriendlyCategoryName , const FString & CategoryName , const UEdGraphSchema_K2 * Schema , const FText & InTooltip , bool bInReadOnly /*=false*/ )
2014-03-14 14:13:41 -04:00
{
Init ( InFriendlyCategoryName , CategoryName , Schema , InTooltip , bInReadOnly ) ;
}
2014-04-23 20:18:55 -04:00
struct FGatherStructTypesFromAssetsHelper
{
2014-04-26 11:11:00 -04:00
typedef TSharedPtr < UEdGraphSchema_K2 : : FPinTypeTreeInfo > FPinTypeTreeInfoPtr ;
2014-04-23 20:18:55 -04:00
struct FCompareChildren
{
2014-04-26 11:11:00 -04:00
FORCEINLINE bool operator ( ) ( const FPinTypeTreeInfoPtr A , const FPinTypeTreeInfoPtr B ) const
2014-04-23 20:18:55 -04:00
{
2014-09-08 12:56:34 -04:00
return ( A - > GetDescription ( ) . ToString ( ) < B - > GetDescription ( ) . ToString ( ) ) ;
2014-04-23 20:18:55 -04:00
}
} ;
2014-04-26 11:11:00 -04:00
static void Gather ( const FString & CategoryName , const UEdGraphSchema_K2 * Schema , TArray < FPinTypeTreeInfoPtr > & OutChildren )
2014-04-23 20:18:55 -04:00
{
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
TArray < FAssetData > AssetData ;
AssetRegistryModule . Get ( ) . GetAssetsByClass ( UUserDefinedStruct : : StaticClass ( ) - > GetFName ( ) , AssetData ) ;
for ( int32 AssetIndex = 0 ; AssetIndex < AssetData . Num ( ) ; + + AssetIndex )
{
const FAssetData & Asset = AssetData [ AssetIndex ] ;
if ( Asset . IsValid ( ) & & ! Asset . IsAssetLoaded ( ) )
{
2014-04-26 11:11:00 -04:00
const FString * pDescription = Asset . TagsAndValues . Find ( TEXT ( " Tooltip " ) ) ;
const FString Tooltip = ( pDescription & & ! pDescription - > IsEmpty ( ) ) ? * pDescription : Asset . ObjectPath . ToString ( ) ;
2014-09-08 12:56:34 -04:00
FPinTypeTreeInfoPtr TypeTreeInfo = MakeShareable ( new UEdGraphSchema_K2 : : FPinTypeTreeInfo ( CategoryName , Asset . ToStringReference ( ) , FText : : FromString ( Tooltip ) ) ) ;
TypeTreeInfo - > FriendlyName = FText : : FromName ( Asset . AssetName ) ;
2014-04-23 20:18:55 -04:00
OutChildren . Add ( TypeTreeInfo ) ;
}
}
OutChildren . Sort ( FCompareChildren ( ) ) ;
}
static UObject * LoadAsset ( const FStringAssetReference & AssetReference )
{
if ( AssetReference . IsValid ( ) )
{
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
2014-07-22 08:14:39 -04:00
const FAssetData AssetData = AssetRegistryModule . Get ( ) . GetAssetByObjectPath ( * AssetReference . ToString ( ) ) ;
2014-04-23 20:18:55 -04:00
return AssetData . GetAsset ( ) ;
}
return NULL ;
}
} ;
const FEdGraphPinType & UEdGraphSchema_K2 : : FPinTypeTreeInfo : : GetPinType ( bool bForceLoadedSubCategoryObject )
{
if ( bForceLoadedSubCategoryObject & & ! PinType . PinSubCategoryObject . IsValid ( ) & & SubCategoryObjectAssetReference . IsValid ( ) )
{
PinType . PinSubCategoryObject = FGatherStructTypesFromAssetsHelper : : LoadAsset ( SubCategoryObjectAssetReference ) ;
}
return PinType ;
}
2014-09-08 12:56:34 -04:00
void UEdGraphSchema_K2 : : FPinTypeTreeInfo : : Init ( const FText & InFriendlyName , const FString & CategoryName , const UEdGraphSchema_K2 * Schema , const FText & InTooltip , bool bInReadOnly )
2014-03-14 14:13:41 -04:00
{
check ( ! CategoryName . IsEmpty ( ) ) ;
check ( Schema ) ;
2014-04-23 20:18:55 -04:00
FriendlyName = InFriendlyName ;
2014-03-14 14:13:41 -04:00
Tooltip = InTooltip ;
2014-09-08 12:56:34 -04:00
PinType . PinCategory = ( CategoryName = = TEXT ( " Enum " ) ? PC_Byte : CategoryName ) ;
2014-03-14 14:13:41 -04:00
PinType . PinSubCategory = TEXT ( " " ) ;
PinType . PinSubCategoryObject = NULL ;
bReadOnly = bInReadOnly ;
2014-09-08 12:56:34 -04:00
if ( Schema - > DoesTypeHaveSubtypes ( CategoryName ) )
2014-03-14 14:13:41 -04:00
{
TArray < UObject * > Subtypes ;
2014-09-08 12:56:34 -04:00
Schema - > GetVariableSubtypes ( CategoryName , Subtypes ) ;
2014-03-14 14:13:41 -04:00
for ( auto it = Subtypes . CreateIterator ( ) ; it ; + + it )
{
2014-09-08 12:56:34 -04:00
FText SubtypeTooltip ;
2014-03-14 14:13:41 -04:00
UStruct * Struct = Cast < UStruct > ( * it ) ;
if ( Struct ! = NULL )
{
2014-09-08 12:56:34 -04:00
SubtypeTooltip = ( Struct ? Struct - > GetToolTipText ( ) : InFriendlyName ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-08 12:56:34 -04:00
Children . Add ( MakeShareable ( new FPinTypeTreeInfo ( PinType . PinCategory , * it , SubtypeTooltip ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 20:18:55 -04:00
2014-09-08 12:56:34 -04:00
if ( Schema - > PC_Struct = = CategoryName )
2014-04-23 20:18:55 -04:00
{
FGatherStructTypesFromAssetsHelper : : Gather ( CategoryName , Schema , Children ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-09-08 12:56:34 -04:00
UEdGraphSchema_K2 : : FPinTypeTreeInfo : : FPinTypeTreeInfo ( const FString & CategoryName , UObject * SubCategoryObject , const FText & InTooltip , bool bInReadOnly /*=false*/ )
2014-03-14 14:13:41 -04:00
{
check ( ! CategoryName . IsEmpty ( ) ) ;
check ( SubCategoryObject ) ;
Tooltip = InTooltip ;
PinType . PinCategory = CategoryName ;
PinType . PinSubCategoryObject = SubCategoryObject ;
bReadOnly = bInReadOnly ;
}
2014-09-08 12:56:34 -04:00
UEdGraphSchema_K2 : : FPinTypeTreeInfo : : FPinTypeTreeInfo ( const FString & CategoryName , const FStringAssetReference & SubCategoryObject , const FText & InTooltip , bool bInReadOnly )
2014-04-23 20:18:55 -04:00
{
check ( ! CategoryName . IsEmpty ( ) ) ;
check ( SubCategoryObject . IsValid ( ) ) ;
Tooltip = InTooltip ;
PinType . PinCategory = CategoryName ;
SubCategoryObjectAssetReference = SubCategoryObject ;
2014-04-24 15:59:15 -04:00
PinType . PinSubCategoryObject = SubCategoryObjectAssetReference . ResolveObject ( ) ;
2014-04-23 20:18:55 -04:00
bReadOnly = bInReadOnly ;
}
2014-09-08 12:56:34 -04:00
FText UEdGraphSchema_K2 : : FPinTypeTreeInfo : : GetDescription ( ) const
2014-08-01 11:07:59 -04:00
{
2014-09-08 12:56:34 -04:00
if ( ! FriendlyName . IsEmpty ( ) )
2014-08-01 11:07:59 -04:00
{
return FriendlyName ;
}
else if ( PinType . PinSubCategoryObject . IsValid ( ) )
{
FString DisplayName = PinType . PinSubCategoryObject - > GetName ( ) ;
const auto SubCategoryClass = Cast < UClass > ( PinType . PinSubCategoryObject . Get ( ) ) ;
if ( SubCategoryClass & & ! SubCategoryClass - > HasAnyClassFlags ( CLASS_Native ) )
{
DisplayName . RemoveFromEnd ( TEXT ( " _C " ) ) ;
}
2014-09-08 12:56:34 -04:00
return FText : : FromString ( DisplayName ) ;
2014-08-01 11:07:59 -04:00
}
else
{
2014-09-08 12:56:34 -04:00
return LOCTEXT ( " PinDescriptionError " , " Error! " ) ;
2014-08-01 11:07:59 -04:00
}
}
2014-09-04 13:55:54 -04:00
const FString UEdGraphSchema_K2 : : PC_Exec ( TEXT ( " exec " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Boolean ( TEXT ( " bool " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Byte ( TEXT ( " byte " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Class ( TEXT ( " class " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Int ( TEXT ( " int " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Float ( TEXT ( " float " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Name ( TEXT ( " name " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Delegate ( TEXT ( " delegate " ) ) ;
const FString UEdGraphSchema_K2 : : PC_MCDelegate ( TEXT ( " mcdelegate " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Object ( TEXT ( " object " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Interface ( TEXT ( " interface " ) ) ;
const FString UEdGraphSchema_K2 : : PC_String ( TEXT ( " string " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Text ( TEXT ( " text " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Struct ( TEXT ( " struct " ) ) ;
const FString UEdGraphSchema_K2 : : PC_Wildcard ( TEXT ( " wildcard " ) ) ;
const FString UEdGraphSchema_K2 : : PSC_Self ( TEXT ( " self " ) ) ;
const FString UEdGraphSchema_K2 : : PSC_Index ( TEXT ( " index " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Execute ( TEXT ( " execute " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Then ( TEXT ( " then " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Completed ( TEXT ( " Completed " ) ) ;
const FString UEdGraphSchema_K2 : : PN_DelegateEntry ( TEXT ( " delegate " ) ) ;
const FString UEdGraphSchema_K2 : : PN_EntryPoint ( TEXT ( " EntryPoint " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Self ( TEXT ( " self " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Else ( TEXT ( " else " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Loop ( TEXT ( " loop " ) ) ;
const FString UEdGraphSchema_K2 : : PN_After ( TEXT ( " after " ) ) ;
const FString UEdGraphSchema_K2 : : PN_ReturnValue ( TEXT ( " ReturnValue " ) ) ;
const FString UEdGraphSchema_K2 : : PN_ObjectToCast ( TEXT ( " Object " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Condition ( TEXT ( " Condition " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Start ( TEXT ( " Start " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Stop ( TEXT ( " Stop " ) ) ;
const FString UEdGraphSchema_K2 : : PN_Index ( TEXT ( " Index " ) ) ;
2014-09-15 10:40:56 -04:00
const FString UEdGraphSchema_K2 : : PN_Item ( TEXT ( " Item " ) ) ;
2014-09-04 13:55:54 -04:00
const FString UEdGraphSchema_K2 : : PN_CastSucceeded ( TEXT ( " then " ) ) ;
const FString UEdGraphSchema_K2 : : PN_CastFailed ( TEXT ( " CastFailed " ) ) ;
const FString UEdGraphSchema_K2 : : PN_CastedValuePrefix ( TEXT ( " As " ) ) ;
const FString UEdGraphSchema_K2 : : PN_MatineeFinished ( TEXT ( " Finished " ) ) ;
const FName UEdGraphSchema_K2 : : FN_UserConstructionScript ( TEXT ( " UserConstructionScript " ) ) ;
const FName UEdGraphSchema_K2 : : FN_ExecuteUbergraphBase ( TEXT ( " ExecuteUbergraph " ) ) ;
const FName UEdGraphSchema_K2 : : GN_EventGraph ( TEXT ( " EventGraph " ) ) ;
const FName UEdGraphSchema_K2 : : GN_AnimGraph ( TEXT ( " AnimGraph " ) ) ;
const FName UEdGraphSchema_K2 : : VR_DefaultCategory ( TEXT ( " Default " ) ) ;
const int32 UEdGraphSchema_K2 : : AG_LevelReference = 100 ;
2014-09-04 17:31:51 -04:00
const UScriptStruct * UEdGraphSchema_K2 : : VectorStruct = nullptr ;
const UScriptStruct * UEdGraphSchema_K2 : : RotatorStruct = nullptr ;
const UScriptStruct * UEdGraphSchema_K2 : : TransformStruct = nullptr ;
const UScriptStruct * UEdGraphSchema_K2 : : LinearColorStruct = nullptr ;
const UScriptStruct * UEdGraphSchema_K2 : : ColorStruct = nullptr ;
2014-09-05 17:51:04 -04:00
bool UEdGraphSchema_K2 : : bGeneratingDocumentation = false ;
2014-03-14 14:13:41 -04:00
UEdGraphSchema_K2 : : UEdGraphSchema_K2 ( const class FPostConstructInitializeProperties & PCIP )
: Super ( PCIP )
{
2014-09-04 17:31:51 -04:00
// Initialize cached static references to well-known struct types
if ( VectorStruct = = nullptr )
{
VectorStruct = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Vector " ) ) ;
RotatorStruct = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Rotator " ) ) ;
TransformStruct = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Transform " ) ) ;
LinearColorStruct = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " LinearColor " ) ) ;
ColorStruct = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Color " ) ) ;
}
2014-03-14 14:13:41 -04:00
}
bool UEdGraphSchema_K2 : : DoesFunctionHaveOutParameters ( const UFunction * Function ) const
{
if ( Function ! = NULL )
{
for ( TFieldIterator < UProperty > PropertyIt ( Function ) ; PropertyIt ; + + PropertyIt )
{
if ( PropertyIt - > PropertyFlags & CPF_OutParm )
{
return true ;
}
}
}
return false ;
}
2014-10-07 00:54:59 -04:00
bool UEdGraphSchema_K2 : : CanFunctionBeUsedInClass ( const UClass * InClass , UFunction * InFunction , const UEdGraph * InDestGraph , uint32 InAllowedFunctionTypes , bool bInShowInherited , bool bInCalledForEach , const FFunctionTargetInfo & InTargetInfo , FText * OutReason ) const
2014-03-14 14:13:41 -04:00
{
if ( CanUserKismetCallFunction ( InFunction ) )
{
2014-09-10 15:59:01 -04:00
bool bLatentFuncsAllowed = true ;
bool bIsConstructionScript = false ;
2014-10-07 00:54:59 -04:00
if ( InDestGraph ! = nullptr )
2014-09-10 15:59:01 -04:00
{
bLatentFuncsAllowed = ( GetGraphType ( InDestGraph ) = = GT_Ubergraph | | ( GetGraphType ( InDestGraph ) = = GT_Macro ) ) ;
bIsConstructionScript = IsConstructionScript ( InDestGraph ) ;
}
2014-03-14 14:13:41 -04:00
const bool bIsPureFunc = ( InFunction - > HasAnyFunctionFlags ( FUNC_BlueprintPure ) ! = false ) ;
2014-09-10 15:59:01 -04:00
if ( bIsPureFunc )
{
const bool bAllowPureFuncs = ( InAllowedFunctionTypes & FT_Pure ) ! = 0 ;
if ( ! bAllowPureFuncs )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " PureFunctionsNotAllowed " , " Pure functions are not allowed. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
}
else
{
const bool bAllowImperativeFuncs = ( InAllowedFunctionTypes & FT_Imperative ) ! = 0 ;
if ( ! bAllowImperativeFuncs )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " ImpureFunctionsNotAllowed " , " Impure functions are not allowed. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
}
2014-03-14 14:13:41 -04:00
const bool bIsConstFunc = ( InFunction - > HasAnyFunctionFlags ( FUNC_Const ) ! = false ) ;
2014-09-10 15:59:01 -04:00
const bool bAllowConstFuncs = ( InAllowedFunctionTypes & FT_Const ) ! = 0 ;
if ( bIsConstFunc & & ! bAllowConstFuncs )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " ConstFunctionsNotAllowed " , " Const functions are not allowed. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
2014-03-14 14:13:41 -04:00
const bool bIsLatent = InFunction - > HasMetaData ( FBlueprintMetadata : : MD_Latent ) ;
2014-09-10 15:59:01 -04:00
if ( bIsLatent & & ! bLatentFuncsAllowed )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " LatentFunctionsNotAllowed " , " Latent functions cannot be used here. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
const bool bIsProtected = InFunction - > GetBoolMetaData ( FBlueprintMetadata : : MD_Protected ) ;
const bool bFuncBelongsToSubClass = InClass - > IsChildOf ( InFunction - > GetOuterUClass ( ) ) ;
if ( bIsProtected )
{
const bool bAllowProtectedFuncs = ( InAllowedFunctionTypes & FT_Protected ) ! = 0 ;
if ( ! bAllowProtectedFuncs )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " ProtectedFunctionsNotAllowed " , " Protected functions are not allowed. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
if ( ! bFuncBelongsToSubClass )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " ProtectedFunctionInaccessible " , " Function is protected and inaccessible. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
}
2014-07-23 12:05:32 -04:00
const bool bIsPrivate = InFunction - > GetBoolMetaData ( FBlueprintMetadata : : MD_Private ) ;
2014-09-10 15:59:01 -04:00
const bool bFuncBelongsToClass = bFuncBelongsToSubClass & & ( InFunction - > GetOuterUClass ( ) = = InClass ) ;
if ( bIsPrivate & & ! bFuncBelongsToClass )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " PrivateFunctionInaccessible " , " Function is private and inaccessible. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
const bool bIsUnsafeForConstruction = InFunction - > GetBoolMetaData ( FBlueprintMetadata : : MD_UnsafeForConstructionScripts ) ;
if ( bIsUnsafeForConstruction & & bIsConstructionScript )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " FunctionUnsafeForConstructionScript " , " Function cannot be used in a Construction Script. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
2014-09-10 16:39:25 -04:00
const bool bRequiresWorldContext = InFunction - > HasMetaData ( FBlueprintMetadata : : MD_WorldContext ) ;
if ( bRequiresWorldContext )
{
if ( InDestGraph & & ! InFunction - > HasMetaData ( FBlueprintMetadata : : MD_CallableWithoutWorldContext ) )
{
UClass * ParentClass = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( InDestGraph ) - > ParentClass ;
if ( ! ParentClass - > GetDefaultObject ( ) - > ImplementsGetWorld ( ) & & ! ParentClass - > HasMetaData ( FBlueprintMetadata : : MD_ShowWorldContextPin ) )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " FunctionRequiresWorldContext " , " Function requires a world context. " ) ;
}
2014-09-10 16:39:25 -04:00
return false ;
}
}
}
2014-09-10 15:59:01 -04:00
const bool bFunctionHidden = FObjectEditorUtils : : IsFunctionHiddenFromClass ( InFunction , InClass ) ;
if ( bFunctionHidden )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " HiddenFunctionInaccessible " , " Function is hidden and inaccessible. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
}
2014-03-14 14:13:41 -04:00
const bool bFunctionStatic = InFunction - > HasAllFunctionFlags ( FUNC_Static ) ;
const bool bHasReturnParams = ( InFunction - > GetReturnProperty ( ) ! = NULL ) ;
const bool bHasArrayPointerParms = InFunction - > HasMetaData ( TEXT ( " ArrayParm " ) ) ;
2014-09-10 15:59:01 -04:00
2014-03-14 14:13:41 -04:00
const bool bAllowForEachCall = ! bFunctionStatic & & ! bIsLatent & & ! bIsPureFunc & & ! bIsConstFunc & & ! bHasReturnParams & & ! bHasArrayPointerParms ;
2014-09-10 15:59:01 -04:00
if ( bInCalledForEach & & ! bAllowForEachCall )
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
if ( bFunctionStatic )
{
* OutReason = LOCTEXT ( " StaticFunctionsNotAllowedInForEachContext " , " Static functions cannot be used within a ForEach context. " ) ;
}
else if ( bIsLatent )
{
* OutReason = LOCTEXT ( " LatentFunctionsNotAllowedInForEachContext " , " Latent functions cannot be used within a ForEach context. " ) ;
}
else if ( bIsPureFunc )
{
* OutReason = LOCTEXT ( " PureFunctionsNotAllowedInForEachContext " , " Pure functions cannot be used within a ForEach context. " ) ;
}
else if ( bIsConstFunc )
{
* OutReason = LOCTEXT ( " ConstFunctionsNotAllowedInForEachContext " , " Const functions cannot be used within a ForEach context. " ) ;
}
else if ( bHasReturnParams )
{
* OutReason = LOCTEXT ( " FunctionsWithReturnValueNotAllowedInForEachContext " , " Functions that return a value cannot be used within a ForEach context. " ) ;
}
else if ( bHasArrayPointerParms )
{
* OutReason = LOCTEXT ( " FunctionsWithArrayParmsNotAllowedInForEachContext " , " Functions with array parameters cannot be used within a ForEach context. " ) ;
}
else
{
* OutReason = LOCTEXT ( " FunctionNotAllowedInForEachContext " , " Function cannot be used within a ForEach context. " ) ;
}
}
2014-09-10 15:59:01 -04:00
return false ;
}
2014-03-14 14:13:41 -04:00
const bool bClassIsAnActor = InClass - > IsChildOf ( AActor : : StaticClass ( ) ) ;
// This will evaluate to false if there are multiple actors selected and the function has a return value or out parameters
2014-09-10 15:59:01 -04:00
const bool bFunctionHasReturnOrOutParameters = bHasReturnParams | | DoesFunctionHaveOutParameters ( InFunction ) ;
2014-03-14 14:13:41 -04:00
const bool bAllowReturnValuesForNoneOrSingleActors = ! bClassIsAnActor | | InTargetInfo . Actors . Num ( ) < = 1 | | ! bFunctionHasReturnOrOutParameters ;
2014-09-10 15:59:01 -04:00
if ( ! bAllowReturnValuesForNoneOrSingleActors )
2014-03-14 14:13:41 -04:00
{
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " FunctionNotAllowedWithMultipleTargets " , " Functions that return a value cannot be used with multiple targets. " ) ;
}
2014-09-10 15:59:01 -04:00
return false ;
2014-03-14 14:13:41 -04:00
}
2014-09-10 15:59:01 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
2014-10-07 00:54:59 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " FunctionInvalid " , " Invalid function. " ) ;
}
2014-03-14 14:13:41 -04:00
return false ;
}
UFunction * UEdGraphSchema_K2 : : GetCallableParentFunction ( UFunction * Function ) const
{
if ( Function )
{
const FName FunctionName = Function - > GetFName ( ) ;
// Search up the parent scopes
UClass * ParentClass = CastChecked < UClass > ( Function - > GetOuter ( ) ) - > GetSuperClass ( ) ;
UFunction * ClassFunction = ParentClass - > FindFunctionByName ( FunctionName ) ;
return ClassFunction ;
}
return NULL ;
}
bool UEdGraphSchema_K2 : : CanUserKismetCallFunction ( const UFunction * Function )
{
2014-05-05 09:44:44 -04:00
return Function & &
( Function - > HasAllFunctionFlags ( FUNC_BlueprintCallable ) & & ! Function - > HasAllFunctionFlags ( FUNC_Delegate ) & & ! Function - > GetBoolMetaData ( FBlueprintMetadata : : MD_BlueprintInternalUseOnly ) & & ! Function - > HasMetaData ( FBlueprintMetadata : : MD_DeprecatedFunction ) ) ;
2014-03-14 14:13:41 -04:00
}
bool UEdGraphSchema_K2 : : CanKismetOverrideFunction ( const UFunction * Function )
{
2014-05-05 09:44:44 -04:00
return Function & &
( Function - > HasAllFunctionFlags ( FUNC_BlueprintEvent ) & & ! Function - > HasAllFunctionFlags ( FUNC_Delegate ) & & ! Function - > GetBoolMetaData ( FBlueprintMetadata : : MD_BlueprintInternalUseOnly ) & & ! Function - > HasMetaData ( FBlueprintMetadata : : MD_DeprecatedFunction ) ) ;
2014-03-14 14:13:41 -04:00
}
struct FNoOutputParametersHelper
{
static bool Check ( const UFunction * InFunction )
{
check ( InFunction ) ;
for ( TFieldIterator < UProperty > PropIt ( InFunction ) ; PropIt & & ( PropIt - > PropertyFlags & CPF_Parm ) ; + + PropIt )
{
UProperty * FuncParam = * PropIt ;
if ( FuncParam - > HasAnyPropertyFlags ( CPF_ReturnParm ) | | ( FuncParam - > HasAnyPropertyFlags ( CPF_OutParm ) & & ! FuncParam - > HasAnyPropertyFlags ( CPF_ReferenceParm ) & & ! FuncParam - > HasAnyPropertyFlags ( CPF_ConstParm ) ) )
{
return false ;
}
}
return true ;
}
} ;
bool UEdGraphSchema_K2 : : FunctionCanBePlacedAsEvent ( const UFunction * InFunction )
{
// First check we are override-able
2014-05-05 09:44:44 -04:00
if ( ! InFunction | | ! CanKismetOverrideFunction ( InFunction ) )
2014-03-14 14:13:41 -04:00
{
return false ;
}
// Then look to see if we have any output, return, or reference params
return FNoOutputParametersHelper : : Check ( InFunction ) ;
}
bool UEdGraphSchema_K2 : : FunctionCanBeUsedInDelegate ( const UFunction * InFunction )
{
if ( ! InFunction | |
! CanUserKismetCallFunction ( InFunction ) | |
InFunction - > HasMetaData ( FBlueprintMetadata : : MD_Latent ) | |
InFunction - > HasAllFunctionFlags ( FUNC_BlueprintPure ) )
{
return false ;
}
return FNoOutputParametersHelper : : Check ( InFunction ) ;
}
2014-09-21 20:33:57 -04:00
FString UEdGraphSchema_K2 : : GetFriendlySignatureName ( const UFunction * Function )
2014-03-14 14:13:41 -04:00
{
return UK2Node_CallFunction : : GetUserFacingFunctionName ( Function ) ;
}
void UEdGraphSchema_K2 : : GetAutoEmitTermParameters ( const UFunction * Function , TArray < FString > & AutoEmitParameterNames ) const
{
AutoEmitParameterNames . Empty ( ) ;
if ( Function - > HasMetaData ( FBlueprintMetadata : : MD_AutoCreateRefTerm ) )
{
FString MetaData = Function - > GetMetaData ( FBlueprintMetadata : : MD_AutoCreateRefTerm ) ;
MetaData . ParseIntoArray ( & AutoEmitParameterNames , TEXT ( " , " ) , true ) ;
}
}
bool UEdGraphSchema_K2 : : FunctionHasParamOfType ( const UFunction * InFunction , UBlueprint const * CallingContext , const FEdGraphPinType & DesiredPinType , bool bWantOutput ) const
{
TSet < FString > HiddenPins ;
FBlueprintEditorUtils : : GetHiddenPinsForFunction ( CallingContext , InFunction , HiddenPins ) ;
// Iterate over all params of function
for ( TFieldIterator < UProperty > PropIt ( InFunction ) ; PropIt & & ( PropIt - > PropertyFlags & CPF_Parm ) ; + + PropIt )
{
UProperty * FuncParam = * PropIt ;
// Ensure that this isn't a hidden parameter
if ( ! HiddenPins . Contains ( FuncParam - > GetName ( ) ) )
{
// See if this is the direction we want (input or output)
const bool bIsFunctionInput = ! FuncParam - > HasAnyPropertyFlags ( CPF_OutParm ) | | FuncParam - > HasAnyPropertyFlags ( CPF_ReferenceParm ) ;
if ( ( ! bIsFunctionInput & & bWantOutput ) | | ( bIsFunctionInput & & ! bWantOutput ) )
{
// See if this pin has compatible types
FEdGraphPinType ParamPinType ;
bool bConverted = ConvertPropertyToPinType ( FuncParam , ParamPinType ) ;
if ( bConverted )
{
if ( bIsFunctionInput & & ArePinTypesCompatible ( DesiredPinType , ParamPinType ) )
{
return true ;
}
else if ( ! bIsFunctionInput & & ArePinTypesCompatible ( ParamPinType , DesiredPinType ) )
{
return true ;
}
}
}
}
}
// Boo, no pin of this type
return false ;
}
void UEdGraphSchema_K2 : : AddExtraFunctionFlags ( const UEdGraph * CurrentGraph , int32 ExtraFlags ) const
{
for ( auto It = CurrentGraph - > Nodes . CreateConstIterator ( ) ; It ; + + It )
{
if ( UK2Node_FunctionEntry * Node = Cast < UK2Node_FunctionEntry > ( * It ) )
{
Node - > ExtraFlags | = ExtraFlags ;
}
}
}
void UEdGraphSchema_K2 : : MarkFunctionEntryAsEditable ( const UEdGraph * CurrentGraph , bool bNewEditable ) const
{
for ( auto It = CurrentGraph - > Nodes . CreateConstIterator ( ) ; It ; + + It )
{
if ( UK2Node_EditablePinBase * Node = Cast < UK2Node_EditablePinBase > ( * It ) )
{
Node - > bIsEditable = bNewEditable ;
}
}
}
void UEdGraphSchema_K2 : : ListFunctionsMatchingSignatureAsDelegates ( FGraphContextMenuBuilder & ContextMenuBuilder , const UClass * Class , const UFunction * SignatureToMatch ) const
{
check ( Class ) ;
for ( TFieldIterator < UFunction > FunctionIt ( Class , EFieldIteratorFlags : : IncludeSuper ) ; FunctionIt ; + + FunctionIt )
{
const UFunction * TrialFunction = * FunctionIt ;
if ( CanUserKismetCallFunction ( TrialFunction ) & & TrialFunction - > IsSignatureCompatibleWith ( SignatureToMatch ) )
{
FString Description ( TrialFunction - > GetName ( ) ) ;
FString Tooltip = FString : : Printf ( TEXT ( " Existing function '%s' as delegate " ) , * ( TrialFunction - > GetName ( ) ) ) ; //@TODO: Need a better tooltip
// @TODO
}
}
}
bool UEdGraphSchema_K2 : : IsActorValidForLevelScriptRefs ( const AActor * TestActor , const ULevelScriptBlueprint * Blueprint ) const
{
check ( Blueprint ) ;
return TestActor
& & ( TestActor - > GetLevel ( ) = = Blueprint - > GetLevel ( ) )
& & FKismetEditorUtilities : : IsActorValidForLevelScript ( TestActor ) ;
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : ReplaceSelectedNode ( UEdGraphNode * SourceNode , AActor * TargetActor )
{
check ( SourceNode ) ;
if ( TargetActor ! = NULL )
{
UK2Node_Literal * LiteralNode = ( UK2Node_Literal * ) ( SourceNode ) ;
if ( LiteralNode )
{
const FScopedTransaction Transaction ( LOCTEXT ( " ReplaceSelectedNodeUndoTransaction " , " Replace Selected Node " ) ) ;
LiteralNode - > Modify ( ) ;
LiteralNode - > SetObjectRef ( TargetActor ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( CastChecked < UEdGraph > ( SourceNode - > GetOuter ( ) ) ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
}
}
void UEdGraphSchema_K2 : : AddSelectedReplaceableNodes ( UBlueprint * Blueprint , const UEdGraphNode * InGraphNode , FMenuBuilder * MenuBuilder ) const
{
ULevelScriptBlueprint * LevelBlueprint = Cast < ULevelScriptBlueprint > ( Blueprint ) ;
if ( LevelBlueprint )
{
//Only allow replace object reference functionality for literal nodes
if ( InGraphNode - > IsA ( UK2Node_Literal : : StaticClass ( ) ) )
{
UK2Node_Literal * LiteralNode = ( UK2Node_Literal * ) ( InGraphNode ) ;
if ( LiteralNode )
{
USelection * SelectedActors = GEditor - > GetSelectedActors ( ) ;
for ( FSelectionIterator Iter ( * SelectedActors ) ; Iter ; + + Iter )
{
// We only care about actors that are referenced in the world for literals, and also in the same level as this blueprint
AActor * Actor = Cast < AActor > ( * Iter ) ;
if ( LiteralNode - > GetObjectRef ( ) ! = Actor & & IsActorValidForLevelScriptRefs ( Actor , LevelBlueprint ) )
{
FText Description = FText : : Format ( LOCTEXT ( " ChangeToActorName " , " Change to <{0}> " ) , FText : : FromString ( Actor - > GetActorLabel ( ) ) ) ;
FText ToolTip = LOCTEXT ( " ReplaceNodeReferenceToolTip " , " Replace node reference " ) ;
MenuBuilder - > AddMenuEntry ( Description , ToolTip , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateUObject ( ( UEdGraphSchema_K2 * const ) this , & UEdGraphSchema_K2 : : ReplaceSelectedNode , const_cast < UEdGraphNode * > ( InGraphNode ) , Actor ) ) ) ;
}
}
}
}
}
}
bool UEdGraphSchema_K2 : : CanUserKismetAccessVariable ( const UProperty * Property , const UClass * InClass , EDelegateFilterMode FilterMode )
{
const bool bIsDelegate = Property - > IsA ( UMulticastDelegateProperty : : StaticClass ( ) ) ;
const bool bIsAccessible = Property - > HasAllPropertyFlags ( CPF_BlueprintVisible ) ;
const bool bIsAssignableOrCallable = Property - > HasAnyPropertyFlags ( CPF_BlueprintAssignable | CPF_BlueprintCallable ) ;
const bool bPassesDelegateFilter = ( bIsAccessible & & ! bIsDelegate & & ( FilterMode ! = MustBeDelegate ) ) | |
( bIsAssignableOrCallable & & bIsDelegate & & ( FilterMode ! = CannotBeDelegate ) ) ;
const bool bHidden = FObjectEditorUtils : : IsVariableCategoryHiddenFromClass ( Property , InClass ) ;
return ! Property - > HasAnyPropertyFlags ( CPF_Parm ) & & bPassesDelegateFilter & & ! bHidden ;
}
bool UEdGraphSchema_K2 : : ClassHasBlueprintAccessibleMembers ( const UClass * InClass ) const
{
// @TODO Don't show other blueprints yet...
UBlueprint * ClassBlueprint = UBlueprint : : GetBlueprintFromClass ( InClass ) ;
if ( ! InClass - > HasAnyClassFlags ( CLASS_Deprecated | CLASS_NewerVersionExists ) & & ( ClassBlueprint = = NULL ) )
{
// Find functions
for ( TFieldIterator < UFunction > FunctionIt ( InClass , EFieldIteratorFlags : : IncludeSuper ) ; FunctionIt ; + + FunctionIt )
{
UFunction * Function = * FunctionIt ;
const bool bIsBlueprintProtected = Function - > GetBoolMetaData ( FBlueprintMetadata : : MD_Protected ) ;
const bool bHidden = FObjectEditorUtils : : IsFunctionHiddenFromClass ( Function , InClass ) ;
if ( UEdGraphSchema_K2 : : CanUserKismetCallFunction ( Function ) & & ! bIsBlueprintProtected & & ! bHidden )
{
return true ;
}
}
// Find vars
for ( TFieldIterator < UProperty > PropertyIt ( InClass , EFieldIteratorFlags : : IncludeSuper ) ; PropertyIt ; + + PropertyIt )
{
UProperty * Property = * PropertyIt ;
if ( CanUserKismetAccessVariable ( Property , InClass , CannotBeDelegate ) )
{
return true ;
}
}
}
return false ;
}
bool UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( const class UEnum * InEnum )
{
return InEnum & & ( InEnum - > GetBoolMetaData ( FBlueprintMetadata : : MD_AllowableBlueprintVariableType ) | | InEnum - > IsA < UUserDefinedEnum > ( ) ) ;
}
bool UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( const class UClass * InClass )
{
if ( InClass )
{
// No Skeleton classes or reinstancing classes (they would inherit the BlueprintType metadata)
if ( FKismetEditorUtilities : : IsClassABlueprintSkeleton ( InClass )
| | InClass - > HasAnyClassFlags ( CLASS_NewerVersionExists ) )
{
return false ;
}
2014-07-15 03:13:33 -04:00
// No Blueprint Macro Libraries
if ( FKismetEditorUtilities : : IsClassABlueprintMacroLibrary ( InClass ) )
{
return false ;
}
2014-03-14 14:13:41 -04:00
// UObject is an exception, and is always a blueprint-able type
if ( InClass = = UObject : : StaticClass ( ) )
2014-07-07 12:21:40 -04:00
{
2014-03-14 14:13:41 -04:00
return true ;
2014-07-07 12:21:40 -04:00
}
2014-03-14 14:13:41 -04:00
2014-07-11 10:49:58 -04:00
static const FBoolConfigValueHelper NotBlueprintType ( TEXT ( " EditoronlyBP " ) , TEXT ( " bBlueprintIsNotBlueprintType " ) ) ;
if ( NotBlueprintType & & InClass - > IsChildOf ( UBlueprint : : StaticClass ( ) ) )
2014-07-07 12:21:40 -04:00
{
2014-04-23 18:37:23 -04:00
return false ;
2014-07-07 12:21:40 -04:00
}
2014-10-10 17:48:56 -04:00
// cannot have level script variables
if ( InClass - > IsChildOf ( ALevelScriptActor : : StaticClass ( ) ) )
{
return false ;
}
2014-07-08 18:23:43 -04:00
2014-03-14 14:13:41 -04:00
const UClass * ParentClass = InClass ;
while ( ParentClass )
{
// Climb up the class hierarchy and look for "BlueprintType" and "NotBlueprintType" to see if this class is allowed.
if ( ParentClass - > GetBoolMetaData ( FBlueprintMetadata : : MD_AllowableBlueprintVariableType )
| | ParentClass - > HasMetaData ( FBlueprintMetadata : : MD_BlueprintSpawnableComponent ) )
2014-07-07 12:21:40 -04:00
{
2014-03-14 14:13:41 -04:00
return true ;
2014-06-16 11:10:42 -04:00
}
2014-07-07 12:21:40 -04:00
else if ( ParentClass - > GetBoolMetaData ( FBlueprintMetadata : : MD_NotAllowableBlueprintVariableType ) )
{
return false ;
}
ParentClass = ParentClass - > GetSuperClass ( ) ;
2014-06-16 11:10:42 -04:00
}
2014-07-07 12:21:40 -04:00
}
2014-07-08 18:23:43 -04:00
2014-03-14 14:13:41 -04:00
return false ;
2014-07-07 12:21:40 -04:00
}
2014-03-14 14:13:41 -04:00
bool UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( const class UScriptStruct * InStruct )
2014-07-08 18:23:43 -04:00
{
2014-04-23 20:18:55 -04:00
if ( auto UDStruct = Cast < const UUserDefinedStruct > ( InStruct ) )
2014-07-08 18:23:43 -04:00
{
2014-04-23 20:18:55 -04:00
if ( EUserDefinedStructureStatus : : UDSS_UpToDate ! = UDStruct - > Status . GetValue ( ) )
{
return false ;
}
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
return InStruct & & ( InStruct - > GetBoolMetaDataHierarchical ( FBlueprintMetadata : : MD_AllowableBlueprintVariableType ) ) ;
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
bool UEdGraphSchema_K2 : : DoesGraphSupportImpureFunctions ( const UEdGraph * InGraph ) const
2014-07-08 18:23:43 -04:00
{
2014-03-14 14:13:41 -04:00
const EGraphType GraphType = GetGraphType ( InGraph ) ;
const bool bAllowImpureFuncs = GraphType ! = GT_Animation ; //@TODO: It's really more nuanced than this (e.g., in a function someone wants to write as pure)
return bAllowImpureFuncs ;
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
bool UEdGraphSchema_K2 : : IsPropertyExposedOnSpawn ( const UProperty * Property )
2014-07-08 18:23:43 -04:00
{
2014-04-02 18:09:23 -04:00
if ( Property )
2014-07-08 18:23:43 -04:00
{
2014-04-02 18:09:23 -04:00
const bool bMeta = Property - > HasMetaData ( FBlueprintMetadata : : MD_ExposeOnSpawn ) ;
const bool bFlag = Property - > HasAllPropertyFlags ( CPF_ExposeOnSpawn ) ;
if ( bMeta ! = bFlag )
2014-07-08 18:23:43 -04:00
{
2014-04-02 18:09:23 -04:00
UE_LOG ( LogBlueprint , Warning
, TEXT ( " ExposeOnSpawn ambiguity. Property '%s', MetaData '%s', Flag '%s' " )
, * Property - > GetFullName ( )
, bMeta ? * GTrue . ToString ( ) : * GFalse . ToString ( )
, bFlag ? * GTrue . ToString ( ) : * GFalse . ToString ( ) ) ;
2014-07-08 18:23:43 -04:00
}
2014-04-02 18:09:23 -04:00
return bMeta | | bFlag ;
2014-07-08 18:23:43 -04:00
}
2014-04-02 18:09:23 -04:00
return false ;
}
2014-03-14 14:13:41 -04:00
// if node is a get/set variable and the variable it refers to does not exist
static bool IsUsingNonExistantVariable ( const UEdGraphNode * InGraphNode , UBlueprint * OwnerBlueprint )
{
bool bNonExistantVariable = false ;
const bool bBreakOrMakeStruct =
InGraphNode - > IsA ( UK2Node_BreakStruct : : StaticClass ( ) ) | |
InGraphNode - > IsA ( UK2Node_MakeStruct : : StaticClass ( ) ) ;
if ( ! bBreakOrMakeStruct )
{
if ( const UK2Node_Variable * Variable = Cast < const UK2Node_Variable > ( InGraphNode ) )
{
if ( Variable - > VariableReference . IsSelfContext ( ) )
{
TArray < FName > CurrentVars ;
FBlueprintEditorUtils : : GetClassVariableList ( OwnerBlueprint , CurrentVars ) ;
2014-10-07 16:04:29 -04:00
if ( false = = CurrentVars . Contains ( Variable - > GetVarName ( ) ) )
{
bNonExistantVariable = true ;
}
}
else if ( Variable - > VariableReference . IsLocalScope ( ) )
{
// If there is no member scope, or we can't find the local variable in the member scope, then it's non-existant
if ( ! Variable - > VariableReference . GetMemberScope ( Variable )
| | ( Variable - > VariableReference . GetMemberScope ( Variable ) & & ! FBlueprintEditorUtils : : FindLocalVariable ( OwnerBlueprint , Variable - > VariableReference . GetMemberScope ( Variable ) , Variable - > GetVarName ( ) ) ) )
2014-03-14 14:13:41 -04:00
{
bNonExistantVariable = true ;
}
}
}
}
return bNonExistantVariable ;
}
2014-06-16 11:10:42 -04:00
bool UEdGraphSchema_K2 : : PinHasSplittableStructType ( const UEdGraphPin * InGraphPin ) const
{
const FEdGraphPinType & PinType = InGraphPin - > PinType ;
2014-08-19 15:17:39 -04:00
bool bCanSplit = ( ! PinType . bIsArray & & PinType . PinCategory = = PC_Struct ) ;
2014-06-16 11:10:42 -04:00
if ( bCanSplit )
{
UScriptStruct * StructType = CastChecked < UScriptStruct > ( InGraphPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( InGraphPin - > Direction = = EGPD_Input )
{
bCanSplit = UK2Node_MakeStruct : : CanBeMade ( StructType ) ;
if ( ! bCanSplit )
{
const FString & MetaData = StructType - > GetMetaData ( TEXT ( " HasNativeMake " ) ) ;
UFunction * Function = FindObject < UFunction > ( NULL , * MetaData , true ) ;
bCanSplit = ( Function ! = NULL ) ;
}
}
else
{
bCanSplit = UK2Node_BreakStruct : : CanBeBroken ( StructType ) ;
if ( ! bCanSplit )
{
const FString & MetaData = StructType - > GetMetaData ( TEXT ( " HasNativeBreak " ) ) ;
UFunction * Function = FindObject < UFunction > ( NULL , * MetaData , true ) ;
bCanSplit = ( Function ! = NULL ) ;
}
}
}
return bCanSplit ;
}
2014-07-14 17:15:42 -04:00
bool UEdGraphSchema_K2 : : PinDefaultValueIsEditable ( const UEdGraphPin & InGraphPin ) const
{
// Array types are not currently assignable without a 'make array' node:
if ( InGraphPin . PinType . bIsArray )
{
return false ;
}
// User defined structures (from code or from data) cannot accept default values:
if ( InGraphPin . PinType . PinCategory = = PC_Struct )
{
// Only the built in struct types are editable as 'default' values on a pin.
// See FNodeFactory::CreatePinWidget for justification of the above statement!
UObject const & SubCategoryObject = * InGraphPin . PinType . PinSubCategoryObject ;
return & SubCategoryObject = = VectorStruct
| | & SubCategoryObject = = RotatorStruct
| | & SubCategoryObject = = TransformStruct
| | & SubCategoryObject = = LinearColorStruct
| | & SubCategoryObject = = ColorStruct ;
}
return true ;
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : GetContextMenuActions ( const UEdGraph * CurrentGraph , const UEdGraphNode * InGraphNode , const UEdGraphPin * InGraphPin , FMenuBuilder * MenuBuilder , bool bIsDebugging ) const
{
check ( CurrentGraph ) ;
UBlueprint * OwnerBlueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( CurrentGraph ) ;
if ( InGraphPin ! = NULL )
{
MenuBuilder - > BeginSection ( " EdGraphSchemaPinActions " , LOCTEXT ( " PinActionsMenuHeader " , " Pin Actions " ) ) ;
{
if ( ! bIsDebugging )
2014-07-08 18:23:43 -04:00
{
// Break pin links
if ( InGraphPin - > LinkedTo . Num ( ) > 1 )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . BreakPinLinks ) ;
}
// Add the change pin type action, if this is a select node
if ( InGraphNode - > IsA ( UK2Node_Select : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . ChangePinType ) ;
}
// add sub menu for break link to
if ( InGraphPin - > LinkedTo . Num ( ) > 0 )
{
if ( InGraphPin - > LinkedTo . Num ( ) > 1 )
{
MenuBuilder - > AddSubMenu (
LOCTEXT ( " BreakLinkTo " , " Break Link To... " ) ,
LOCTEXT ( " BreakSpecificLinks " , " Break a specific link... " ) ,
FNewMenuDelegate : : CreateUObject ( ( UEdGraphSchema_K2 * const ) this , & UEdGraphSchema_K2 : : GetBreakLinkToSubMenuActions , const_cast < UEdGraphPin * > ( InGraphPin ) ) ) ;
2014-04-02 18:09:23 -04:00
MenuBuilder - > AddSubMenu (
LOCTEXT ( " JumpToConnection " , " Jump to Connection... " ) ,
LOCTEXT ( " JumpToSpecificConnection " , " Jump to specific connection... " ) ,
FNewMenuDelegate : : CreateUObject ( ( UEdGraphSchema_K2 * const ) this , & UEdGraphSchema_K2 : : GetJumpToConnectionSubMenuActions , const_cast < UEdGraphPin * > ( InGraphPin ) ) ) ;
2014-07-08 18:23:43 -04:00
}
else
{
( ( UEdGraphSchema_K2 * const ) this ) - > GetBreakLinkToSubMenuActions ( * MenuBuilder , const_cast < UEdGraphPin * > ( InGraphPin ) ) ;
2014-04-02 18:09:23 -04:00
( ( UEdGraphSchema_K2 * const ) this ) - > GetJumpToConnectionSubMenuActions ( * MenuBuilder , const_cast < UEdGraphPin * > ( InGraphPin ) ) ;
2014-07-08 18:23:43 -04:00
}
}
// Conditionally add the var promotion pin if this is an output pin and it's not an exec pin
if ( InGraphPin - > PinType . PinCategory ! = PC_Exec )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . PromoteToVariable ) ;
}
2014-07-11 17:44:43 -04:00
if ( PinHasSplittableStructType ( InGraphPin ) & & InGraphNode - > AllowSplitPins ( ) )
2014-05-08 15:03:09 -04:00
{
2014-06-16 11:10:42 -04:00
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . SplitStructPin ) ;
2014-05-08 15:03:09 -04:00
}
2014-06-16 11:10:42 -04:00
if ( InGraphPin - > ParentPin ! = NULL )
2014-05-08 15:03:09 -04:00
{
2014-06-16 11:10:42 -04:00
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RecombineStructPin ) ;
2014-05-08 15:03:09 -04:00
}
2014-08-14 16:28:28 -04:00
2014-07-08 18:23:43 -04:00
// Conditionally add the execution path pin removal if this is an execution branching node
if ( InGraphPin - > Direction = = EGPD_Output & & InGraphPin - > GetOwningNode ( ) )
{
2014-09-16 10:25:25 -04:00
if ( CastChecked < UK2Node > ( InGraphPin - > GetOwningNode ( ) ) - > CanEverRemoveExecutionPin ( ) )
2014-07-08 18:23:43 -04:00
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RemoveExecutionPin ) ;
}
}
2014-06-30 16:03:48 -04:00
if ( UK2Node_SetFieldsInStruct : : ShowCustomPinActions ( InGraphPin , true ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RemoveThisStructVarPin ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RemoveOtherStructVarPins ) ;
}
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
}
MenuBuilder - > EndSection ( ) ;
// Add the watch pin / unwatch pin menu items
MenuBuilder - > BeginSection ( " EdGraphSchemaWatches " , LOCTEXT ( " WatchesHeader " , " Watches " ) ) ;
{
if ( ! IsMetaPin ( * InGraphPin ) )
{
const UEdGraphPin * WatchedPin = ( ( InGraphPin - > Direction = = EGPD_Input ) & & ( InGraphPin - > LinkedTo . Num ( ) > 0 ) ) ? InGraphPin - > LinkedTo [ 0 ] : InGraphPin ;
if ( FKismetDebugUtilities : : IsPinBeingWatched ( OwnerBlueprint , WatchedPin ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . StopWatchingPin ) ;
}
else
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . StartWatchingPin ) ;
}
}
}
MenuBuilder - > EndSection ( ) ;
}
else if ( InGraphNode ! = NULL )
{
if ( IsUsingNonExistantVariable ( InGraphNode , OwnerBlueprint ) )
{
MenuBuilder - > BeginSection ( " EdGraphSchemaNodeActions " , LOCTEXT ( " NodeActionsMenuHeader " , " Node Actions " ) ) ;
{
GetNonExistentVariableMenu ( InGraphNode , OwnerBlueprint , MenuBuilder ) ;
}
MenuBuilder - > EndSection ( ) ;
}
else
{
MenuBuilder - > BeginSection ( " EdGraphSchemaNodeActions " , LOCTEXT ( " NodeActionsMenuHeader " , " Node Actions " ) ) ;
{
if ( ! bIsDebugging )
{
// Replaceable node display option
AddSelectedReplaceableNodes ( OwnerBlueprint , InGraphNode , MenuBuilder ) ;
// Node contextual actions
MenuBuilder - > AddMenuEntry ( FGenericCommands : : Get ( ) . Delete ) ;
MenuBuilder - > AddMenuEntry ( FGenericCommands : : Get ( ) . Cut ) ;
MenuBuilder - > AddMenuEntry ( FGenericCommands : : Get ( ) . Copy ) ;
MenuBuilder - > AddMenuEntry ( FGenericCommands : : Get ( ) . Duplicate ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . ReconstructNodes ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . BreakNodeLinks ) ;
// tunnel nodes have option to open function editor
if ( InGraphNode - > IsA ( UK2Node_Tunnel : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . EditTunnel ) ;
}
// Conditionally add the action to add an execution pin, if this is an execution node
if ( InGraphNode - > IsA ( UK2Node_ExecutionSequence : : StaticClass ( ) ) | | InGraphNode - > IsA ( UK2Node_Switch : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AddExecutionPin ) ;
}
// Conditionally add the action to create a super function call node, if this is an event or function entry
if ( InGraphNode - > IsA ( UK2Node_Event : : StaticClass ( ) ) | | InGraphNode - > IsA ( UK2Node_FunctionEntry : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AddParentNode ) ;
}
// Conditionally add the actions to add or remove an option pin, if this is a select node
if ( InGraphNode - > IsA ( UK2Node_Select : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AddOptionPin ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RemoveOptionPin ) ;
}
// Conditionally add the action to find instances of the node if it is a custom event
if ( InGraphNode - > IsA ( UK2Node_CustomEvent : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . FindInstancesOfCustomEvent ) ;
}
// Don't show the "Assign selected Actor" option if more than one actor is selected
if ( InGraphNode - > IsA ( UK2Node_ActorBoundEvent : : StaticClass ( ) ) & & GEditor - > GetSelectedActorCount ( ) = = 1 )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AssignReferencedActor ) ;
}
2014-04-23 18:24:27 -04:00
// Add the goto source code action for native functions
if ( InGraphNode - > IsA ( UK2Node_CallFunction : : StaticClass ( ) ) )
{
2014-08-25 15:47:12 -04:00
const UEdGraphNode * ResultEventNode = NULL ;
if ( Cast < UK2Node_CallFunction > ( InGraphNode ) - > GetFunctionGraph ( ResultEventNode ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . GoToDefinition ) ;
}
else
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . GotoNativeFunctionDefinition ) ;
}
}
// Functions, macros, and composite nodes support going to a definition
if ( InGraphNode - > IsA ( UK2Node_MacroInstance : : StaticClass ( ) ) | | InGraphNode - > IsA ( UK2Node_Composite : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . GoToDefinition ) ;
2014-04-23 18:24:27 -04:00
}
// show search for references for variable nodes and goto source code action
2014-03-14 14:13:41 -04:00
if ( InGraphNode - > IsA ( UK2Node_Variable : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . FindVariableReferences ) ;
2014-04-23 18:24:27 -04:00
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . GotoNativeVariableDefinition ) ;
2014-10-13 15:07:57 -04:00
GetReplaceVariableMenu ( InGraphNode , OwnerBlueprint , MenuBuilder , true ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-30 16:03:48 -04:00
if ( InGraphNode - > IsA ( UK2Node_SetFieldsInStruct : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RestoreAllStructVarPins ) ;
}
2014-03-14 14:13:41 -04:00
MenuBuilder - > AddMenuEntry ( FGenericCommands : : Get ( ) . Rename , NAME_None , LOCTEXT ( " Rename " , " Rename " ) , LOCTEXT ( " Rename_Tooltip " , " Renames selected function or variable in blueprint. " ) ) ;
}
// Select referenced actors in the level
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . SelectReferenceInLevel ) ;
}
MenuBuilder - > EndSection ( ) ; //EdGraphSchemaNodeActions
if ( ! bIsDebugging )
{
// Collapse/expand nodes
MenuBuilder - > BeginSection ( " EdGraphSchemaOrganization " , LOCTEXT ( " OrganizationHeader " , " Organization " ) ) ;
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . CollapseNodes ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . CollapseSelectionToFunction ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . CollapseSelectionToMacro ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . ExpandNodes ) ;
if ( InGraphNode - > IsA ( UK2Node_Composite : : StaticClass ( ) ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . PromoteSelectionToFunction ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . PromoteSelectionToMacro ) ;
}
}
MenuBuilder - > EndSection ( ) ;
}
// Add breakpoint actions
if ( const UK2Node * K2Node = Cast < const UK2Node > ( InGraphNode ) )
{
if ( ! K2Node - > IsNodePure ( ) )
{
2014-07-08 18:23:43 -04:00
MenuBuilder - > BeginSection ( " EdGraphSchemaBreakpoints " , LOCTEXT ( " BreakpointsHeader " , " Breakpoints " ) ) ;
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . ToggleBreakpoint ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AddBreakpoint ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . RemoveBreakpoint ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . EnableBreakpoint ) ;
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . DisableBreakpoint ) ;
}
MenuBuilder - > EndSection ( ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
Super : : GetContextMenuActions ( CurrentGraph , InGraphNode , InGraphPin , MenuBuilder , bIsDebugging ) ;
}
void UEdGraphSchema_K2 : : OnCreateNonExistentVariable ( UK2Node_Variable * Variable , UBlueprint * OwnerBlueprint )
{
if ( UEdGraphPin * Pin = Variable - > FindPin ( Variable - > GetVarNameString ( ) ) )
{
2014-10-07 16:04:29 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " CreateMissingVariable " , " Create Missing Variable " ) ) ;
2014-03-14 14:13:41 -04:00
if ( FBlueprintEditorUtils : : AddMemberVariable ( OwnerBlueprint , Variable - > GetVarName ( ) , Pin - > PinType ) )
{
Variable - > VariableReference . SetSelfMember ( Variable - > GetVarName ( ) ) ;
}
}
}
2014-10-07 16:04:29 -04:00
void UEdGraphSchema_K2 : : OnCreateNonExistentLocalVariable ( UK2Node_Variable * Variable , UBlueprint * OwnerBlueprint )
2014-03-14 14:13:41 -04:00
{
if ( UEdGraphPin * Pin = Variable - > FindPin ( Variable - > GetVarNameString ( ) ) )
{
2014-10-07 16:04:29 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " CreateMissingLocalVariable " , " Create Missing Local Variable " ) ) ;
FName VarName = Variable - > GetVarName ( ) ;
if ( FBlueprintEditorUtils : : AddLocalVariable ( OwnerBlueprint , Variable - > GetGraph ( ) , VarName , Pin - > PinType ) )
{
FGuid LocalVarGuid = FBlueprintEditorUtils : : FindLocalVariableGuidByName ( OwnerBlueprint , Variable - > GetGraph ( ) , VarName ) ;
if ( LocalVarGuid . IsValid ( ) )
{
Variable - > VariableReference . SetLocalMember ( VarName , Variable - > GetGraph ( ) - > GetName ( ) , LocalVarGuid ) ;
}
}
}
}
void UEdGraphSchema_K2 : : OnReplaceVariableForVariableNode ( UK2Node_Variable * Variable , UBlueprint * OwnerBlueprint , FString VariableName , bool bIsSelfMember )
{
if ( UEdGraphPin * Pin = Variable - > FindPin ( Variable - > GetVarNameString ( ) ) )
{
2014-10-13 15:07:57 -04:00
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " GraphEd_ReplaceVariable " , " Replace Variable " ) ) ;
Variable - > Modify ( ) ;
Pin - > Modify ( ) ;
2014-10-07 16:04:29 -04:00
if ( bIsSelfMember )
{
Variable - > VariableReference . SetSelfMember ( FName ( * VariableName ) ) ;
}
else
{
Variable - > VariableReference . SetLocalMember ( FName ( * VariableName ) , Variable - > GetGraph ( ) - > GetName ( ) , FBlueprintEditorUtils : : FindLocalVariableGuidByName ( OwnerBlueprint , Variable - > GetGraph ( ) , * VariableName ) ) ;
}
2014-03-14 14:13:41 -04:00
Pin - > PinName = VariableName ;
2014-10-07 16:04:29 -04:00
Variable - > ReconstructNode ( ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-10-13 15:07:57 -04:00
void UEdGraphSchema_K2 : : GetReplaceVariableMenu ( FMenuBuilder & MenuBuilder , UK2Node_Variable * Variable , UBlueprint * OwnerBlueprint , bool bReplaceExistingVariable /*=false*/ )
2014-03-14 14:13:41 -04:00
{
if ( UEdGraphPin * Pin = Variable - > FindPin ( Variable - > GetVarNameString ( ) ) )
{
2014-10-13 15:07:57 -04:00
FName ExistingVariableName = bReplaceExistingVariable ? Variable - > GetVarName ( ) : NAME_None ;
FText ReplaceVariableWithTooltipFormat ;
if ( ! bReplaceExistingVariable )
{
ReplaceVariableWithTooltipFormat = LOCTEXT ( " ReplaceNonExistantVarToolTip " , " Variable '{OldVariable}' does not exist, replace with matching variable '{AlternateVariable}'? " ) ;
}
else
{
ReplaceVariableWithTooltipFormat = LOCTEXT ( " ReplaceExistantVarToolTip " , " Replace Variable '{OldVariable}' with matching variable '{AlternateVariable}'? " ) ;
}
2014-03-14 14:13:41 -04:00
TArray < FName > Variables ;
FBlueprintEditorUtils : : GetNewVariablesOfType ( OwnerBlueprint , Pin - > PinType , Variables ) ;
2014-10-07 16:04:29 -04:00
MenuBuilder . BeginSection ( NAME_None , LOCTEXT ( " Variables " , " Variables " ) ) ;
2014-03-14 14:13:41 -04:00
for ( TArray < FName > : : TIterator VarIt ( Variables ) ; VarIt ; + + VarIt )
{
2014-10-13 15:07:57 -04:00
if ( * VarIt ! = ExistingVariableName )
{
const FText AlternativeVar = FText : : FromName ( * VarIt ) ;
2014-03-14 14:13:41 -04:00
2014-10-13 15:07:57 -04:00
FFormatNamedArguments TooltipArgs ;
TooltipArgs . Add ( TEXT ( " OldVariable " ) , Variable - > GetVarNameText ( ) ) ;
TooltipArgs . Add ( TEXT ( " AlternateVariable " ) , AlternativeVar ) ;
const FText Desc = FText : : Format ( ReplaceVariableWithTooltipFormat , TooltipArgs ) ;
MenuBuilder . AddMenuEntry ( AlternativeVar , Desc , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateStatic ( & UEdGraphSchema_K2 : : OnReplaceVariableForVariableNode , const_cast < UK2Node_Variable * > ( Variable ) , OwnerBlueprint , ( * VarIt ) . ToString ( ) , /*bIsSelfMember=*/ true ) ) ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-10-07 16:04:29 -04:00
MenuBuilder . EndSection ( ) ;
2014-10-13 15:07:57 -04:00
FText ReplaceLocalVariableWithTooltipFormat ;
if ( ! bReplaceExistingVariable )
{
ReplaceLocalVariableWithTooltipFormat = LOCTEXT ( " ReplaceNonExistantLocalVarToolTip " , " Variable '{OldVariable}' does not exist, replace with matching local variable '{AlternateVariable}'? " ) ;
}
else
{
ReplaceLocalVariableWithTooltipFormat = LOCTEXT ( " ReplaceExistantLocalVarToolTip " , " Replace Variable '{OldVariable}' with matching local variable '{AlternateVariable}'? " ) ;
}
2014-10-07 16:04:29 -04:00
TArray < FName > LocalVariables ;
FBlueprintEditorUtils : : GetLocalVariablesOfType ( Variable - > GetGraph ( ) , Pin - > PinType , LocalVariables ) ;
MenuBuilder . BeginSection ( NAME_None , LOCTEXT ( " LocalVariables " , " LocalVariables " ) ) ;
for ( TArray < FName > : : TIterator VarIt ( LocalVariables ) ; VarIt ; + + VarIt )
{
2014-10-13 15:07:57 -04:00
if ( * VarIt ! = ExistingVariableName )
{
const FText AlternativeVar = FText : : FromName ( * VarIt ) ;
2014-10-07 16:04:29 -04:00
2014-10-13 15:07:57 -04:00
FFormatNamedArguments TooltipArgs ;
TooltipArgs . Add ( TEXT ( " OldVariable " ) , Variable - > GetVarNameText ( ) ) ;
TooltipArgs . Add ( TEXT ( " AlternateVariable " ) , AlternativeVar ) ;
const FText Desc = FText : : Format ( ReplaceLocalVariableWithTooltipFormat , TooltipArgs ) ;
MenuBuilder . AddMenuEntry ( AlternativeVar , Desc , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateStatic ( & UEdGraphSchema_K2 : : OnReplaceVariableForVariableNode , const_cast < UK2Node_Variable * > ( Variable ) , OwnerBlueprint , ( * VarIt ) . ToString ( ) , /*bIsSelfMember=*/ false ) ) ) ;
}
2014-10-07 16:04:29 -04:00
}
MenuBuilder . EndSection ( ) ;
2014-03-14 14:13:41 -04:00
}
}
void UEdGraphSchema_K2 : : GetNonExistentVariableMenu ( const UEdGraphNode * InGraphNode , UBlueprint * OwnerBlueprint , FMenuBuilder * MenuBuilder ) const
{
if ( const UK2Node_Variable * Variable = Cast < const UK2Node_Variable > ( InGraphNode ) )
{
2014-10-07 16:04:29 -04:00
// Creating missing variables should never occur in a Macro Library or Interface, they do not support variables
if ( OwnerBlueprint - > BlueprintType ! = BPTYPE_MacroLibrary & & OwnerBlueprint - > BlueprintType ! = BPTYPE_Interface )
{
// Creating missing member variables should never occur in a Function Library, they do not support variables
if ( OwnerBlueprint - > BlueprintType ! = BPTYPE_FunctionLibrary )
{
// create missing variable
const FText Label = FText : : Format ( LOCTEXT ( " CreateNonExistentVar " , " Create variable '{0}' " ) , Variable - > GetVarNameText ( ) ) ;
const FText Desc = FText : : Format ( LOCTEXT ( " CreateNonExistentVarToolTip " , " Variable '{0}' does not exist, create it? " ) , Variable - > GetVarNameText ( ) ) ;
MenuBuilder - > AddMenuEntry ( Label , Desc , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateStatic ( & UEdGraphSchema_K2 : : OnCreateNonExistentVariable , const_cast < UK2Node_Variable * > ( Variable ) , OwnerBlueprint ) ) ) ;
}
// Only allow creating missing local variables if in a function graph
if ( InGraphNode - > GetGraph ( ) - > GetSchema ( ) - > GetGraphType ( InGraphNode - > GetGraph ( ) ) = = GT_Function )
{
const FText Label = FText : : Format ( LOCTEXT ( " CreateNonExistentLocalVar " , " Create local variable '{0}' " ) , Variable - > GetVarNameText ( ) ) ;
const FText Desc = FText : : Format ( LOCTEXT ( " CreateNonExistentLocalVarToolTip " , " Local variable '{0}' does not exist, create it? " ) , Variable - > GetVarNameText ( ) ) ;
MenuBuilder - > AddMenuEntry ( Label , Desc , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateStatic ( & UEdGraphSchema_K2 : : OnCreateNonExistentLocalVariable , const_cast < UK2Node_Variable * > ( Variable ) , OwnerBlueprint ) ) ) ;
}
2014-03-14 14:13:41 -04:00
}
// delete this node
{
const FText Desc = FText : : Format ( LOCTEXT ( " DeleteNonExistentVarToolTip " , " Referenced variable '{0}' does not exist, delete this node? " ) , Variable - > GetVarNameText ( ) ) ;
MenuBuilder - > AddMenuEntry ( FGenericCommands : : Get ( ) . Delete , NAME_None , FGenericCommands : : Get ( ) . Delete - > GetLabel ( ) , Desc ) ;
}
2014-10-13 15:07:57 -04:00
GetReplaceVariableMenu ( InGraphNode , OwnerBlueprint , MenuBuilder ) ;
}
}
void UEdGraphSchema_K2 : : GetReplaceVariableMenu ( const UEdGraphNode * InGraphNode , UBlueprint * InOwnerBlueprint , FMenuBuilder * InMenuBuilder , bool bInReplaceExistingVariable /* = false*/ ) const
{
if ( const UK2Node_Variable * Variable = Cast < const UK2Node_Variable > ( InGraphNode ) )
{
2014-03-14 14:13:41 -04:00
// replace with matching variables
if ( UEdGraphPin * Pin = Variable - > FindPin ( Variable - > GetVarNameString ( ) ) )
{
2014-10-13 15:07:57 -04:00
FName ExistingVariableName = bInReplaceExistingVariable ? Variable - > GetVarName ( ) : NAME_None ;
2014-03-14 14:13:41 -04:00
TArray < FName > Variables ;
2014-10-13 15:07:57 -04:00
FBlueprintEditorUtils : : GetNewVariablesOfType ( InOwnerBlueprint , Pin - > PinType , Variables ) ;
Variables . RemoveSwap ( ExistingVariableName ) ;
2014-03-14 14:13:41 -04:00
2014-10-07 16:04:29 -04:00
TArray < FName > LocalVariables ;
FBlueprintEditorUtils : : GetLocalVariablesOfType ( Variable - > GetGraph ( ) , Pin - > PinType , LocalVariables ) ;
2014-10-13 15:07:57 -04:00
LocalVariables . RemoveSwap ( ExistingVariableName ) ;
2014-10-07 16:04:29 -04:00
if ( Variables . Num ( ) > 0 | | LocalVariables . Num ( ) > 0 )
2014-03-14 14:13:41 -04:00
{
2014-10-13 15:07:57 -04:00
FText ReplaceVariableWithTooltip ;
if ( bInReplaceExistingVariable )
{
ReplaceVariableWithTooltip = LOCTEXT ( " ReplaceVariableWithToolTip " , " Replace Variable '{0}' with another variable? " ) ;
}
else
{
ReplaceVariableWithTooltip = LOCTEXT ( " ReplaceMissingVariableWithToolTip " , " Variable '{0}' does not exist, replace with another variable? " ) ;
}
InMenuBuilder - > AddSubMenu (
2014-03-14 14:13:41 -04:00
FText : : Format ( LOCTEXT ( " ReplaceVariableWith " , " Replace variable '{0}' with... " ) , Variable - > GetVarNameText ( ) ) ,
2014-10-13 15:07:57 -04:00
FText : : Format ( ReplaceVariableWithTooltip , Variable - > GetVarNameText ( ) ) ,
FNewMenuDelegate : : CreateStatic ( & UEdGraphSchema_K2 : : GetReplaceVariableMenu ,
const_cast < UK2Node_Variable * > ( Variable ) , InOwnerBlueprint , bInReplaceExistingVariable ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
void UEdGraphSchema_K2 : : GetBreakLinkToSubMenuActions ( class FMenuBuilder & MenuBuilder , UEdGraphPin * InGraphPin )
{
// Make sure we have a unique name for every entry in the list
TMap < FString , uint32 > LinkTitleCount ;
// Add all the links we could break from
for ( TArray < class UEdGraphPin * > : : TConstIterator Links ( InGraphPin - > LinkedTo ) ; Links ; + + Links )
{
UEdGraphPin * Pin = * Links ;
2014-04-23 18:30:37 -04:00
FText Title = Pin - > GetOwningNode ( ) - > GetNodeTitle ( ENodeTitleType : : ListView ) ;
FString TitleString = Title . ToString ( ) ;
2014-03-14 14:13:41 -04:00
if ( Pin - > PinName ! = TEXT ( " " ) )
{
2014-08-07 13:23:24 -04:00
TitleString = FString : : Printf ( TEXT ( " %s (%s) " ) , * TitleString , * Pin - > GetDisplayName ( ) . ToString ( ) ) ;
2014-03-14 14:13:41 -04:00
// Add name of connection if possible
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeTitle " ) , Title ) ;
2014-08-07 13:23:24 -04:00
Args . Add ( TEXT ( " PinName " ) , Pin - > GetDisplayName ( ) ) ;
2014-03-14 14:13:41 -04:00
Title = FText : : Format ( LOCTEXT ( " BreakDescPin " , " {NodeTitle} ({PinName}) " ) , Args ) ;
}
uint32 & Count = LinkTitleCount . FindOrAdd ( TitleString ) ;
FText Description ;
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeTitle " ) , Title ) ;
Args . Add ( TEXT ( " NumberOfNodes " ) , Count ) ;
if ( Count = = 0 )
{
Description = FText : : Format ( LOCTEXT ( " BreakDesc " , " Break link to {NodeTitle} " ) , Args ) ;
}
else
{
Description = FText : : Format ( LOCTEXT ( " BreakDescMulti " , " Break link to {NodeTitle} ({NumberOfNodes}) " ) , Args ) ;
}
+ + Count ;
MenuBuilder . AddMenuEntry ( Description , Description , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateUObject ( ( USoundClassGraphSchema * const ) this , & USoundClassGraphSchema : : BreakSinglePinLink , const_cast < UEdGraphPin * > ( InGraphPin ) , * Links ) ) ) ;
}
}
2014-04-02 18:09:23 -04:00
void UEdGraphSchema_K2 : : GetJumpToConnectionSubMenuActions ( class FMenuBuilder & MenuBuilder , UEdGraphPin * InGraphPin )
{
// Make sure we have a unique name for every entry in the list
TMap < FString , uint32 > LinkTitleCount ;
// Add all the links we could break from
for ( auto PinLink : InGraphPin - > LinkedTo )
2014-07-08 18:23:43 -04:00
{
2014-04-23 18:30:37 -04:00
FText Title = PinLink - > GetOwningNode ( ) - > GetNodeTitle ( ENodeTitleType : : ListView ) ;
FString TitleString = Title . ToString ( ) ;
2014-04-02 18:09:23 -04:00
if ( PinLink - > PinName ! = TEXT ( " " ) )
2014-07-08 18:23:43 -04:00
{
2014-08-07 13:23:24 -04:00
TitleString = FString : : Printf ( TEXT ( " %s (%s) " ) , * TitleString , * PinLink - > GetDisplayName ( ) . ToString ( ) ) ;
2014-04-02 18:09:23 -04:00
// Add name of connection if possible
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeTitle " ) , Title ) ;
2014-08-07 13:23:24 -04:00
Args . Add ( TEXT ( " PinName " ) , PinLink - > GetDisplayName ( ) ) ;
2014-04-02 18:09:23 -04:00
Title = FText : : Format ( LOCTEXT ( " JumpToDescPin " , " {NodeTitle} ({PinName}) " ) , Args ) ;
}
uint32 & Count = LinkTitleCount . FindOrAdd ( TitleString ) ;
FText Description ;
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " NodeTitle " ) , Title ) ;
Args . Add ( TEXT ( " NumberOfNodes " ) , Count ) ;
if ( Count = = 0 )
2014-07-08 18:23:43 -04:00
{
2014-04-02 18:09:23 -04:00
Description = FText : : Format ( LOCTEXT ( " JumpDesc " , " Jump to {NodeTitle} " ) , Args ) ;
2014-07-08 18:23:43 -04:00
}
else
{
2014-04-02 18:09:23 -04:00
Description = FText : : Format ( LOCTEXT ( " JumpDescMulti " , " Jump to {NodeTitle} ({NumberOfNodes}) " ) , Args ) ;
2014-07-08 18:23:43 -04:00
}
2014-04-02 18:09:23 -04:00
+ + Count ;
MenuBuilder . AddMenuEntry ( Description , Description , FSlateIcon ( ) , FUIAction (
FExecuteAction : : CreateStatic ( & FKismetEditorUtilities : : BringKismetToFocusAttentionOnObject , Cast < const UObject > ( PinLink ) , false ) ) ) ;
}
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : GetGraphContextActions ( FGraphContextMenuBuilder & ContextMenuBuilder ) const
2014-07-08 18:23:43 -04:00
{
2014-03-14 14:13:41 -04:00
FBlueprintGraphActionListBuilder BlueprintContextMenuBuilder ( ContextMenuBuilder . CurrentGraph ) ;
BlueprintContextMenuBuilder . FromPin = ContextMenuBuilder . FromPin ;
BlueprintContextMenuBuilder . SelectedObjects . Append ( ContextMenuBuilder . SelectedObjects ) ;
check ( BlueprintContextMenuBuilder . Blueprint ! = NULL ) ;
// Run thru all nodes and add any menu items they want to add
Super : : GetGraphContextActions ( BlueprintContextMenuBuilder ) ;
// Now do schema-specific stuff
FK2ActionMenuBuilder ( this ) . GetGraphContextActions ( BlueprintContextMenuBuilder ) ;
ContextMenuBuilder . Append ( BlueprintContextMenuBuilder ) ;
}
void UEdGraphSchema_K2 : : GetAllActions ( FBlueprintPaletteListBuilder & PaletteBuilder )
2014-07-08 18:23:43 -04:00
{
2014-03-14 14:13:41 -04:00
const UEdGraphSchema_K2 * K2SchemaInst = GetDefault < UEdGraphSchema_K2 > ( ) ;
FK2ActionMenuBuilder ( K2SchemaInst ) . GetAllActions ( PaletteBuilder ) ;
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : GetPaletteActions ( FBlueprintPaletteListBuilder & ActionMenuBuilder , TWeakObjectPtr < UClass > FilterClass /* = NULL*/ )
2014-07-15 13:26:38 -04:00
{
2014-03-14 14:13:41 -04:00
const UEdGraphSchema_K2 * K2SchemaInst = GetDefault < UEdGraphSchema_K2 > ( ) ;
FK2ActionMenuBuilder ( K2SchemaInst ) . GetPaletteActions ( ActionMenuBuilder , FilterClass ) ;
}
const FPinConnectionResponse UEdGraphSchema_K2 : : DetermineConnectionResponseOfCompatibleTypedPins ( const UEdGraphPin * PinA , const UEdGraphPin * PinB , const UEdGraphPin * InputPin , const UEdGraphPin * OutputPin ) const
{
// Now check to see if there are already connections and this is an 'exclusive' connection
const bool bBreakExistingDueToExecOutput = IsExecPin ( * OutputPin ) & & ( OutputPin - > LinkedTo . Num ( ) > 0 ) ;
const bool bBreakExistingDueToDataInput = ! IsExecPin ( * InputPin ) & & ( InputPin - > LinkedTo . Num ( ) > 0 ) ;
bool bMultipleSelfException = false ;
const UK2Node * OwningNode = Cast < UK2Node > ( InputPin - > GetOwningNode ( ) ) ;
if ( bBreakExistingDueToDataInput & &
IsSelfPin ( * InputPin ) & &
OwningNode & &
OwningNode - > AllowMultipleSelfs ( false ) & &
! InputPin - > PinType . bIsArray & &
! OutputPin - > PinType . bIsArray )
{
//check if the node wont be expanded as foreach call, if there is a link to an array
bool bAnyArrayInput = false ;
for ( int InputLinkIndex = 0 ; InputLinkIndex < InputPin - > LinkedTo . Num ( ) ; InputLinkIndex + + )
{
if ( const UEdGraphPin * Pin = InputPin - > LinkedTo [ InputLinkIndex ] )
{
if ( Pin - > PinType . bIsArray )
{
bAnyArrayInput = true ;
break ;
}
}
}
bMultipleSelfException = ! bAnyArrayInput ;
}
if ( bBreakExistingDueToExecOutput )
{
const ECanCreateConnectionResponse ReplyBreakOutputs = ( PinA = = OutputPin ) ? CONNECT_RESPONSE_BREAK_OTHERS_A : CONNECT_RESPONSE_BREAK_OTHERS_B ;
return FPinConnectionResponse ( ReplyBreakOutputs , TEXT ( " Replace existing output connections " ) ) ;
}
else if ( bBreakExistingDueToDataInput & & ! bMultipleSelfException )
{
const ECanCreateConnectionResponse ReplyBreakInputs = ( PinA = = InputPin ) ? CONNECT_RESPONSE_BREAK_OTHERS_A : CONNECT_RESPONSE_BREAK_OTHERS_B ;
return FPinConnectionResponse ( ReplyBreakInputs , TEXT ( " Replace existing input connections " ) ) ;
}
else
{
return FPinConnectionResponse ( CONNECT_RESPONSE_MAKE , TEXT ( " " ) ) ;
}
}
const FPinConnectionResponse UEdGraphSchema_K2 : : CanCreateConnection ( const UEdGraphPin * PinA , const UEdGraphPin * PinB ) const
{
2014-04-23 19:46:43 -04:00
const UK2Node * OwningNodeA = Cast < UK2Node > ( PinA - > GetOwningNodeUnchecked ( ) ) ;
const UK2Node * OwningNodeB = Cast < UK2Node > ( PinB - > GetOwningNodeUnchecked ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 19:46:43 -04:00
if ( ! OwningNodeA | | ! OwningNodeB )
{
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , TEXT ( " Invalid nodes " ) ) ;
}
2014-03-14 14:13:41 -04:00
// Make sure the pins are not on the same node
if ( OwningNodeA = = OwningNodeB )
{
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , TEXT ( " Both are on the same node " ) ) ;
}
// node can disallow the connection
{
FString RespondMessage ;
if ( OwningNodeA & & OwningNodeA - > IsConnectionDisallowed ( PinA , PinB , RespondMessage ) )
{
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , RespondMessage ) ;
}
if ( OwningNodeB & & OwningNodeB - > IsConnectionDisallowed ( PinB , PinA , RespondMessage ) )
{
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , RespondMessage ) ;
}
}
// Compare the directions
const UEdGraphPin * InputPin = NULL ;
const UEdGraphPin * OutputPin = NULL ;
if ( ! CategorizePinsByDirection ( PinA , PinB , /*out*/ InputPin , /*out*/ OutputPin ) )
{
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , TEXT ( " Directions are not compatible " ) ) ;
}
bool bIgnoreArray = false ;
if ( const UK2Node * OwningNode = Cast < UK2Node > ( InputPin - > GetOwningNode ( ) ) )
{
const bool bAllowMultipleSelfs = OwningNode - > AllowMultipleSelfs ( true ) ; // it applies also to ForEachCall
const bool bNotAnArrayFunction = ! InputPin - > PinType . bIsArray ;
const bool bSelfPin = IsSelfPin ( * InputPin ) ;
bIgnoreArray = bAllowMultipleSelfs & & bNotAnArrayFunction & & bSelfPin ;
}
2014-04-23 19:46:43 -04:00
// Find the calling context in case one of the pins is of type object and has a value of Self
UClass * CallingContext = NULL ;
const UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNode ( PinA - > GetOwningNodeUnchecked ( ) ) ;
if ( Blueprint )
{
CallingContext = ( Blueprint - > GeneratedClass ! = NULL ) ? Blueprint - > GeneratedClass : Blueprint - > ParentClass ;
}
2014-03-14 14:13:41 -04:00
// Compare the types
const bool bTypesMatch = ArePinsCompatible ( OutputPin , InputPin , CallingContext , bIgnoreArray ) ;
if ( bTypesMatch )
{
return DetermineConnectionResponseOfCompatibleTypedPins ( PinA , PinB , InputPin , OutputPin ) ;
}
else
{
// Autocasting
FName DummyName ;
UK2Node * DummyNode ;
const bool bCanAutocast = SearchForAutocastFunction ( OutputPin , InputPin , /*out*/ DummyName ) ;
const bool bCanAutoConvert = FindSpecializedConversionNode ( OutputPin , InputPin , false , /* out */ DummyNode ) ;
if ( bCanAutocast | | bCanAutoConvert )
{
2014-09-05 13:06:18 -04:00
return FPinConnectionResponse ( CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE , FString : : Printf ( TEXT ( " Convert %s to %s " ) , * TypeToText ( OutputPin - > PinType ) . ToString ( ) , * TypeToText ( InputPin - > PinType ) . ToString ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-04-23 20:18:55 -04:00
if ( OutputPin & & InputPin & & ( PC_Struct = = OutputPin - > PinType . PinCategory ) & & ( PC_Struct = = InputPin - > PinType . PinCategory )
& & ( OutputPin - > PinType . PinSubCategoryObject ! = InputPin - > PinType . PinSubCategoryObject ) )
{
FString Msg ( TEXT ( " Only exactly matching structures are considered compatible. " ) ) ;
auto InStruct = Cast < const UStruct > ( InputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
auto OutStruct = Cast < const UStruct > ( OutputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( InStruct & & OutStruct & & OutStruct - > IsChildOf ( InStruct ) )
{
Msg + = TEXT ( " Derived structures are disallowed. " ) ;
}
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , Msg ) ;
}
2014-09-05 13:06:18 -04:00
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , FString : : Printf ( TEXT ( " %s is not compatible with %s " ) , * TypeToText ( PinA - > PinType ) . ToString ( ) , * TypeToText ( PinB - > PinType ) . ToString ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
bool UEdGraphSchema_K2 : : TryCreateConnection ( UEdGraphPin * PinA , UEdGraphPin * PinB ) const
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( PinA - > GetOwningNode ( ) ) ;
bool bModified = UEdGraphSchema : : TryCreateConnection ( PinA , PinB ) ;
if ( bModified )
{
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
return bModified ;
}
bool UEdGraphSchema_K2 : : SearchForAutocastFunction ( const UEdGraphPin * OutputPin , const UEdGraphPin * InputPin , /*out*/ FName & TargetFunction ) const
{
// NOTE: Under no circumstances should anyone *ever* add a questionable cast to this function.
// If it could be at all confusing why a function is provided, to even a novice user, err on the side of do not cast!!!
// This includes things like string->int (does it do length, atoi, or what?) that would be autocasts in a traditional scripting language
TargetFunction = NAME_None ;
const UScriptStruct * InputStructType = Cast < const UScriptStruct > ( InputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
const UScriptStruct * OutputStructType = Cast < const UScriptStruct > ( OutputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( OutputPin - > PinType . bIsArray ! = InputPin - > PinType . bIsArray )
{
// We don't autoconvert between arrays and non-arrays. Those are handled by specialized conversions
}
else if ( OutputPin - > PinType . PinCategory = = PC_Int )
{
if ( InputPin - > PinType . PinCategory = = PC_Float )
{
TargetFunction = TEXT ( " Conv_IntToFloat " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_IntToString " ) ;
}
else if ( ( InputPin - > PinType . PinCategory = = PC_Byte ) & & ( InputPin - > PinType . PinSubCategoryObject = = NULL ) )
{
TargetFunction = TEXT ( " Conv_IntToByte " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Boolean )
{
TargetFunction = TEXT ( " Conv_IntToBool " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Text )
{
TargetFunction = TEXT ( " Conv_IntToText " ) ;
}
}
else if ( OutputPin - > PinType . PinCategory = = PC_Float )
{
if ( InputPin - > PinType . PinCategory = = PC_Int )
{
TargetFunction = TEXT ( " FFloor " ) ;
}
else if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = VectorStruct ) )
{
TargetFunction = TEXT ( " Conv_FloatToVector " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_FloatToString " ) ;
}
else if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = LinearColorStruct ) )
{
TargetFunction = TEXT ( " Conv_FloatToLinearColor " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Text )
{
TargetFunction = TEXT ( " Conv_FloatToText " ) ;
}
}
else if ( OutputPin - > PinType . PinCategory = = PC_Struct )
{
if ( OutputStructType = = VectorStruct )
{
if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = TransformStruct ) )
{
TargetFunction = TEXT ( " Conv_VectorToTransform " ) ;
}
2014-08-08 20:52:04 -04:00
else if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = LinearColorStruct ) )
2014-03-14 14:13:41 -04:00
{
TargetFunction = TEXT ( " Conv_VectorToLinearColor " ) ;
}
2014-08-08 20:52:04 -04:00
else if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = RotatorStruct ) )
{
TargetFunction = TEXT ( " Conv_VectorToRotator " ) ;
}
2014-03-14 14:13:41 -04:00
else if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_VectorToString " ) ;
}
// NOTE: Did you see the note above about unsafe and unclear casts?
}
else if ( OutputStructType = = RotatorStruct )
{
if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = TransformStruct ) )
{
TargetFunction = TEXT ( " MakeTransform " ) ;
}
2014-08-08 20:52:04 -04:00
else if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = VectorStruct ) )
{
TargetFunction = TEXT ( " Conv_RotatorToVector " ) ;
}
2014-03-14 14:13:41 -04:00
else if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_RotatorToString " ) ;
}
// NOTE: Did you see the note above about unsafe and unclear casts?
}
else if ( OutputStructType = = LinearColorStruct )
{
if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = ColorStruct ) )
{
TargetFunction = TEXT ( " Conv_LinearColorToColor " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_ColorToString " ) ;
}
else if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = VectorStruct ) )
{
TargetFunction = TEXT ( " Conv_LinearColorToVector " ) ;
}
}
else if ( OutputStructType = = ColorStruct )
{
if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = LinearColorStruct ) )
{
TargetFunction = TEXT ( " Conv_ColorToLinearColor " ) ;
}
}
}
else if ( OutputPin - > PinType . PinCategory = = PC_Boolean )
{
if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_BoolToString " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Int )
{
TargetFunction = TEXT ( " Conv_BoolToInt " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Float )
{
TargetFunction = TEXT ( " Conv_BoolToFloat " ) ;
}
else if ( ( InputPin - > PinType . PinCategory = = PC_Byte ) & & ( InputPin - > PinType . PinSubCategoryObject = = NULL ) )
{
TargetFunction = TEXT ( " Conv_BoolToByte " ) ;
}
2014-08-14 16:28:28 -04:00
else if ( InputPin - > PinType . PinCategory = = PC_Text )
{
TargetFunction = TEXT ( " Conv_BoolToText " ) ;
}
2014-03-14 14:13:41 -04:00
}
else if ( OutputPin - > PinType . PinCategory = = PC_Byte & &
( OutputPin - > PinType . PinSubCategoryObject = = NULL | | ! OutputPin - > PinType . PinSubCategoryObject - > IsA ( UEnum : : StaticClass ( ) ) ) )
{
if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_ByteToString " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Int )
{
TargetFunction = TEXT ( " Conv_ByteToInt " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Float )
{
TargetFunction = TEXT ( " Conv_ByteToFloat " ) ;
}
2014-08-14 16:28:28 -04:00
else if ( InputPin - > PinType . PinCategory = = PC_Text )
{
TargetFunction = TEXT ( " Conv_ByteToText " ) ;
}
2014-03-14 14:13:41 -04:00
}
else if ( OutputPin - > PinType . PinCategory = = PC_Name )
{
if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_NameToString " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Text )
{
TargetFunction = TEXT ( " Conv_NameToText " ) ;
}
}
else if ( OutputPin - > PinType . PinCategory = = PC_String )
{
if ( InputPin - > PinType . PinCategory = = PC_Name )
{
TargetFunction = TEXT ( " Conv_StringToName " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Int )
{
TargetFunction = TEXT ( " Conv_StringToInt " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Float )
{
TargetFunction = TEXT ( " Conv_StringToFloat " ) ;
}
else if ( InputPin - > PinType . PinCategory = = PC_Text )
{
TargetFunction = TEXT ( " Conv_StringToText " ) ;
}
else
{
// NOTE: Did you see the note above about unsafe and unclear casts?
}
}
else if ( OutputPin - > PinType . PinCategory = = PC_Text )
{
if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " Conv_TextToString " ) ;
}
}
2014-04-23 17:58:27 -04:00
else if ( ( OutputPin - > PinType . PinCategory = = PC_Interface ) & & ( InputPin - > PinType . PinCategory = = PC_Object ) )
2014-04-02 18:09:23 -04:00
{
UClass const * InputClass = Cast < UClass const > ( InputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
2014-04-23 17:58:27 -04:00
bool const bInputIsUObject = ( ( InputClass ! = NULL ) & & ( InputClass = = UObject : : StaticClass ( ) ) ) ;
if ( bInputIsUObject )
2014-04-02 18:09:23 -04:00
{
TargetFunction = TEXT ( " Conv_InterfaceToObject " ) ;
}
}
2014-03-14 14:13:41 -04:00
return TargetFunction ! = NAME_None ;
}
bool UEdGraphSchema_K2 : : FindSpecializedConversionNode ( const UEdGraphPin * OutputPin , const UEdGraphPin * InputPin , bool bCreateNode , /*out*/ UK2Node * & TargetNode ) const
{
bool bCanConvert = false ;
TargetNode = NULL ;
// Conversion for scalar -> array
if ( ( ! OutputPin - > PinType . bIsArray & & InputPin - > PinType . bIsArray ) & & ArePinTypesCompatible ( OutputPin - > PinType , InputPin - > PinType , NULL , true ) )
{
bCanConvert = true ;
if ( bCreateNode )
{
TargetNode = NewObject < UK2Node_MakeArray > ( ) ;
}
}
// If connecting an object to a 'call function' self pin, and not currently compatible, see if there is a property we can call a function on
2014-04-23 17:58:27 -04:00
else if ( InputPin - > GetOwningNode ( ) - > IsA ( UK2Node_CallFunction : : StaticClass ( ) ) & & IsSelfPin ( * InputPin ) & &
( ( OutputPin - > PinType . PinCategory = = PC_Object ) | | ( OutputPin - > PinType . PinCategory = = PC_Interface ) ) )
2014-03-14 14:13:41 -04:00
{
UK2Node_CallFunction * CallFunctionNode = ( UK2Node_CallFunction * ) ( InputPin - > GetOwningNode ( ) ) ;
UClass * OutputPinClass = Cast < UClass > ( OutputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
UClass * FunctionClass = CallFunctionNode - > FunctionReference . GetMemberParentClass ( CallFunctionNode ) ;
if ( FunctionClass ! = NULL & & OutputPinClass ! = NULL )
{
// Iterate over object properties..
for ( TFieldIterator < UObjectProperty > PropIt ( OutputPinClass , EFieldIteratorFlags : : IncludeSuper ) ; PropIt ; + + PropIt )
{
UObjectProperty * ObjProp = * PropIt ;
// .. if we have a blueprint visible var, and is of the type which contains this function..
if ( ObjProp - > HasAllPropertyFlags ( CPF_BlueprintVisible ) & & ObjProp - > PropertyClass - > IsChildOf ( FunctionClass ) )
{
// say we can convert
bCanConvert = true ;
// Create 'get variable' node
if ( bCreateNode )
{
UK2Node_VariableGet * GetNode = NewObject < UK2Node_VariableGet > ( ) ;
GetNode - > VariableReference . SetFromField < UProperty > ( ObjProp , false ) ;
TargetNode = GetNode ;
}
}
}
}
}
if ( ! bCanConvert )
{
// CHECK ENUM TO NAME CAST
const bool bInoputMatch = InputPin & & ! InputPin - > PinType . bIsArray & & ( ( PC_Name = = InputPin - > PinType . PinCategory ) | | ( PC_String = = InputPin - > PinType . PinCategory ) ) ;
const bool bOutputMatch = OutputPin & & ! OutputPin - > PinType . bIsArray & & ( PC_Byte = = OutputPin - > PinType . PinCategory ) & & ( NULL ! = Cast < UEnum > ( OutputPin - > PinType . PinSubCategoryObject . Get ( ) ) ) ;
if ( bOutputMatch & & bInoputMatch )
{
bCanConvert = true ;
if ( bCreateNode )
{
check ( NULL = = TargetNode ) ;
if ( PC_Name = = InputPin - > PinType . PinCategory )
{
TargetNode = NewObject < UK2Node_GetEnumeratorName > ( ) ;
}
else if ( PC_String = = InputPin - > PinType . PinCategory )
{
TargetNode = NewObject < UK2Node_GetEnumeratorNameAsString > ( ) ;
}
}
}
}
if ( ! bCanConvert & & InputPin & & OutputPin )
{
// CHECK BYTE TO ENUM CAST
UEnum * Enum = Cast < UEnum > ( InputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
const bool bInoputMatch = ! InputPin - > PinType . bIsArray & & ( PC_Byte = = InputPin - > PinType . PinCategory ) & & Enum ;
const bool bOutputMatch = ! OutputPin - > PinType . bIsArray & & ( PC_Byte = = OutputPin - > PinType . PinCategory ) ;
if ( bOutputMatch & & bInoputMatch )
{
bCanConvert = true ;
if ( bCreateNode )
{
auto CastByteToEnum = NewObject < UK2Node_CastByteToEnum > ( ) ;
CastByteToEnum - > Enum = Enum ;
CastByteToEnum - > bSafe = true ;
TargetNode = CastByteToEnum ;
}
}
}
return bCanConvert ;
}
void UEdGraphSchema_K2 : : AutowireConversionNode ( UEdGraphPin * InputPin , UEdGraphPin * OutputPin , UEdGraphNode * ConversionNode ) const
{
bool bAllowInputConnections = true ;
bool bAllowOutputConnections = true ;
for ( int32 PinIndex = 0 ; PinIndex < ConversionNode - > Pins . Num ( ) ; + + PinIndex )
{
UEdGraphPin * TestPin = ConversionNode - > Pins [ PinIndex ] ;
if ( ( TestPin - > Direction = = EGPD_Input ) & & ( ArePinTypesCompatible ( OutputPin - > PinType , TestPin - > PinType ) ) )
{
if ( bAllowOutputConnections & & TryCreateConnection ( TestPin , OutputPin ) )
{
// Successful connection, do not allow more output connections
bAllowOutputConnections = false ;
}
}
else if ( ( TestPin - > Direction = = EGPD_Output ) & & ( ArePinTypesCompatible ( TestPin - > PinType , InputPin - > PinType ) ) )
{
if ( bAllowInputConnections & & TryCreateConnection ( TestPin , InputPin ) )
{
// Successful connection, do not allow more input connections
bAllowInputConnections = false ;
}
}
}
}
bool UEdGraphSchema_K2 : : CreateAutomaticConversionNodeAndConnections ( UEdGraphPin * PinA , UEdGraphPin * PinB ) const
{
// Determine which pin is an input and which pin is an output
UEdGraphPin * InputPin = NULL ;
UEdGraphPin * OutputPin = NULL ;
if ( ! CategorizePinsByDirection ( PinA , PinB , /*out*/ InputPin , /*out*/ OutputPin ) )
{
return false ;
}
FName TargetFunctionName ;
TSubclassOf < UK2Node > ConversionNodeClass ;
UK2Node * TemplateConversionNode = NULL ;
if ( SearchForAutocastFunction ( OutputPin , InputPin , /*out*/ TargetFunctionName ) )
{
// Create a new call function node for the casting operator
UClass * ClassContainingConversionFunction = NULL ; //@TODO: Should probably return this from the search function too
UK2Node_CallFunction * TemplateNode = NewObject < UK2Node_CallFunction > ( ) ;
TemplateNode - > FunctionReference . SetExternalMember ( TargetFunctionName , ClassContainingConversionFunction ) ;
//TemplateNode->bIsBeadFunction = true;
TemplateConversionNode = TemplateNode ;
}
else
{
FindSpecializedConversionNode ( OutputPin , InputPin , true , /*out*/ TemplateConversionNode ) ;
}
if ( TemplateConversionNode ! = NULL )
{
// Determine where to position the new node (assuming it isn't going to get beaded)
FVector2D AverageLocation = CalculateAveragePositionBetweenNodes ( InputPin , OutputPin ) ;
UK2Node * ConversionNode = FEdGraphSchemaAction_K2NewNode : : SpawnNodeFromTemplate < UK2Node > ( InputPin - > GetOwningNode ( ) - > GetGraph ( ) , TemplateConversionNode , AverageLocation ) ;
// Connect the cast node up to the output/input pins
AutowireConversionNode ( InputPin , OutputPin , ConversionNode ) ;
return true ;
}
return false ;
}
FString UEdGraphSchema_K2 : : IsPinDefaultValid ( const UEdGraphPin * Pin , const FString & NewDefaultValue , UObject * NewDefaultObject , const FText & InNewDefaultText ) const
{
const UBlueprint * OwningBP = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( Pin - > GetOwningNode ( ) ) ;
const bool bIsArray = Pin - > PinType . bIsArray ;
const bool bIsReference = Pin - > PinType . bIsReference ;
const bool bIsAutoCreateRefTerm = IsAutoCreateRefTerm ( Pin ) ;
2014-05-29 16:49:22 -04:00
if ( OwningBP - > BlueprintType ! = BPTYPE_Interface )
2014-03-14 14:13:41 -04:00
{
2014-06-16 11:10:42 -04:00
if ( ! bIsAutoCreateRefTerm )
2014-05-29 16:49:22 -04:00
{
2014-06-16 11:10:42 -04:00
if ( bIsArray )
2014-05-29 16:49:22 -04:00
{
return TEXT ( " Literal values are not allowed for array parameters. Use a Make Array node instead " ) ;
}
2014-06-16 11:10:42 -04:00
else if ( bIsReference )
2014-05-29 16:49:22 -04:00
{
return TEXT ( " Literal values are not allowed for pass-by-reference parameters. " ) ;
}
}
2014-03-14 14:13:41 -04:00
}
FString ReturnMsg ;
DefaultValueSimpleValidation ( Pin - > PinType , Pin - > PinName , NewDefaultValue , NewDefaultObject , InNewDefaultText , & ReturnMsg ) ;
return ReturnMsg ;
}
bool UEdGraphSchema_K2 : : DoesSupportPinWatching ( ) const
{
return true ;
}
bool UEdGraphSchema_K2 : : IsPinBeingWatched ( UEdGraphPin const * Pin ) const
{
// Note: If you crash here; it is likely that you forgot to call Blueprint->OnBlueprintChanged.Broadcast(Blueprint) to invalidate the cached UI state
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( Pin - > GetOwningNode ( ) ) ;
return FKismetDebugUtilities : : IsPinBeingWatched ( Blueprint , Pin ) ;
}
void UEdGraphSchema_K2 : : ClearPinWatch ( UEdGraphPin const * Pin ) const
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( Pin - > GetOwningNode ( ) ) ;
FKismetDebugUtilities : : RemovePinWatch ( Blueprint , Pin ) ;
}
bool UEdGraphSchema_K2 : : DefaultValueSimpleValidation ( const FEdGraphPinType & PinType , const FString & PinName , const FString & NewDefaultValue , UObject * NewDefaultObject , const FText & InNewDefaultText , FString * OutMsg /*= NULL*/ ) const
{
# ifdef DVSV_RETURN_MSG
2014-06-16 08:04:54 -04:00
static_assert ( false , " Macro redefinition. " ) ;
2014-03-14 14:13:41 -04:00
# endif
# define DVSV_RETURN_MSG(Str) if(NULL != OutMsg) { *OutMsg = Str; } return false;
const FString & PinCategory = PinType . PinCategory ;
const FString & PinSubCategory = PinType . PinSubCategory ;
const UObject * PinSubCategoryObject = PinType . PinSubCategoryObject . Get ( ) ;
2014-05-22 13:49:30 -04:00
if ( PinType . bIsArray )
{
// arrays are validated separately
}
2014-03-14 14:13:41 -04:00
//@TODO: FCString::Atoi, FCString::Atof, and appStringToBool will 'accept' any input, but we should probably catch and warn
// about invalid input (non numeric for int/byte/float, and non 0/1 or yes/no/true/false for bool)
2014-05-22 13:49:30 -04:00
else if ( PinCategory = = PC_Boolean )
2014-03-14 14:13:41 -04:00
{
// All input is acceptable to some degree
}
else if ( PinCategory = = PC_Byte )
{
const UEnum * EnumPtr = Cast < const UEnum > ( PinSubCategoryObject ) ;
if ( EnumPtr )
{
if ( EnumPtr - > FindEnumIndex ( * NewDefaultValue ) = = INDEX_NONE )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " '%s' is not a valid enumerant of '<%s>' " ) , * NewDefaultValue , * ( EnumPtr - > GetName ( ) ) ) ) ;
}
}
else if ( ! NewDefaultValue . IsEmpty ( ) )
{
int32 Value ;
if ( ! FDefaultValueHelper : : ParseInt ( NewDefaultValue , Value ) )
{
DVSV_RETURN_MSG ( TEXT ( " Expected a valid unsigned number for a byte property " ) ) ;
}
if ( ( Value < 0 ) | | ( Value > 255 ) )
{
DVSV_RETURN_MSG ( TEXT ( " Expected a value between 0 and 255 for a byte property " ) ) ;
}
}
}
else if ( PinCategory = = PC_Class )
{
// Should have an object set but no string
if ( ! NewDefaultValue . IsEmpty ( ) )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " String NewDefaultValue '%s' specified on class pin '%s' " ) , * NewDefaultValue , * ( PinName ) ) ) ;
}
if ( NewDefaultObject = = NULL )
{
// Valid self-reference or empty reference
}
else
{
// Otherwise, we expect to be able to resolve the type at least
const UClass * DefaultClassType = Cast < const UClass > ( NewDefaultObject ) ;
if ( DefaultClassType = = NULL )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " Literal on pin %s is not a class. " ) , * ( PinName ) ) ) ;
}
else
{
// @TODO support PinSubCategory == 'self'
const UClass * PinClassType = Cast < const UClass > ( PinSubCategoryObject ) ;
if ( PinClassType = = NULL )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " Failed to find class for pin %s " ) , * ( PinName ) ) ) ;
}
else
{
// Have both types, make sure the specified type is a valid subtype
if ( ! DefaultClassType - > IsChildOf ( PinClassType ) )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " %s isn't a valid subclass of %s (specified on pin %s) " ) , * NewDefaultObject - > GetPathName ( ) , * PinClassType - > GetName ( ) , * ( PinName ) ) ) ;
}
}
}
}
}
else if ( PinCategory = = PC_Float )
{
if ( ! NewDefaultValue . IsEmpty ( ) )
{
if ( ! FDefaultValueHelper : : IsStringValidFloat ( NewDefaultValue ) )
{
DVSV_RETURN_MSG ( TEXT ( " Expected a valid number for an float property " ) ) ;
}
}
}
else if ( PinCategory = = PC_Int )
{
if ( ! NewDefaultValue . IsEmpty ( ) )
{
if ( ! FDefaultValueHelper : : IsStringValidInteger ( NewDefaultValue ) )
{
DVSV_RETURN_MSG ( TEXT ( " Expected a valid number for an integer property " ) ) ;
}
}
}
else if ( PinCategory = = PC_Name )
{
2014-08-21 23:21:25 -04:00
// Anything is allowed
2014-03-14 14:13:41 -04:00
}
2014-04-23 17:58:27 -04:00
else if ( ( PinCategory = = PC_Object ) | | ( PinCategory = = PC_Interface ) )
2014-03-14 14:13:41 -04:00
{
if ( PinSubCategoryObject = = NULL & & PinSubCategory ! = PSC_Self )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " PinSubCategoryObject on pin '%s' is NULL and PinSubCategory is '%s' not 'self' " ) , * ( PinName ) , * PinSubCategory ) ) ;
}
if ( PinSubCategoryObject ! = NULL & & PinSubCategory ! = TEXT ( " " ) )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " PinSubCategoryObject on pin '%s' is non-NULL but PinSubCategory is '%s', should be empty " ) , * ( PinName ) , * PinSubCategory ) ) ;
}
// Should have an object set but no string - 'self' is not a valid NewDefaultValue for PC_Object pins
if ( ! NewDefaultValue . IsEmpty ( ) )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " String NewDefaultValue '%s' specified on object pin '%s' " ) , * NewDefaultValue , * ( PinName ) ) ) ;
}
// Check that the object that is set is of the correct class
const UClass * ObjectClass = Cast < const UClass > ( PinSubCategoryObject ) ;
if ( NewDefaultObject ! = NULL & & ObjectClass ! = NULL & & ! NewDefaultObject - > IsA ( ObjectClass ) )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " %s isn't a %s (specified on pin %s) " ) , * NewDefaultObject - > GetPathName ( ) , * ObjectClass - > GetName ( ) , * ( PinName ) ) ) ;
}
}
else if ( PinCategory = = PC_String )
{
// All strings are valid
}
else if ( PinCategory = = PC_Text )
{
// Neither of these should ever be true
if ( InNewDefaultText . IsTransient ( ) )
{
DVSV_RETURN_MSG ( TEXT ( " Invalid text literal, text is transient! " ) ) ;
}
2014-06-10 16:45:28 -04:00
}
2014-03-14 14:13:41 -04:00
else if ( PinCategory = = PC_Struct )
{
if ( PinSubCategory ! = TEXT ( " " ) )
{
2014-04-23 20:18:55 -04:00
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " Invalid PinSubCategory value '%s' (it should be empty) " ) , * PinSubCategory ) ) ;
2014-03-14 14:13:41 -04:00
}
// Only FRotator and FVector properties are currently allowed to have a valid default value
const UScriptStruct * StructType = Cast < const UScriptStruct > ( PinSubCategoryObject ) ;
if ( StructType = = NULL )
{
//@TODO: MessageLog.Error(*FString::Printf(TEXT("Failed to find struct named %s (passed thru @@)"), *PinSubCategory), SourceObject);
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " No struct specified for pin '%s' " ) , * ( PinName ) ) ) ;
}
else if ( ! NewDefaultValue . IsEmpty ( ) )
{
if ( StructType = = VectorStruct )
{
if ( ! FDefaultValueHelper : : IsStringValidVector ( NewDefaultValue ) )
{
DVSV_RETURN_MSG ( TEXT ( " Invalid value for an FVector " ) ) ;
}
}
else if ( StructType = = RotatorStruct )
{
FRotator Rot ;
if ( ! FDefaultValueHelper : : IsStringValidRotator ( NewDefaultValue ) )
{
DVSV_RETURN_MSG ( TEXT ( " Invalid value for an FRotator " ) ) ;
}
}
else if ( StructType = = TransformStruct )
{
FTransform Transform ;
if ( ! Transform . InitFromString ( NewDefaultValue ) )
{
DVSV_RETURN_MSG ( TEXT ( " Invalid value for an FTransform " ) ) ;
}
}
else if ( StructType = = LinearColorStruct )
{
FLinearColor Color ;
// Color form: "(R=%f,G=%f,B=%f,A=%f)"
if ( ! Color . InitFromString ( NewDefaultValue ) )
{
DVSV_RETURN_MSG ( TEXT ( " Invalid value for an FLinearColor " ) ) ;
}
}
else
{
// Structs must pass validation at this point, because we need a UStructProperty to run ImportText
// They'll be verified in FKCHandler_CallFunction::CreateFunctionCallStatement()
}
}
}
else if ( PinCategory = = TEXT ( " CommentType " ) )
{
// Anything is allowed
}
else
{
2014-09-05 13:06:18 -04:00
//@TODO: MessageLog.Error(*FString::Printf(TEXT("Unsupported type %s on @@"), *UEdGraphSchema_K2::TypeToText(Type).ToString()), SourceObject);
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " Unsupported type %s on pin %s " ) , * UEdGraphSchema_K2 : : TypeToText ( PinType ) . ToString ( ) , * ( PinName ) ) ) ;
2014-03-14 14:13:41 -04:00
}
# undef DVSV_RETURN_MSG
return true ;
}
FLinearColor UEdGraphSchema_K2 : : GetPinTypeColor ( const FEdGraphPinType & PinType ) const
{
const FString & TypeString = PinType . PinCategory ;
2014-05-20 19:00:53 -04:00
const UGraphEditorSettings * Settings = GetDefault < UGraphEditorSettings > ( ) ;
2014-03-14 14:13:41 -04:00
if ( TypeString = = PC_Exec )
{
2014-05-20 19:00:53 -04:00
return Settings - > ExecutionPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Object )
{
2014-05-20 19:00:53 -04:00
return Settings - > ObjectPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 17:58:27 -04:00
else if ( TypeString = = PC_Interface )
{
2014-05-20 19:00:53 -04:00
return Settings - > InterfacePinTypeColor ;
2014-04-23 17:58:27 -04:00
}
2014-03-14 14:13:41 -04:00
else if ( TypeString = = PC_Float )
{
2014-05-20 19:00:53 -04:00
return Settings - > FloatPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Boolean )
{
2014-05-20 19:00:53 -04:00
return Settings - > BooleanPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Byte )
{
2014-05-20 19:00:53 -04:00
return Settings - > BytePinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Int )
{
2014-05-20 19:00:53 -04:00
return Settings - > IntPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Struct )
{
if ( PinType . PinSubCategoryObject = = VectorStruct )
{
// vector
2014-05-20 19:00:53 -04:00
return Settings - > VectorPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( PinType . PinSubCategoryObject = = RotatorStruct )
{
// rotator
2014-05-20 19:00:53 -04:00
return Settings - > RotatorPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( PinType . PinSubCategoryObject = = TransformStruct )
{
// transform
2014-05-20 19:00:53 -04:00
return Settings - > TransformPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-05-20 19:00:53 -04:00
return Settings - > StructPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
}
else if ( TypeString = = PC_String )
{
2014-05-20 19:00:53 -04:00
return Settings - > StringPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Text )
{
2014-05-20 19:00:53 -04:00
return Settings - > TextPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Wildcard )
{
if ( PinType . PinSubCategory = = PSC_Index )
{
2014-05-20 19:00:53 -04:00
return Settings - > IndexPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-05-20 19:00:53 -04:00
return Settings - > WildcardPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
}
else if ( TypeString = = PC_Name )
{
2014-05-20 19:00:53 -04:00
return Settings - > NamePinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Delegate )
{
2014-05-20 19:00:53 -04:00
return Settings - > DelegatePinTypeColor ;
2014-03-14 14:13:41 -04:00
}
else if ( TypeString = = PC_Class )
{
2014-05-20 19:00:53 -04:00
return Settings - > ClassPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
// Type does not have a defined color!
2014-05-20 19:00:53 -04:00
return Settings - > DefaultPinTypeColor ;
2014-03-14 14:13:41 -04:00
}
FString UEdGraphSchema_K2 : : GetPinDisplayName ( const UEdGraphPin * Pin ) const
{
FString DisplayName ;
if ( Pin ! = NULL )
{
UEdGraphNode * Node = Pin - > GetOwningNode ( ) ;
if ( Node - > ShouldOverridePinNames ( ) )
{
DisplayName = Node - > GetPinNameOverride ( * Pin ) ;
}
else
{
DisplayName = Super : : GetPinDisplayName ( Pin ) ;
// bit of a hack to hide 'execute' and 'then' pin names
if ( ( Pin - > PinType . PinCategory = = PC_Exec ) & &
( ( DisplayName = = PN_Execute ) | | ( DisplayName = = PN_Then ) ) )
{
DisplayName = FString ( TEXT ( " " ) ) ;
}
}
if ( GEditor & & GetDefault < UEditorStyleSettings > ( ) - > bShowFriendlyNames )
{
2014-04-23 17:36:48 -04:00
DisplayName = FName : : NameToDisplayString ( DisplayName , Pin - > PinType . PinCategory = = PC_Boolean ) ;
2014-03-14 14:13:41 -04:00
}
}
return DisplayName ;
}
2014-09-05 13:06:18 -04:00
void UEdGraphSchema_K2 : : ConstructBasicPinTooltip ( const UEdGraphPin & Pin , const FText & PinDescription , FString & TooltipOut ) const
2014-03-14 14:13:41 -04:00
{
2014-09-05 17:51:04 -04:00
if ( bGeneratingDocumentation )
2014-03-14 14:13:41 -04:00
{
2014-09-05 17:51:04 -04:00
TooltipOut = PinDescription . ToString ( ) ;
}
else
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " PinType " ) , TypeToText ( Pin . PinType ) ) ;
if ( UEdGraphNode * PinNode = Pin . GetOwningNode ( ) )
2014-03-14 14:13:41 -04:00
{
2014-09-05 17:51:04 -04:00
UEdGraphSchema_K2 const * const K2Schema = Cast < const UEdGraphSchema_K2 > ( PinNode - > GetSchema ( ) ) ;
if ( ensure ( K2Schema ! = NULL ) ) // ensure that this node belongs to this schema
{
Args . Add ( TEXT ( " DisplayName " ) , FText : : FromString ( GetPinDisplayName ( & Pin ) ) ) ;
Args . Add ( TEXT ( " LineFeed1 " ) , FText : : FromString ( TEXT ( " \n " ) ) ) ;
}
}
else
{
Args . Add ( TEXT ( " DisplayName " ) , FText : : GetEmpty ( ) ) ;
Args . Add ( TEXT ( " LineFeed1 " ) , FText : : GetEmpty ( ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-05 13:06:18 -04:00
2014-03-14 14:13:41 -04:00
2014-09-05 17:51:04 -04:00
if ( ! PinDescription . IsEmpty ( ) )
{
Args . Add ( TEXT ( " Description " ) , PinDescription ) ;
Args . Add ( TEXT ( " LineFeed2 " ) , FText : : FromString ( TEXT ( " \n \n " ) ) ) ;
}
else
{
Args . Add ( TEXT ( " Description " ) , FText : : GetEmpty ( ) ) ;
Args . Add ( TEXT ( " LineFeed2 " ) , FText : : GetEmpty ( ) ) ;
}
2014-09-05 13:06:18 -04:00
2014-09-05 17:51:04 -04:00
TooltipOut = FText : : Format ( LOCTEXT ( " PinTooltip " , " {DisplayName}{LineFeed1}{PinType}{LineFeed2}{Description} " ) , Args ) . ToString ( ) ;
}
2014-03-14 14:13:41 -04:00
}
EGraphType UEdGraphSchema_K2 : : GetGraphType ( const UEdGraph * TestEdGraph ) const
{
if ( TestEdGraph )
{
//@TODO: Should there be a GT_Subgraph type?
UEdGraph * GraphToTest = const_cast < UEdGraph * > ( TestEdGraph ) ;
for ( UObject * TestOuter = GraphToTest ; TestOuter ; TestOuter = TestOuter - > GetOuter ( ) )
{
// reached up to the blueprint for the graph
if ( UBlueprint * Blueprint = Cast < UBlueprint > ( TestOuter ) )
{
if ( Blueprint - > BlueprintType = = BPTYPE_MacroLibrary | |
Blueprint - > MacroGraphs . Contains ( GraphToTest ) )
{
return GT_Macro ;
}
else if ( Blueprint - > UbergraphPages . Contains ( GraphToTest ) )
{
return GT_Ubergraph ;
}
else if ( Blueprint - > FunctionGraphs . Contains ( GraphToTest ) )
{
return GT_Function ;
}
}
else
{
GraphToTest = Cast < UEdGraph > ( TestOuter ) ;
}
}
}
return Super : : GetGraphType ( TestEdGraph ) ;
}
bool UEdGraphSchema_K2 : : IsTitleBarPin ( const UEdGraphPin & Pin ) const
{
return IsExecPin ( Pin ) ;
}
void UEdGraphSchema_K2 : : CreateMacroGraphTerminators ( UEdGraph & Graph , UClass * Class ) const
{
const FName GraphName = Graph . GetFName ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( & Graph ) ;
// Create the entry/exit tunnels
{
FGraphNodeCreator < UK2Node_Tunnel > EntryNodeCreator ( Graph ) ;
UK2Node_Tunnel * EntryNode = EntryNodeCreator . CreateNode ( ) ;
EntryNode - > bCanHaveOutputs = true ;
EntryNodeCreator . Finalize ( ) ;
2014-09-12 18:37:04 -04:00
SetNodeMetaData ( EntryNode , FNodeMetadata : : DefaultGraphNode ) ;
2014-03-14 14:13:41 -04:00
}
{
FGraphNodeCreator < UK2Node_Tunnel > ExitNodeCreator ( Graph ) ;
UK2Node_Tunnel * ExitNode = ExitNodeCreator . CreateNode ( ) ;
ExitNode - > bCanHaveInputs = true ;
ExitNode - > NodePosX = 240 ;
ExitNodeCreator . Finalize ( ) ;
2014-09-12 18:37:04 -04:00
SetNodeMetaData ( ExitNode , FNodeMetadata : : DefaultGraphNode ) ;
2014-03-14 14:13:41 -04:00
}
}
void UEdGraphSchema_K2 : : CreateFunctionGraphTerminators ( UEdGraph & Graph , UClass * Class ) const
{
const FName GraphName = Graph . GetFName ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( & Graph ) ;
check ( Blueprint - > BlueprintType ! = BPTYPE_MacroLibrary ) ;
// Create a function entry node
FGraphNodeCreator < UK2Node_FunctionEntry > FunctionEntryCreator ( Graph ) ;
UK2Node_FunctionEntry * EntryNode = FunctionEntryCreator . CreateNode ( ) ;
EntryNode - > SignatureClass = Class ;
EntryNode - > SignatureName = GraphName ;
FunctionEntryCreator . Finalize ( ) ;
2014-09-12 18:37:04 -04:00
SetNodeMetaData ( EntryNode , FNodeMetadata : : DefaultGraphNode ) ;
2014-03-14 14:13:41 -04:00
// See if we need to implement a return node
UFunction * InterfaceToImplement = FindField < UFunction > ( Class , GraphName ) ;
if ( InterfaceToImplement )
{
// See if any function params are marked as out
bool bHasOutParam = false ;
for ( TFieldIterator < UProperty > It ( InterfaceToImplement ) ; It & & ( It - > PropertyFlags & CPF_Parm ) ; + + It )
{
if ( It - > PropertyFlags & CPF_OutParm )
{
bHasOutParam = true ;
break ;
}
}
if ( bHasOutParam )
{
FGraphNodeCreator < UK2Node_FunctionResult > NodeCreator ( Graph ) ;
UK2Node_FunctionResult * ReturnNode = NodeCreator . CreateNode ( ) ;
ReturnNode - > SignatureClass = Class ;
ReturnNode - > SignatureName = GraphName ;
ReturnNode - > NodePosX = EntryNode - > NodePosX + EntryNode - > NodeWidth + 256 ;
ReturnNode - > NodePosY = EntryNode - > NodePosY ;
NodeCreator . Finalize ( ) ;
2014-09-12 18:37:04 -04:00
SetNodeMetaData ( ReturnNode , FNodeMetadata : : DefaultGraphNode ) ;
2014-03-14 14:13:41 -04:00
// Auto-connect the pins for entry and exit, so that by default the signature is properly generated
UEdGraphPin * EntryNodeExec = FindExecutionPin ( * EntryNode , EGPD_Output ) ;
UEdGraphPin * ResultNodeExec = FindExecutionPin ( * ReturnNode , EGPD_Input ) ;
EntryNodeExec - > MakeLinkTo ( ResultNodeExec ) ;
}
}
}
2014-05-08 15:03:09 -04:00
void UEdGraphSchema_K2 : : CreateFunctionGraphTerminators ( UEdGraph & Graph , UFunction * FunctionSignature ) const
{
const FName GraphName = Graph . GetFName ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( & Graph ) ;
check ( Blueprint - > BlueprintType ! = BPTYPE_MacroLibrary ) ;
// Create a function entry node
FGraphNodeCreator < UK2Node_FunctionEntry > FunctionEntryCreator ( Graph ) ;
UK2Node_FunctionEntry * EntryNode = FunctionEntryCreator . CreateNode ( ) ;
EntryNode - > SignatureClass = NULL ;
EntryNode - > SignatureName = GraphName ;
FunctionEntryCreator . Finalize ( ) ;
2014-09-12 18:37:04 -04:00
SetNodeMetaData ( EntryNode , FNodeMetadata : : DefaultGraphNode ) ;
2014-05-08 15:03:09 -04:00
2014-05-09 16:33:22 -04:00
// We don't have a signature class to base this on permanently, because it's not an override function.
// so we need to define the pins as user defined so that they are serialized.
EntryNode - > CreateUserDefinedPinsForFunctionEntryExit ( FunctionSignature , /*bIsFunctionEntry=*/ true ) ;
2014-05-08 15:03:09 -04:00
// See if any function params are marked as out
bool bHasOutParam = false ;
for ( TFieldIterator < UProperty > It ( FunctionSignature ) ; It & & ( It - > PropertyFlags & CPF_Parm ) ; + + It )
{
if ( It - > PropertyFlags & CPF_OutParm )
{
bHasOutParam = true ;
break ;
}
}
if ( bHasOutParam )
{
FGraphNodeCreator < UK2Node_FunctionResult > NodeCreator ( Graph ) ;
UK2Node_FunctionResult * ReturnNode = NodeCreator . CreateNode ( ) ;
ReturnNode - > SignatureClass = NULL ;
ReturnNode - > SignatureName = GraphName ;
ReturnNode - > NodePosX = EntryNode - > NodePosX + EntryNode - > NodeWidth + 256 ;
ReturnNode - > NodePosY = EntryNode - > NodePosY ;
NodeCreator . Finalize ( ) ;
2014-09-12 18:37:04 -04:00
SetNodeMetaData ( ReturnNode , FNodeMetadata : : DefaultGraphNode ) ;
2014-05-08 15:03:09 -04:00
2014-05-09 16:33:22 -04:00
ReturnNode - > CreateUserDefinedPinsForFunctionEntryExit ( FunctionSignature , /*bIsFunctionEntry=*/ false ) ;
2014-05-08 15:03:09 -04:00
// Auto-connect the pins for entry and exit, so that by default the signature is properly generated
UEdGraphPin * EntryNodeExec = FindExecutionPin ( * EntryNode , EGPD_Output ) ;
UEdGraphPin * ResultNodeExec = FindExecutionPin ( * ReturnNode , EGPD_Input ) ;
EntryNodeExec - > MakeLinkTo ( ResultNodeExec ) ;
}
}
2014-03-14 14:13:41 -04:00
bool UEdGraphSchema_K2 : : ConvertPropertyToPinType ( const UProperty * Property , /*out*/ FEdGraphPinType & TypeOut ) const
{
if ( Property = = NULL )
{
TypeOut . PinCategory = TEXT ( " bad_type " ) ;
return false ;
}
TypeOut . PinSubCategory = TEXT ( " " ) ;
// Handle whether or not this is an array property
const UArrayProperty * ArrayProperty = Cast < const UArrayProperty > ( Property ) ;
const UProperty * TestProperty = ArrayProperty ? ArrayProperty - > Inner : Property ;
TypeOut . bIsArray = ( ArrayProperty ! = NULL ) ;
TypeOut . bIsReference = Property - > HasAllPropertyFlags ( CPF_OutParm | CPF_ReferenceParm ) ;
TypeOut . bIsConst = Property - > HasAllPropertyFlags ( CPF_ConstParm ) ;
// Check to see if this is the wildcard property for the target array type
UFunction * Function = Cast < UFunction > ( Property - > GetOuter ( ) ) ;
2014-04-23 20:18:55 -04:00
if ( UK2Node_CallArrayFunction : : IsWildcardProperty ( Function , Property )
| | UK2Node_CallFunction : : IsStructureWildcardProperty ( Function , Property - > GetName ( ) ) )
2014-03-14 14:13:41 -04:00
{
TypeOut . PinCategory = PC_Wildcard ;
}
else if ( const UInterfaceProperty * InterfaceProperty = Cast < const UInterfaceProperty > ( TestProperty ) )
{
2014-04-23 17:58:27 -04:00
TypeOut . PinCategory = PC_Interface ;
2014-03-14 14:13:41 -04:00
TypeOut . PinSubCategoryObject = InterfaceProperty - > InterfaceClass ;
}
else if ( const UClassProperty * ClassProperty = Cast < const UClassProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Class ;
TypeOut . PinSubCategoryObject = ClassProperty - > MetaClass ;
}
else if ( const UAssetClassProperty * AssetClassProperty = Cast < const UAssetClassProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Class ;
TypeOut . PinSubCategoryObject = AssetClassProperty - > MetaClass ;
}
else if ( const UObjectPropertyBase * ObjectProperty = Cast < const UObjectPropertyBase > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Object ;
TypeOut . PinSubCategoryObject = ObjectProperty - > PropertyClass ;
TypeOut . bIsWeakPointer = TestProperty - > IsA ( UWeakObjectProperty : : StaticClass ( ) ) ;
}
else if ( const UStructProperty * StructProperty = Cast < const UStructProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Struct ;
TypeOut . PinSubCategoryObject = StructProperty - > Struct ;
}
else if ( Cast < const UFloatProperty > ( TestProperty ) ! = NULL )
{
TypeOut . PinCategory = PC_Float ;
}
else if ( Cast < const UIntProperty > ( TestProperty ) ! = NULL )
{
TypeOut . PinCategory = PC_Int ;
}
else if ( const UByteProperty * ByteProperty = Cast < const UByteProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Byte ;
TypeOut . PinSubCategoryObject = ByteProperty - > Enum ;
}
else if ( Cast < const UNameProperty > ( TestProperty ) ! = NULL )
{
TypeOut . PinCategory = PC_Name ;
}
else if ( Cast < const UBoolProperty > ( TestProperty ) ! = NULL )
{
TypeOut . PinCategory = PC_Boolean ;
}
else if ( Cast < const UStrProperty > ( TestProperty ) ! = NULL )
{
TypeOut . PinCategory = PC_String ;
}
else if ( Cast < const UTextProperty > ( TestProperty ) ! = NULL )
{
TypeOut . PinCategory = PC_Text ;
}
else if ( const UMulticastDelegateProperty * MulticastDelegateProperty = Cast < const UMulticastDelegateProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_MCDelegate ;
2014-04-23 20:18:55 -04:00
FMemberReference : : FillSimpleMemberReference < UFunction > ( MulticastDelegateProperty - > SignatureFunction , TypeOut . PinSubCategoryMemberReference ) ;
2014-03-14 14:13:41 -04:00
}
else if ( const UDelegateProperty * DelegateProperty = Cast < const UDelegateProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Delegate ;
2014-04-23 20:18:55 -04:00
FMemberReference : : FillSimpleMemberReference < UFunction > ( DelegateProperty - > SignatureFunction , TypeOut . PinSubCategoryMemberReference ) ;
2014-03-14 14:13:41 -04:00
}
else
{
TypeOut . PinCategory = TEXT ( " bad_type " ) ;
return false ;
}
return true ;
}
FString UEdGraphSchema_K2 : : TypeToString ( const FEdGraphPinType & Type )
{
2014-04-23 18:30:37 -04:00
return TypeToText ( Type ) . ToString ( ) ;
2014-03-14 14:13:41 -04:00
}
FString UEdGraphSchema_K2 : : TypeToString ( UProperty * const Property )
2014-09-05 13:06:18 -04:00
{
return TypeToText ( Property ) . ToString ( ) ;
}
FText UEdGraphSchema_K2 : : TypeToText ( UProperty * const Property )
2014-03-14 14:13:41 -04:00
{
if ( UStructProperty * Struct = Cast < UStructProperty > ( Property ) )
{
2014-04-23 19:41:03 -04:00
if ( Struct - > Struct )
{
2014-09-05 13:06:18 -04:00
FEdGraphPinType PinType ;
PinType . PinCategory = PC_Struct ;
PinType . PinSubCategoryObject = Struct - > Struct ;
return TypeToText ( PinType ) ;
}
2014-03-14 14:13:41 -04:00
}
else if ( UClassProperty * Class = Cast < UClassProperty > ( Property ) )
2014-07-08 18:23:43 -04:00
{
2014-09-05 13:06:18 -04:00
if ( Class - > MetaClass )
2014-07-08 18:23:43 -04:00
{
2014-09-05 13:06:18 -04:00
FEdGraphPinType PinType ;
PinType . PinCategory = PC_Class ;
PinType . PinSubCategoryObject = Class - > MetaClass ;
return TypeToText ( PinType ) ;
}
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
else if ( UInterfaceProperty * Interface = Cast < UInterfaceProperty > ( Property ) )
{
2014-04-23 19:41:03 -04:00
if ( Interface - > InterfaceClass ! = nullptr )
2014-07-08 18:23:43 -04:00
{
2014-09-05 13:06:18 -04:00
FEdGraphPinType PinType ;
PinType . PinCategory = PC_Interface ;
PinType . PinSubCategoryObject = Interface - > InterfaceClass ;
return TypeToText ( PinType ) ;
}
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
else if ( UObjectPropertyBase * Obj = Cast < UObjectPropertyBase > ( Property ) )
{
if ( Obj - > PropertyClass )
{
2014-09-05 13:06:18 -04:00
FEdGraphPinType PinType ;
PinType . PinCategory = PC_Object ;
PinType . PinSubCategoryObject = Obj - > PropertyClass ;
PinType . bIsWeakPointer = Property - > IsA ( UWeakObjectProperty : : StaticClass ( ) ) ;
return TypeToText ( PinType ) ;
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
2014-09-05 13:06:18 -04:00
return FText : : GetEmpty ( ) ;
2014-03-14 14:13:41 -04:00
}
else if ( UArrayProperty * Array = Cast < UArrayProperty > ( Property ) )
{
2014-04-23 19:41:03 -04:00
if ( Array - > Inner )
2014-07-08 18:23:43 -04:00
{
2014-09-05 13:06:18 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ArrayType " ) , TypeToText ( Array - > Inner ) ) ;
return FText : : Format ( LOCTEXT ( " ArrayPropertyText " , " Array of {ArrayType} " ) , Args ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-07-08 18:23:43 -04:00
2014-09-05 13:06:18 -04:00
return FText : : FromString ( Property - > GetClass ( ) - > GetName ( ) ) ;
}
FText UEdGraphSchema_K2 : : GetCategoryText ( const FString & Category , const bool bForMenu )
{
2014-09-09 16:50:33 -04:00
if ( Category . IsEmpty ( ) )
{
return FText : : GetEmpty ( ) ;
}
2014-09-05 13:06:18 -04:00
static TMap < FString , FText > CategoryDescriptions ;
if ( CategoryDescriptions . Num ( ) = = 0 )
{
CategoryDescriptions . Add ( PC_Exec , LOCTEXT ( " Exec " , " Exec " ) ) ;
CategoryDescriptions . Add ( PC_Boolean , LOCTEXT ( " BoolCategory " , " Boolean " ) ) ;
CategoryDescriptions . Add ( PC_Byte , LOCTEXT ( " ByteCategory " , " Byte " ) ) ;
CategoryDescriptions . Add ( PC_Class , LOCTEXT ( " ClassCategory " , " Class " ) ) ;
CategoryDescriptions . Add ( PC_Int , LOCTEXT ( " IntCategory " , " Integer " ) ) ;
CategoryDescriptions . Add ( PC_Float , LOCTEXT ( " FloatCategory " , " Float " ) ) ;
CategoryDescriptions . Add ( PC_Name , LOCTEXT ( " NameCategory " , " Name " ) ) ;
CategoryDescriptions . Add ( PC_Delegate , LOCTEXT ( " DelegateCategory " , " Delegate " ) ) ;
CategoryDescriptions . Add ( PC_MCDelegate , LOCTEXT ( " MulticastDelegateCategory " , " Multicast Delegate " ) ) ;
CategoryDescriptions . Add ( PC_Object , LOCTEXT ( " ObjectCategory " , " Reference " ) ) ;
CategoryDescriptions . Add ( PC_Interface , LOCTEXT ( " InterfaceCategory " , " Interface " ) ) ;
CategoryDescriptions . Add ( PC_String , LOCTEXT ( " StringCategory " , " String " ) ) ;
CategoryDescriptions . Add ( PC_Text , LOCTEXT ( " TextCategory " , " Text " ) ) ;
CategoryDescriptions . Add ( PC_Struct , LOCTEXT ( " StructCategory " , " Structure " ) ) ;
CategoryDescriptions . Add ( PC_Wildcard , LOCTEXT ( " WildcardCategory " , " Wildcard " ) ) ;
}
if ( bForMenu )
{
if ( Category = = PC_Object )
{
return LOCTEXT ( " ObjectCategoryForMenu " , " Object Reference " ) ;
}
}
2014-09-17 12:56:36 -04:00
if ( FText const * TypeDesc = CategoryDescriptions . Find ( Category ) )
{
return * TypeDesc ;
}
else
{
ensureMsgf ( false , TEXT ( " Unhandled blueprint type ('%s'), failed to find type description. " ) , * Category ) ;
return FText : : FromString ( Category ) ;
}
2014-06-16 11:10:42 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 18:30:37 -04:00
FText UEdGraphSchema_K2 : : TypeToText ( const FEdGraphPinType & Type )
{
FText PropertyText ;
if ( Type . PinSubCategoryObject ! = NULL )
2014-09-05 13:06:18 -04:00
{
2014-04-23 18:30:37 -04:00
const UEdGraphSchema_K2 * Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
if ( Type . PinCategory = = Schema - > PC_Byte )
2014-07-08 18:23:43 -04:00
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " EnumName " ) , FText : : FromString ( Type . PinSubCategoryObject - > GetName ( ) ) ) ;
2014-09-05 13:06:18 -04:00
PropertyText = FText : : Format ( LOCTEXT ( " EnumAsText " , " {EnumName} Enum " ) , Args ) ;
2014-07-08 18:23:43 -04:00
}
2014-04-23 18:30:37 -04:00
else
{
2014-10-09 12:04:45 -04:00
UObject * SubCategoryObj = Type . PinSubCategoryObject . Get ( ) ;
FString SubCategoryObjName = SubCategoryObj - > GetName ( ) ;
if ( UField * SubCategoryField = Cast < UField > ( SubCategoryObj ) )
{
SubCategoryObjName = SubCategoryField - > GetDisplayNameText ( ) . ToString ( ) ;
}
2014-04-23 18:30:37 -04:00
if ( ! Type . bIsWeakPointer )
2014-07-08 18:23:43 -04:00
{
2014-04-23 18:30:37 -04:00
UClass * PSCOAsClass = Cast < UClass > ( Type . PinSubCategoryObject . Get ( ) ) ;
const bool bIsInterface = PSCOAsClass & & PSCOAsClass - > HasAnyClassFlags ( CLASS_Interface ) ;
FFormatNamedArguments Args ;
2014-09-05 13:06:18 -04:00
// Don't display the category for "well-known" struct types
if ( Type . PinCategory = = PC_Struct & & ( Type . PinSubCategoryObject = = VectorStruct | | Type . PinSubCategoryObject = = RotatorStruct | | Type . PinSubCategoryObject = = TransformStruct ) )
{
Args . Add ( TEXT ( " Category " ) , FText : : GetEmpty ( ) ) ;
}
else
{
Args . Add ( TEXT ( " Category " ) , ( ! bIsInterface ? GetCategoryText ( Type . PinCategory ) : GetCategoryText ( PC_Interface ) ) ) ;
}
2014-10-09 12:04:45 -04:00
Args . Add ( TEXT ( " ObjectName " ) , FText : : FromString ( FName : : NameToDisplayString ( SubCategoryObjName , /*bIsBool =*/ false ) ) ) ;
2014-09-05 13:06:18 -04:00
PropertyText = FText : : Format ( LOCTEXT ( " ObjectAsText " , " {ObjectName} {Category} " ) , Args ) ;
2014-07-08 18:23:43 -04:00
}
2014-04-23 18:30:37 -04:00
else
2014-07-08 18:23:43 -04:00
{
2014-04-23 18:30:37 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " Category " ) , FText : : FromString ( Type . PinCategory ) ) ;
2014-10-09 12:04:45 -04:00
Args . Add ( TEXT ( " ObjectName " ) , FText : : FromString ( SubCategoryObjName ) ) ;
2014-09-05 13:06:18 -04:00
PropertyText = FText : : Format ( LOCTEXT ( " WeakPtrAsText " , " {ObjectName} Weak {Category} " ) , Args ) ;
2014-04-23 18:30:37 -04:00
}
}
}
else if ( Type . PinSubCategory ! = TEXT ( " " ) )
{
FFormatNamedArguments Args ;
2014-09-05 13:06:18 -04:00
Args . Add ( TEXT ( " Category " ) , GetCategoryText ( Type . PinCategory ) ) ;
Args . Add ( TEXT ( " ObjectName " ) , FText : : FromString ( FName : : NameToDisplayString ( Type . PinSubCategory , false ) ) ) ;
PropertyText = FText : : Format ( LOCTEXT ( " ObjectAsText " , " {ObjectName} {Category} " ) , Args ) ;
2014-07-08 18:23:43 -04:00
}
else
{
2014-09-05 13:06:18 -04:00
PropertyText = GetCategoryText ( Type . PinCategory ) ;
2014-07-08 18:23:43 -04:00
}
2014-04-23 18:30:37 -04:00
if ( Type . bIsArray )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " PropertyTitle " ) , PropertyText ) ;
2014-10-09 12:04:45 -04:00
PropertyText = FText : : Format ( LOCTEXT ( " ArrayAsText " , " Array of {PropertyTitle}s " ) , Args ) ;
2014-04-23 18:30:37 -04:00
}
else if ( Type . bIsReference )
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " PropertyTitle " ) , PropertyText ) ;
PropertyText = FText : : Format ( LOCTEXT ( " PropertyByRef " , " {PropertyTitle} (by ref) " ) , Args ) ;
}
return PropertyText ;
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : GetVariableTypeTree ( TArray < TSharedPtr < FPinTypeTreeInfo > > & TypeTree , bool bAllowExec , bool bAllowWildCard ) const
{
// Clear the list
TypeTree . Empty ( ) ;
if ( bAllowExec )
{
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Exec , true ) , PC_Exec , this , LOCTEXT ( " ExecType " , " Execution pin " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Boolean , true ) , PC_Boolean , this , LOCTEXT ( " BooleanType " , " True or false value " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Byte , true ) , PC_Byte , this , LOCTEXT ( " ByteType " , " 8 bit number " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Int , true ) , PC_Int , this , LOCTEXT ( " IntegerType " , " Integer number " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Float , true ) , PC_Float , this , LOCTEXT ( " FloatType " , " Floating point number " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Name , true ) , PC_Name , this , LOCTEXT ( " NameType " , " A text name " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_String , true ) , PC_String , this , LOCTEXT ( " StringType " , " A text string " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Text , true ) , PC_Text , this , LOCTEXT ( " TextType " , " A localizable text string " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
// Add in special first-class struct types
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( PC_Struct , VectorStruct , LOCTEXT ( " VectorType " , " A 3D vector " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( PC_Struct , RotatorStruct , LOCTEXT ( " RotatorType " , " A 3D rotation " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( PC_Struct , TransformStruct , LOCTEXT ( " TransformType " , " A 3D transformation, including translation, rotation and 3D scale. " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
// Add wildcard type
if ( bAllowWildCard )
{
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Wildcard , true ) , PC_Wildcard , this , LOCTEXT ( " WildcardType " , " Wildcard type (unspecified). " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
}
// Add the types that have subtrees
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Struct , true ) , PC_Struct , this , LOCTEXT ( " StructType " , " Struct (value) types. " ) , true ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Object , true ) , PC_Object , this , LOCTEXT ( " ObjectType " , " Object pointer. " ) , true ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Interface , true ) , PC_Interface , this , LOCTEXT ( " InterfaceType " , " Interface pointer. " ) , true ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Class , true ) , PC_Class , this , LOCTEXT ( " ClassType " , " Class pointers. " ) , true ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( LOCTEXT ( " EnumCategory " , " Enum " ) , TEXT ( " Enum " ) , this , LOCTEXT ( " EnumType " , " Enumeration types. " ) , true ) ) ) ;
2014-03-14 14:13:41 -04:00
}
void UEdGraphSchema_K2 : : GetVariableIndexTypeTree ( TArray < TSharedPtr < FPinTypeTreeInfo > > & TypeTree , bool bAllowExec , bool bAllowWildcard ) const
{
// Clear the list
TypeTree . Empty ( ) ;
if ( bAllowExec )
{
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Exec , true ) , PC_Exec , this , LOCTEXT ( " ExecIndexType " , " Execution pin " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Boolean , true ) , PC_Boolean , this , LOCTEXT ( " BooleanIndexType " , " True or false value " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Byte , true ) , PC_Byte , this , LOCTEXT ( " ByteIndexType " , " 8 bit number " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Int , true ) , PC_Int , this , LOCTEXT ( " IntegerIndexType " , " Integer number " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
// Add wildcard type
if ( bAllowWildcard )
{
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Wildcard , true ) , PC_Wildcard , this , LOCTEXT ( " WildcardIndexType " , " Wildcard type (unspecified). " ) ) ) ) ;
2014-03-14 14:13:41 -04:00
}
// Add the types that have subtrees
2014-09-08 12:56:34 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( LOCTEXT ( " EnumCategory " , " Enum " ) , TEXT ( " Enum " ) , this , LOCTEXT ( " EnumIndexType " , " Enumeration types. " ) , true ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-08 12:56:34 -04:00
bool UEdGraphSchema_K2 : : DoesTypeHaveSubtypes ( const FString & Category ) const
2014-03-14 14:13:41 -04:00
{
2014-09-08 12:56:34 -04:00
return ( Category = = PC_Struct ) | | ( Category = = PC_Object ) | | ( Category = = PC_Interface ) | | ( Category = = PC_Class ) | | ( Category = = TEXT ( " Enum " ) ) ;
2014-03-14 14:13:41 -04:00
}
void UEdGraphSchema_K2 : : GetVariableSubtypes ( const FString & Type , TArray < UObject * > & SubtypesList ) const
{
SubtypesList . Empty ( ) ;
if ( Type = = PC_Struct )
{
// Find script structs marked with "BlueprintType=true" in their metadata, and add to the list
for ( TObjectIterator < UScriptStruct > StructIt ; StructIt ; + + StructIt )
{
UScriptStruct * ScriptStruct = * StructIt ;
if ( UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( ScriptStruct ) )
{
SubtypesList . Add ( ScriptStruct ) ;
}
}
}
2014-04-23 17:58:27 -04:00
else if ( Type = = PC_Class )
2014-03-14 14:13:41 -04:00
{
// Generate a list of all potential objects which have "BlueprintType=true" in their metadata
for ( TObjectIterator < UClass > ClassIt ; ClassIt ; + + ClassIt )
{
UClass * CurrentClass = * ClassIt ;
2014-07-09 10:32:27 -04:00
if ( UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( CurrentClass ) & & ! CurrentClass - > HasAnyClassFlags ( CLASS_Deprecated ) )
2014-03-14 14:13:41 -04:00
{
SubtypesList . Add ( CurrentClass ) ;
}
}
}
2014-04-23 17:58:27 -04:00
else if ( Type = = PC_Object )
{
// Generate a list of all potential objects which have "BlueprintType=true" in their metadata (that aren't interfaces)
for ( TObjectIterator < UClass > ClassIt ; ClassIt ; + + ClassIt )
{
UClass * CurrentClass = * ClassIt ;
2014-07-09 10:32:27 -04:00
if ( ! CurrentClass - > IsChildOf ( UInterface : : StaticClass ( ) ) & & UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( CurrentClass ) & & ! CurrentClass - > HasAnyClassFlags ( CLASS_Deprecated ) )
2014-04-23 17:58:27 -04:00
{
SubtypesList . Add ( CurrentClass ) ;
}
}
}
else if ( Type = = PC_Interface )
{
// Generate a list of all potential objects which have "BlueprintType=true" in their metadata (only ones that are interfaces)
for ( TObjectIterator < UClass > ClassIt ; ClassIt ; + + ClassIt )
{
UClass * CurrentClass = * ClassIt ;
if ( CurrentClass - > IsChildOf ( UInterface : : StaticClass ( ) ) & & UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( CurrentClass ) )
{
SubtypesList . Add ( CurrentClass ) ;
}
}
}
2014-03-14 14:13:41 -04:00
else if ( Type = = TEXT ( " Enum " ) )
{
// Generate a list of all potential enums which have "BlueprintType=true" in their metadata
for ( TObjectIterator < UEnum > EnumIt ; EnumIt ; + + EnumIt )
{
UEnum * CurrentEnum = * EnumIt ;
if ( UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( CurrentEnum ) )
{
SubtypesList . Add ( CurrentEnum ) ;
}
}
}
SubtypesList . Sort ( ) ;
}
2014-09-02 11:46:07 -04:00
struct FWildcardArrayPinHelper
{
static bool CheckArrayCompatibility ( const UEdGraphPin * OutputPin , const UEdGraphPin * InputPin , bool bIgnoreArray )
{
if ( bIgnoreArray )
{
return true ;
}
const UK2Node * OwningNode = InputPin ? Cast < UK2Node > ( InputPin - > GetOwningNode ( ) ) : NULL ;
2014-09-02 12:26:15 -04:00
const bool bInputWildcardPinAcceptsArray = ! OwningNode | | OwningNode - > DoesInputWildcardPinAcceptArray ( InputPin ) ;
2014-09-02 11:46:07 -04:00
if ( bInputWildcardPinAcceptsArray )
{
return true ;
}
const bool bCheckInputPin = ( InputPin - > PinType . PinCategory = = GetDefault < UEdGraphSchema_K2 > ( ) - > PC_Wildcard ) & & ! InputPin - > PinType . bIsArray ;
const bool bArrayOutputPin = OutputPin & & OutputPin - > PinType . bIsArray ;
return ! ( bCheckInputPin & & bArrayOutputPin ) ;
}
} ;
2014-03-14 14:13:41 -04:00
bool UEdGraphSchema_K2 : : ArePinsCompatible ( const UEdGraphPin * PinA , const UEdGraphPin * PinB , const UClass * CallingContext , bool bIgnoreArray /*= false*/ ) const
{
if ( ( PinA - > Direction = = EGPD_Input ) & & ( PinB - > Direction = = EGPD_Output ) )
{
2014-09-02 11:46:07 -04:00
return FWildcardArrayPinHelper : : CheckArrayCompatibility ( PinB , PinA , bIgnoreArray )
& & ArePinTypesCompatible ( PinB - > PinType , PinA - > PinType , CallingContext , bIgnoreArray ) ;
2014-03-14 14:13:41 -04:00
}
else if ( ( PinB - > Direction = = EGPD_Input ) & & ( PinA - > Direction = = EGPD_Output ) )
{
2014-09-02 11:46:07 -04:00
return FWildcardArrayPinHelper : : CheckArrayCompatibility ( PinA , PinB , bIgnoreArray )
& & ArePinTypesCompatible ( PinA - > PinType , PinB - > PinType , CallingContext , bIgnoreArray ) ;
2014-03-14 14:13:41 -04:00
}
else
{
return false ;
}
}
bool UEdGraphSchema_K2 : : ArePinTypesCompatible ( const FEdGraphPinType & Output , const FEdGraphPinType & Input , const UClass * CallingContext , bool bIgnoreArray /*= false*/ ) const
{
if ( ! bIgnoreArray & & ( Output . bIsArray ! = Input . bIsArray ) & & ( Input . PinCategory ! = PC_Wildcard | | Input . bIsArray ) )
{
return false ;
}
else if ( Output . PinCategory = = Input . PinCategory )
{
if ( ( Output . PinSubCategory = = Input . PinSubCategory ) & & ( Output . PinSubCategoryObject = = Input . PinSubCategoryObject ) )
{
return true ;
}
2014-04-23 17:58:27 -04:00
else if ( Output . PinCategory = = PC_Interface )
{
UClass const * OutputClass = Cast < UClass const > ( Output . PinSubCategoryObject . Get ( ) ) ;
check ( OutputClass & & OutputClass - > IsChildOf ( UInterface : : StaticClass ( ) ) ) ;
UClass const * InputClass = Cast < UClass const > ( Input . PinSubCategoryObject . Get ( ) ) ;
check ( InputClass & & InputClass - > IsChildOf ( UInterface : : StaticClass ( ) ) ) ;
return OutputClass - > IsChildOf ( InputClass ) ;
}
2014-03-14 14:13:41 -04:00
else if ( ( Output . PinCategory = = PC_Object ) | | ( Output . PinCategory = = PC_Struct ) | | ( Output . PinCategory = = PC_Class ) )
{
// Subcategory mismatch, but the two could be castable
// Only allow a match if the input is a superclass of the output
2014-04-23 17:58:27 -04:00
UStruct const * OutputObject = ( Output . PinSubCategory = = PSC_Self ) ? CallingContext : Cast < UStruct > ( Output . PinSubCategoryObject . Get ( ) ) ;
UStruct const * InputObject = ( Input . PinSubCategory = = PSC_Self ) ? CallingContext : Cast < UStruct > ( Input . PinSubCategoryObject . Get ( ) ) ;
2014-03-14 14:13:41 -04:00
if ( ( OutputObject ! = NULL ) & & ( InputObject ! = NULL ) )
{
2014-04-23 20:18:55 -04:00
if ( Output . PinCategory = = PC_Struct )
{
2014-05-13 04:48:45 -04:00
return OutputObject - > IsChildOf ( InputObject ) & & FStructUtils : : TheSameLayout ( OutputObject , InputObject ) ;
2014-04-23 20:18:55 -04:00
}
2014-03-14 14:13:41 -04:00
// Special Case: Cannot mix interface and non-interface calls, because the pointer size is different under the hood
const bool bInputIsInterface = InputObject - > IsChildOf ( UInterface : : StaticClass ( ) ) ;
const bool bOutputIsInterface = OutputObject - > IsChildOf ( UInterface : : StaticClass ( ) ) ;
if ( bInputIsInterface ! = bOutputIsInterface )
{
UClass const * OutputClass = Cast < const UClass > ( OutputObject ) ;
UClass const * InputClass = Cast < const UClass > ( InputObject ) ;
if ( bInputIsInterface & & ( OutputClass ! = NULL ) )
{
return OutputClass - > ImplementsInterface ( InputClass ) ;
}
else if ( bOutputIsInterface & & ( InputClass ! = NULL ) )
{
return InputClass - > ImplementsInterface ( OutputClass ) ;
}
}
return OutputObject - > IsChildOf ( InputObject ) & & ( bInputIsInterface = = bOutputIsInterface ) ;
}
}
else if ( ( Output . PinCategory = = PC_Byte ) & & ( Output . PinSubCategory = = Input . PinSubCategory ) )
{
// NOTE: This allows enums to be converted to bytes. Long-term we don't want to allow that, but we need it
// for now until we have == for enums in order to be able to compare them.
if ( Input . PinSubCategoryObject = = NULL )
{
return true ;
}
}
else if ( PC_Delegate = = Output . PinCategory | | PC_MCDelegate = = Output . PinCategory )
{
2014-05-22 14:14:52 -04:00
const UFunction * OutFunction = FMemberReference : : ResolveSimpleMemberReference < UFunction > ( Output . PinSubCategoryMemberReference ) ;
const UFunction * InFunction = FMemberReference : : ResolveSimpleMemberReference < UFunction > ( Input . PinSubCategoryMemberReference ) ;
return ! OutFunction | | ! InFunction | | OutFunction - > IsSignatureCompatibleWith ( InFunction ) ;
2014-03-14 14:13:41 -04:00
}
}
else if ( Output . PinCategory = = PC_Wildcard | | Input . PinCategory = = PC_Wildcard )
{
// If this is an Index Wildcard we have to check compatibility for indexing types
if ( Output . PinSubCategory = = PSC_Index )
{
return IsIndexWildcardCompatible ( Input ) ;
}
else if ( Input . PinSubCategory = = PSC_Index )
{
return IsIndexWildcardCompatible ( Output ) ;
}
return true ;
}
2014-04-23 17:58:27 -04:00
else if ( ( Output . PinCategory = = PC_Interface ) & & ( Input . PinCategory = = PC_Object ) )
{
UClass const * InterfaceClass = Cast < UClass const > ( Output . PinSubCategoryObject . Get ( ) ) ;
UClass const * InputClass = Cast < UClass const > ( Input . PinSubCategoryObject . Get ( ) ) ;
2014-05-29 17:33:04 -04:00
2014-06-04 17:11:48 -04:00
if ( ( InputClass = = nullptr ) & & ( Input . PinSubCategory = = PSC_Self ) )
2014-05-29 17:33:04 -04:00
{
InputClass = CallingContext ;
}
2014-08-13 08:37:46 -04:00
return InputClass & & ( InputClass - > ImplementsInterface ( InterfaceClass ) | | InterfaceClass - > IsChildOf ( InputClass ) ) ;
2014-04-23 17:58:27 -04:00
}
else if ( ( Output . PinCategory = = PC_Object ) & & ( Input . PinCategory = = PC_Interface ) )
{
UClass const * OutputClass = Cast < UClass const > ( Output . PinSubCategoryObject . Get ( ) ) ;
UClass const * InterfaceClass = Cast < UClass const > ( Input . PinSubCategoryObject . Get ( ) ) ;
2014-05-29 17:33:04 -04:00
2014-06-04 17:11:48 -04:00
if ( ( OutputClass = = nullptr ) & & ( Output . PinSubCategory = = PSC_Self ) )
2014-05-29 17:33:04 -04:00
{
OutputClass = CallingContext ;
}
2014-08-18 13:34:41 -04:00
return OutputClass & & OutputClass - > ImplementsInterface ( InterfaceClass ) | | OutputClass - > IsChildOf ( InterfaceClass ) ;
2014-04-23 17:58:27 -04:00
}
2014-03-14 14:13:41 -04:00
2014-04-23 18:14:04 -04:00
// Pins representing BLueprint objects and subclass of UObject can match when EditoronlyBP.bAllowClassAndBlueprintPinMatching=true (BaseEngine.ini)
2014-04-23 16:39:43 -04:00
// It's required for converting all UBlueprint references into UClass.
struct FObjClassAndBlueprintHelper
{
private :
bool bAllow ;
public :
FObjClassAndBlueprintHelper ( ) : bAllow ( false )
{
2014-04-23 18:14:04 -04:00
GConfig - > GetBool ( TEXT ( " EditoronlyBP " ) , TEXT ( " bAllowClassAndBlueprintPinMatching " ) , bAllow , GEditorIni ) ;
2014-04-23 16:39:43 -04:00
}
bool Match ( const FEdGraphPinType & A , const FEdGraphPinType & B , const UEdGraphSchema_K2 & Schema ) const
{
if ( bAllow & & ( B . PinCategory = = Schema . PC_Object ) & & ( A . PinCategory = = Schema . PC_Class ) )
{
const bool bAIsObjectClass = ( UObject : : StaticClass ( ) = = A . PinSubCategoryObject . Get ( ) ) ;
const UClass * BClass = Cast < UClass > ( B . PinSubCategoryObject . Get ( ) ) ;
const bool bBIsBlueprintObj = BClass & & BClass - > IsChildOf ( UBlueprint : : StaticClass ( ) ) ;
return bAIsObjectClass & & bBIsBlueprintObj ;
}
return false ;
}
} ;
static FObjClassAndBlueprintHelper MatchHelper ;
if ( MatchHelper . Match ( Input , Output , * this ) | | MatchHelper . Match ( Output , Input , * this ) )
{
return true ;
}
2014-03-14 14:13:41 -04:00
return false ;
}
void UEdGraphSchema_K2 : : BreakNodeLinks ( UEdGraphNode & TargetNode ) const
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( & TargetNode ) ;
Super : : BreakNodeLinks ( TargetNode ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
void UEdGraphSchema_K2 : : BreakPinLinks ( UEdGraphPin & TargetPin , bool bSendsNodeNotifcation ) const
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " GraphEd_BreakPinLinks " , " Break Pin Links " ) ) ;
// cache this here, as BreakPinLinks can trigger a node reconstruction invalidating the TargetPin referenceS
UBlueprint * const Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( TargetPin . GetOwningNode ( ) ) ;
Super : : BreakPinLinks ( TargetPin , bSendsNodeNotifcation ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
void UEdGraphSchema_K2 : : BreakSinglePinLink ( UEdGraphPin * SourcePin , UEdGraphPin * TargetPin )
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " GraphEd_BreakSinglePinLink " , " Break Pin Link " ) ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( TargetPin - > GetOwningNode ( ) ) ;
Super : : BreakSinglePinLink ( SourcePin , TargetPin ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
void UEdGraphSchema_K2 : : ReconstructNode ( UEdGraphNode & TargetNode , bool bIsBatchRequest /*=false*/ ) const
{
2014-07-31 09:53:50 -04:00
{
TArray < UObject * > NodeChildren ;
GetObjectsWithOuter ( & TargetNode , NodeChildren , false ) ;
for ( int32 Iter = 0 ; Iter < NodeChildren . Num ( ) ; + + Iter )
{
UEdGraphPin * Pin = Cast < UEdGraphPin > ( NodeChildren [ Iter ] ) ;
const bool bIsValidPin = ! Pin
| | ( Pin - > HasAllFlags ( RF_PendingKill ) & & ! Pin - > LinkedTo . Num ( ) )
| | TargetNode . Pins . Contains ( Pin ) ;
if ( ! bIsValidPin )
{
UE_LOG ( LogBlueprint , Error ,
TEXT ( " Broken Node: %s keeps removed/invalid pin: %s. Try refresh all nodes. " ) ,
* TargetNode . GetFullName ( ) , * Pin - > GetFullName ( ) ) ;
}
}
}
2014-03-14 14:13:41 -04:00
Super : : ReconstructNode ( TargetNode , bIsBatchRequest ) ;
// If the reconstruction is being handled by something doing a batch (i.e. the blueprint autoregenerating itself), defer marking the blueprint as modified to prevent multiple recompiles
if ( ! bIsBatchRequest )
{
const UK2Node * K2Node = Cast < UK2Node > ( & TargetNode ) ;
if ( K2Node & & K2Node - > NodeCausesStructuralBlueprintChange ( ) )
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( & TargetNode ) ;
FBlueprintEditorUtils : : MarkBlueprintAsStructurallyModified ( Blueprint ) ;
}
}
}
bool UEdGraphSchema_K2 : : CanEncapuslateNode ( UEdGraphNode const & TestNode ) const
{
// Can't encapsulate entry points (may relax this restriction in the future, but it makes sense for now)
return ! TestNode . IsA ( UK2Node_FunctionTerminator : : StaticClass ( ) ) & &
2014-07-08 18:23:43 -04:00
TestNode . GetClass ( ) ! = UK2Node_Tunnel : : StaticClass ( ) ; //Tunnel nodes getting sucked into collapsed graphs fails badly, want to allow derived types though(composite node/Macroinstances)
2014-03-14 14:13:41 -04:00
}
void UEdGraphSchema_K2 : : HandleGraphBeingDeleted ( UEdGraph & GraphBeingRemoved ) const
{
if ( UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( & GraphBeingRemoved ) )
{
// Look for collapsed graph nodes that reference this graph
TArray < UK2Node_Composite * > CompositeNodes ;
FBlueprintEditorUtils : : GetAllNodesOfClass < UK2Node_Composite > ( Blueprint , /*out*/ CompositeNodes ) ;
TSet < UK2Node_Composite * > NodesToDelete ;
for ( int32 i = 0 ; i < CompositeNodes . Num ( ) ; + + i )
{
UK2Node_Composite * CompositeNode = CompositeNodes [ i ] ;
if ( CompositeNode - > BoundGraph = = & GraphBeingRemoved )
{
NodesToDelete . Add ( CompositeNode ) ;
}
}
// Delete the node that owns us
ensure ( NodesToDelete . Num ( ) < = 1 ) ;
for ( TSet < UK2Node_Composite * > : : TIterator It ( NodesToDelete ) ; It ; + + It )
{
UK2Node_Composite * NodeToDelete = * It ;
// Prevent re-entrancy here
NodeToDelete - > BoundGraph = NULL ;
NodeToDelete - > Modify ( ) ;
NodeToDelete - > DestroyNode ( ) ;
}
}
}
void UEdGraphSchema_K2 : : TrySetDefaultValue ( UEdGraphPin & Pin , const FString & NewDefaultValue ) const
{
FString UseDefaultValue ;
UObject * UseDefaultObject = NULL ;
FText UseDefaultText ;
2014-04-23 17:58:27 -04:00
if ( ( Pin . PinType . PinCategory = = PC_Object ) | | ( Pin . PinType . PinCategory = = PC_Class ) | | ( Pin . PinType . PinCategory = = PC_Interface ) )
2014-03-14 14:13:41 -04:00
{
UseDefaultObject = FindObject < UObject > ( ANY_PACKAGE , * NewDefaultValue ) ;
UseDefaultValue = NULL ;
}
else
{
UseDefaultObject = NULL ;
UseDefaultValue = NewDefaultValue ;
}
// Check the default value and make it an error if it's bogus
if ( IsPinDefaultValid ( & Pin , UseDefaultValue , UseDefaultObject , UseDefaultText ) = = TEXT ( " " ) )
{
Pin . DefaultObject = UseDefaultObject ;
Pin . DefaultValue = UseDefaultValue ;
Pin . DefaultTextValue = UseDefaultText ;
}
UEdGraphNode * Node = Pin . GetOwningNode ( ) ;
check ( Node ) ;
Node - > PinDefaultValueChanged ( & Pin ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( Node ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
void UEdGraphSchema_K2 : : TrySetDefaultObject ( UEdGraphPin & Pin , UObject * NewDefaultObject ) const
{
FText UseDefaultText ;
// Check the default value and make it an error if it's bogus
if ( IsPinDefaultValid ( & Pin , FString ( TEXT ( " " ) ) , NewDefaultObject , UseDefaultText ) = = TEXT ( " " ) )
{
Pin . DefaultObject = NewDefaultObject ;
Pin . DefaultValue = NULL ;
Pin . DefaultTextValue = UseDefaultText ;
}
UEdGraphNode * Node = Pin . GetOwningNode ( ) ;
check ( Node ) ;
Node - > PinDefaultValueChanged ( & Pin ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( Node ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
void UEdGraphSchema_K2 : : TrySetDefaultText ( UEdGraphPin & InPin , const FText & InNewDefaultText ) const
{
// No reason to set the FText if it is not a PC_Text.
if ( InPin . PinType . PinCategory = = PC_Text )
{
// Check the default value and make it an error if it's bogus
if ( IsPinDefaultValid ( & InPin , TEXT ( " " ) , NULL , InNewDefaultText ) = = TEXT ( " " ) )
{
InPin . DefaultObject = NULL ;
InPin . DefaultValue = NULL ;
if ( InNewDefaultText . IsEmpty ( ) )
{
InPin . DefaultTextValue = InNewDefaultText ;
}
else
{
2014-07-07 20:00:22 -04:00
if ( InNewDefaultText . IsCultureInvariant ( ) )
{
InPin . DefaultTextValue = InNewDefaultText ;
}
else
{
2014-03-14 14:13:41 -04:00
InPin . DefaultTextValue = FText : : ChangeKey ( TEXT ( " " ) , InPin . GetOwningNode ( ) - > NodeGuid . ToString ( ) + TEXT ( " _ " ) + InPin . PinName + FString : : FromInt ( InPin . GetOwningNode ( ) - > Pins . Find ( & InPin ) ) , InNewDefaultText ) ;
}
}
2014-07-07 20:00:22 -04:00
}
2014-03-14 14:13:41 -04:00
UEdGraphNode * Node = InPin . GetOwningNode ( ) ;
check ( Node ) ;
Node - > PinDefaultValueChanged ( & InPin ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNodeChecked ( Node ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
}
bool UEdGraphSchema_K2 : : IsAutoCreateRefTerm ( const UEdGraphPin * Pin ) const
{
check ( Pin ! = NULL ) ;
bool bIsAutoCreateRefTerm = false ;
UEdGraphNode * OwningNode = Pin - > GetOwningNode ( ) ;
UK2Node_CallFunction * FuncNode = Cast < UK2Node_CallFunction > ( OwningNode ) ;
if ( FuncNode )
{
UFunction * TargetFunction = FuncNode - > GetTargetFunction ( ) ;
2014-09-09 12:16:13 -04:00
if ( TargetFunction & & ! Pin - > PinName . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
2014-09-09 12:16:13 -04:00
bIsAutoCreateRefTerm = ( Pin - > PinName = = TargetFunction - > GetMetaData ( FBlueprintMetadata : : MD_AutoCreateRefTerm ) ) ;
2014-03-14 14:13:41 -04:00
}
}
return bIsAutoCreateRefTerm ;
}
bool UEdGraphSchema_K2 : : ShouldHidePinDefaultValue ( UEdGraphPin * Pin ) const
{
check ( Pin ! = NULL ) ;
2014-07-16 14:55:10 -04:00
if ( Pin - > bDefaultValueIsIgnored | | Pin - > PinType . bIsArray | | ( Pin - > PinName = = PN_Self & & Pin - > LinkedTo . Num ( ) > 0 ) | | ( Pin - > PinType . PinCategory = = PC_Exec ) | | ( Pin - > PinType . bIsReference & & ! IsAutoCreateRefTerm ( Pin ) ) )
2014-03-14 14:13:41 -04:00
{
return true ;
}
return false ;
}
2014-06-16 17:47:38 -04:00
bool UEdGraphSchema_K2 : : ShouldShowAssetPickerForPin ( UEdGraphPin * Pin ) const
{
bool bShow = true ;
if ( Pin - > PinType . PinCategory = = PC_Object )
{
UClass * ObjectClass = Cast < UClass > ( Pin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( ObjectClass )
{
// Don't show literal buttons for component type objects
bShow = ! ObjectClass - > IsChildOf ( UActorComponent : : StaticClass ( ) ) ;
2014-09-10 16:39:25 -04:00
if ( bShow )
{
if ( UK2Node_CallFunction * CallFunctionNode = Cast < UK2Node_CallFunction > ( Pin - > GetOwningNode ( ) ) )
{
2014-09-16 19:17:35 -04:00
if ( UFunction * FunctionRef = CallFunctionNode - > GetTargetFunction ( ) )
{
const UEdGraphPin * WorldContextPin = CallFunctionNode - > FindPin ( FunctionRef - > GetMetaData ( FBlueprintMetadata : : MD_WorldContext ) ) ;
bShow = ( WorldContextPin ! = Pin ) ;
}
2014-09-10 16:39:25 -04:00
}
}
2014-06-16 17:47:38 -04:00
}
}
return bShow ;
}
2014-06-16 11:10:42 -04:00
void UEdGraphSchema_K2 : : SetPinDefaultValue ( UEdGraphPin * Pin , const UFunction * Function , const UProperty * Param ) const
{
if ( Function & & Param )
{
const FString MetadataDefaultValue = Function - > GetMetaData ( * Param - > GetName ( ) ) ;
if ( ! MetadataDefaultValue . IsEmpty ( ) )
{
// Specified default value in the metadata
Pin - > DefaultValue = Pin - > AutogeneratedDefaultValue = MetadataDefaultValue ;
}
else
{
const FName MetadataCppDefaultValueKey ( * ( FString ( TEXT ( " CPP_Default_ " ) ) + Param - > GetName ( ) ) ) ;
const FString MetadataCppDefaultValue = Function - > GetMetaData ( MetadataCppDefaultValueKey ) ;
if ( ! MetadataCppDefaultValue . IsEmpty ( ) )
{
Pin - > DefaultValue = Pin - > AutogeneratedDefaultValue = MetadataCppDefaultValue ;
}
}
}
if ( Pin - > DefaultValue . Len ( ) = = 0 )
{
// Set the default value to (T)0
SetPinDefaultValueBasedOnType ( Pin ) ;
}
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : SetPinDefaultValueBasedOnType ( UEdGraphPin * Pin ) const
{
// Create a useful default value based on the pin type
if ( Pin - > PinType . bIsArray )
{
Pin - > AutogeneratedDefaultValue = TEXT ( " " ) ;
}
else if ( Pin - > PinType . PinCategory = = PC_Int )
{
Pin - > AutogeneratedDefaultValue = TEXT ( " 0 " ) ;
}
else if ( Pin - > PinType . PinCategory = = PC_Byte )
{
UEnum * EnumPtr = Cast < UEnum > ( Pin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( EnumPtr )
{
// First element of enum can change. If the enum is { A, B, C } and the default value is A,
// the defult value should not change when enum will be changed into { N, A, B, C }
Pin - > AutogeneratedDefaultValue = TEXT ( " " ) ;
Pin - > DefaultValue = EnumPtr - > GetEnumName ( 0 ) ;
return ;
}
else
{
Pin - > AutogeneratedDefaultValue = TEXT ( " 0 " ) ;
}
}
else if ( Pin - > PinType . PinCategory = = PC_Float )
{
Pin - > AutogeneratedDefaultValue = TEXT ( " 0.0 " ) ;
}
else if ( Pin - > PinType . PinCategory = = PC_Boolean )
{
Pin - > AutogeneratedDefaultValue = TEXT ( " false " ) ;
}
else if ( Pin - > PinType . PinCategory = = PC_Name )
{
Pin - > AutogeneratedDefaultValue = TEXT ( " None " ) ;
}
else if ( ( Pin - > PinType . PinCategory = = PC_Struct ) & & ( ( Pin - > PinType . PinSubCategoryObject = = VectorStruct ) | | ( Pin - > PinType . PinSubCategoryObject = = RotatorStruct ) ) )
{
Pin - > AutogeneratedDefaultValue = TEXT ( " 0, 0, 0 " ) ;
}
else
{
Pin - > AutogeneratedDefaultValue = TEXT ( " " ) ;
}
Pin - > DefaultValue = Pin - > AutogeneratedDefaultValue ;
}
void UEdGraphSchema_K2 : : ValidateExistingConnections ( UEdGraphPin * Pin )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
// Break any newly invalid links
TArray < UEdGraphPin * > BrokenLinks ;
for ( int32 Index = 0 ; Index < Pin - > LinkedTo . Num ( ) ; )
{
UEdGraphPin * OtherPin = Pin - > LinkedTo [ Index ] ;
if ( K2Schema - > ArePinsCompatible ( Pin , OtherPin ) )
{
+ + Index ;
}
else
{
OtherPin - > LinkedTo . Remove ( Pin ) ;
Pin - > LinkedTo . RemoveAtSwap ( Index ) ;
BrokenLinks . Add ( OtherPin ) ;
}
}
// Cascade the check for changed pin types
for ( TArray < UEdGraphPin * > : : TIterator PinIt ( BrokenLinks ) ; PinIt ; + + PinIt )
{
UEdGraphPin * OtherPin = * PinIt ;
OtherPin - > GetOwningNode ( ) - > PinConnectionListChanged ( OtherPin ) ;
}
}
UFunction * UEdGraphSchema_K2 : : FindSetVariableByNameFunction ( const FEdGraphPinType & PinType )
{
2014-04-23 20:18:55 -04:00
//!!!! Keep this function synced with FExposeOnSpawnValidator::IsSupported !!!!
struct FIsCustomStructureParamHelper
{
static bool Is ( const UObject * Obj )
{
static const FName BlueprintTypeName ( TEXT ( " BlueprintType " ) ) ;
const auto Struct = Cast < const UScriptStruct > ( Obj ) ;
return Struct ? Struct - > GetBoolMetaData ( BlueprintTypeName ) : false ;
}
} ;
2014-03-14 14:13:41 -04:00
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
FName SetFunctionName = NAME_None ;
if ( PinType . PinCategory = = K2Schema - > PC_Int )
{
static FName SetIntName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetIntPropertyByName ) ) ;
SetFunctionName = SetIntName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Byte )
{
static FName SetByteName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetBytePropertyByName ) ) ;
SetFunctionName = SetByteName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Float )
{
static FName SetFloatName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetFloatPropertyByName ) ) ;
SetFunctionName = SetFloatName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Boolean )
{
static FName SetBoolName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetBoolPropertyByName ) ) ;
SetFunctionName = SetBoolName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Object )
{
static FName SetObjectName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetObjectPropertyByName ) ) ;
SetFunctionName = SetObjectName ;
}
2014-08-12 11:00:03 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_Class )
{
static FName SetObjectName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetClassPropertyByName ) ) ;
SetFunctionName = SetObjectName ;
}
2014-04-23 17:58:27 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_Interface )
{
static FName SetObjectName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetObjectPropertyByName ) ) ;
SetFunctionName = SetObjectName ;
}
2014-03-14 14:13:41 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_String )
{
static FName SetStringName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetStringPropertyByName ) ) ;
SetFunctionName = SetStringName ;
}
2014-10-02 14:23:34 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_Text )
{
static FName SetTextName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetTextPropertyByName ) ) ;
SetFunctionName = SetTextName ;
}
2014-03-14 14:13:41 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_Name )
{
static FName SetNameName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetNamePropertyByName ) ) ;
SetFunctionName = SetNameName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Struct & & PinType . PinSubCategoryObject = = VectorStruct )
{
static FName SetVectorName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetVectorPropertyByName ) ) ;
SetFunctionName = SetVectorName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Struct & & PinType . PinSubCategoryObject = = RotatorStruct )
{
static FName SetRotatorName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetRotatorPropertyByName ) ) ;
SetFunctionName = SetRotatorName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Struct & & PinType . PinSubCategoryObject = = ColorStruct )
{
static FName SetLinearColorName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetLinearColorPropertyByName ) ) ;
SetFunctionName = SetLinearColorName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_Struct & & PinType . PinSubCategoryObject = = TransformStruct )
{
static FName SetTransformName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetTransformPropertyByName ) ) ;
SetFunctionName = SetTransformName ;
}
2014-04-23 20:18:55 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_Struct & & FIsCustomStructureParamHelper : : Is ( PinType . PinSubCategoryObject . Get ( ) ) )
{
static FName SetStructureName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetStructurePropertyByName ) ) ;
SetFunctionName = SetStructureName ;
}
2014-03-14 14:13:41 -04:00
UFunction * Function = NULL ;
if ( SetFunctionName ! = NAME_None )
{
if ( PinType . bIsArray )
{
static FName SetArrayName ( GET_FUNCTION_NAME_CHECKED ( UKismetArrayLibrary , SetArrayPropertyByName ) ) ;
Function = FindField < UFunction > ( UKismetArrayLibrary : : StaticClass ( ) , SetArrayName ) ;
}
else
{
Function = FindField < UFunction > ( UKismetSystemLibrary : : StaticClass ( ) , SetFunctionName ) ;
}
}
return Function ;
}
bool UEdGraphSchema_K2 : : CanPromotePinToVariable ( const UEdGraphPin & Pin ) const
{
const FEdGraphPinType & PinType = Pin . PinType ;
bool bCanPromote = ( PinType . PinCategory ! = PC_Wildcard & & PinType . PinCategory ! = PC_Exec ) ? true : false ;
const UK2Node * Node = Cast < UK2Node > ( Pin . GetOwningNode ( ) ) ;
const UBlueprint * OwningBlueprint = Node - > GetBlueprint ( ) ;
2014-06-24 10:11:09 -04:00
if ( ! OwningBlueprint | | ( OwningBlueprint - > BlueprintType = = BPTYPE_MacroLibrary ) | | ( OwningBlueprint - > BlueprintType = = BPTYPE_FunctionLibrary ) )
2014-03-14 14:13:41 -04:00
{
// Never allow promotion in macros, because there's not a scope to define them in
bCanPromote = false ;
}
else
{
if ( PinType . PinCategory = = PC_Delegate )
{
bCanPromote = false ;
}
2014-04-23 17:58:27 -04:00
else if ( ( PinType . PinCategory = = PC_Object ) | | ( PinType . PinCategory = = PC_Interface ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 17:58:27 -04:00
if ( PinType . PinSubCategoryObject ! = NULL )
2014-03-14 14:13:41 -04:00
{
2014-07-08 18:23:43 -04:00
if ( UClass * Class = Cast < UClass > ( PinType . PinSubCategoryObject . Get ( ) ) )
{
bCanPromote = UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( Class ) ;
}
}
2014-03-14 14:13:41 -04:00
}
2014-04-02 18:09:23 -04:00
else if ( ( PinType . PinCategory = = PC_Struct ) & & ( PinType . PinSubCategoryObject ! = NULL ) )
{
if ( UScriptStruct * Struct = Cast < UScriptStruct > ( PinType . PinSubCategoryObject . Get ( ) ) )
{
bCanPromote = UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( Struct ) ;
}
}
2014-03-14 14:13:41 -04:00
}
return bCanPromote ;
}
2014-06-16 11:10:42 -04:00
bool UEdGraphSchema_K2 : : CanSplitStructPin ( const UEdGraphPin & Pin ) const
{
2014-07-11 17:44:43 -04:00
return ( Pin . LinkedTo . Num ( ) = = 0 & & PinHasSplittableStructType ( & Pin ) & & Pin . GetOwningNode ( ) - > AllowSplitPins ( ) ) ;
2014-06-16 11:10:42 -04:00
}
bool UEdGraphSchema_K2 : : CanRecombineStructPin ( const UEdGraphPin & Pin ) const
{
bool bCanRecombine = ( Pin . ParentPin ! = NULL & & Pin . LinkedTo . Num ( ) = = 0 ) ;
if ( bCanRecombine )
{
// Go through all the other subpins and ensure they also are not connected to anything
TArray < UEdGraphPin * > PinsToExamine = Pin . ParentPin - > SubPins ;
int32 PinIndex = 0 ;
while ( bCanRecombine & & PinIndex < PinsToExamine . Num ( ) )
{
UEdGraphPin * SubPin = PinsToExamine [ PinIndex ] ;
if ( SubPin - > LinkedTo . Num ( ) > 0 )
{
bCanRecombine = false ;
}
else if ( SubPin - > SubPins . Num ( ) > 0 )
{
PinsToExamine . Append ( SubPin - > SubPins ) ;
}
+ + PinIndex ;
}
}
return bCanRecombine ;
}
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : GetGraphDisplayInformation ( const UEdGraph & Graph , /*out*/ FGraphDisplayInfo & DisplayInfo ) const
{
DisplayInfo . DocLink = TEXT ( " Shared/Editors/BlueprintEditor/GraphTypes " ) ;
2014-04-23 18:30:37 -04:00
DisplayInfo . PlainName = FText : : FromString ( Graph . GetName ( ) ) ; // Fallback is graph name
2014-03-14 14:13:41 -04:00
UFunction * Function = NULL ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( & Graph ) ;
if ( Blueprint )
{
Function = Blueprint - > SkeletonGeneratedClass - > FindFunctionByName ( Graph . GetFName ( ) ) ;
}
const EGraphType GraphType = GetGraphType ( & Graph ) ;
if ( GraphType = = GT_Ubergraph )
{
DisplayInfo . DocExcerptName = TEXT ( " EventGraph " ) ;
if ( Graph . GetFName ( ) = = GN_EventGraph )
{
// localized name for the first event graph
2014-04-23 18:30:37 -04:00
DisplayInfo . PlainName = LOCTEXT ( " GraphDisplayName_EventGraph " , " EventGraph " ) ;
DisplayInfo . Tooltip = DisplayInfo . PlainName . ToString ( ) ;
2014-03-14 14:13:41 -04:00
}
else
{
DisplayInfo . Tooltip = Graph . GetName ( ) ;
}
}
else if ( GraphType = = GT_Function )
{
2014-07-08 18:23:43 -04:00
if ( Graph . GetFName ( ) = = FN_UserConstructionScript )
{
2014-04-23 18:30:37 -04:00
DisplayInfo . PlainName = LOCTEXT ( " GraphDisplayName_ConstructionScript " , " ConstructionScript " ) ;
2014-03-14 14:13:41 -04:00
DisplayInfo . Tooltip = LOCTEXT ( " GraphTooltip_ConstructionScript " , " Function executed when Blueprint is placed or modified. " ) . ToString ( ) ;
DisplayInfo . DocExcerptName = TEXT ( " ConstructionScript " ) ;
2014-07-08 18:23:43 -04:00
}
2014-03-14 14:13:41 -04:00
else
2014-07-08 18:23:43 -04:00
{
2014-09-01 12:04:47 -04:00
// If we found a function from this graph..
2014-03-14 14:13:41 -04:00
if ( Function )
2014-07-08 18:23:43 -04:00
{
2014-09-01 12:04:47 -04:00
DisplayInfo . PlainName = FText : : FromString ( UK2Node_CallFunction : : GetUserFacingFunctionName ( Function ) ) ; // grab friendly function name
DisplayInfo . Tooltip = UK2Node_CallFunction : : GetDefaultTooltipForFunction ( Function ) ; // grab its tooltip
2014-07-08 18:23:43 -04:00
}
else
{
2014-03-14 14:13:41 -04:00
DisplayInfo . Tooltip = Graph . GetName ( ) ;
}
DisplayInfo . DocExcerptName = TEXT ( " FunctionGraph " ) ;
}
}
else if ( GraphType = = GT_Macro )
{
// Show macro description if set
FKismetUserDeclaredFunctionMetadata * MetaData = UK2Node_MacroInstance : : GetAssociatedGraphMetadata ( & Graph ) ;
2014-07-07 20:00:22 -04:00
DisplayInfo . Tooltip = ( MetaData & & MetaData - > ToolTip . Len ( ) > 0 ) ? MetaData - > ToolTip : Graph . GetName ( ) ;
2014-03-14 14:13:41 -04:00
DisplayInfo . DocExcerptName = TEXT ( " MacroGraph " ) ;
}
else if ( GraphType = = GT_Animation )
{
2014-04-23 18:30:37 -04:00
DisplayInfo . PlainName = LOCTEXT ( " GraphDisplayName_AnimGraph " , " AnimGraph " ) ;
2014-03-14 14:13:41 -04:00
DisplayInfo . Tooltip = LOCTEXT ( " GraphTooltip_AnimGraph " , " Graph used to blend together different animations. " ) . ToString ( ) ;
DisplayInfo . DocExcerptName = TEXT ( " AnimGraph " ) ;
}
else if ( GraphType = = GT_StateMachine )
2014-07-08 18:23:43 -04:00
{
2014-03-14 14:13:41 -04:00
DisplayInfo . Tooltip = Graph . GetName ( ) ;
DisplayInfo . DocExcerptName = TEXT ( " StateMachine " ) ;
}
// Add pure to notes if set
if ( Function & & Function - > HasAnyFunctionFlags ( FUNC_BlueprintPure ) )
2014-07-08 18:23:43 -04:00
{
DisplayInfo . Notes . Add ( TEXT ( " pure " ) ) ;
}
2014-03-14 14:13:41 -04:00
// Mark transient graphs as obviously so
if ( Graph . HasAllFlags ( RF_Transient ) )
{
2014-04-23 18:30:37 -04:00
DisplayInfo . PlainName = FText : : FromString ( FString : : Printf ( TEXT ( " $$ %s $$ " ) , * DisplayInfo . PlainName . ToString ( ) ) ) ;
2014-03-14 14:13:41 -04:00
DisplayInfo . Notes . Add ( TEXT ( " intermediate build product " ) ) ;
}
2014-04-23 18:30:37 -04:00
if ( GEditor & & GetDefault < UEditorStyleSettings > ( ) - > bShowFriendlyNames )
{
DisplayInfo . DisplayName = FText : : FromString ( FName : : NameToDisplayString ( DisplayInfo . PlainName . ToString ( ) , false ) ) ;
}
else
{
DisplayInfo . DisplayName = DisplayInfo . PlainName ;
}
2014-03-14 14:13:41 -04:00
}
bool UEdGraphSchema_K2 : : IsSelfPin ( const UEdGraphPin & Pin ) const
{
return ( Pin . PinName = = PN_Self ) ;
}
bool UEdGraphSchema_K2 : : IsDelegateCategory ( const FString & Category ) const
{
return ( Category = = PC_Delegate ) ;
}
FVector2D UEdGraphSchema_K2 : : CalculateAveragePositionBetweenNodes ( UEdGraphPin * InputPin , UEdGraphPin * OutputPin )
{
UEdGraphNode * InputNode = InputPin - > GetOwningNode ( ) ;
UEdGraphNode * OutputNode = OutputPin - > GetOwningNode ( ) ;
const FVector2D InputCorner ( InputNode - > NodePosX , InputNode - > NodePosY ) ;
const FVector2D OutputCorner ( OutputNode - > NodePosX , OutputNode - > NodePosY ) ;
return ( InputCorner + OutputCorner ) * 0.5f ;
}
2014-04-23 17:48:43 -04:00
bool UEdGraphSchema_K2 : : IsConstructionScript ( const UEdGraph * TestEdGraph ) const
{
TArray < class UK2Node_FunctionEntry * > EntryNodes ;
TestEdGraph - > GetNodesOfClass < UK2Node_FunctionEntry > ( EntryNodes ) ;
bool bIsConstructionScript = false ;
if ( EntryNodes . Num ( ) > 0 )
{
UK2Node_FunctionEntry const * const EntryNode = EntryNodes [ 0 ] ;
bIsConstructionScript = ( EntryNode - > SignatureName = = FN_UserConstructionScript ) ;
}
return bIsConstructionScript ;
}
2014-03-14 14:13:41 -04:00
bool UEdGraphSchema_K2 : : IsCompositeGraph ( const UEdGraph * TestEdGraph ) const
{
check ( TestEdGraph ) ;
const EGraphType GraphType = GetGraphType ( TestEdGraph ) ;
if ( GraphType = = GT_Function )
{
//Find the Tunnel node for composite graph and see if its output is a composite node
for ( auto I = TestEdGraph - > Nodes . CreateConstIterator ( ) ; I ; + + I )
{
UEdGraphNode * Node = * I ;
if ( auto Tunnel = Cast < UK2Node_Tunnel > ( Node ) )
{
if ( auto OutNode = Tunnel - > OutputSourceNode )
{
if ( Cast < UK2Node_Composite > ( OutNode ) )
{
return true ;
}
}
}
}
}
return false ;
}
void UEdGraphSchema_K2 : : DroppedAssetsOnGraph ( const TArray < FAssetData > & Assets , const FVector2D & GraphPosition , UEdGraph * Graph ) const
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( Graph ) ;
if ( ( Blueprint ! = NULL ) & & FBlueprintEditorUtils : : IsActorBased ( Blueprint ) )
{
float XOffset = 0.0f ;
for ( int32 AssetIdx = 0 ; AssetIdx < Assets . Num ( ) ; AssetIdx + + )
{
FVector2D Position = GraphPosition + ( AssetIdx * FVector2D ( XOffset , 0.0f ) ) ;
UObject * Asset = Assets [ AssetIdx ] . GetAsset ( ) ;
2014-04-23 18:18:30 -04:00
UClass * AssetClass = Asset - > GetClass ( ) ;
if ( UBlueprint * BlueprintAsset = Cast < UBlueprint > ( Asset ) )
{
AssetClass = BlueprintAsset - > GeneratedClass ;
}
TSubclassOf < UActorComponent > DestinationComponentType = FComponentAssetBrokerage : : GetPrimaryComponentForAsset ( AssetClass ) ;
if ( ( DestinationComponentType = = NULL ) & & AssetClass - > IsChildOf ( AActor : : StaticClass ( ) ) )
{
DestinationComponentType = UChildActorComponent : : StaticClass ( ) ;
}
2014-03-14 14:13:41 -04:00
// Make sure we have an asset type that's registered with the component list
if ( DestinationComponentType ! = NULL )
{
2014-04-23 19:02:16 -04:00
UEdGraph * TempOuter = NewObject < UEdGraph > ( ( UObject * ) Blueprint ) ;
TempOuter - > SetFlags ( RF_Transient ) ;
TSharedPtr < FEdGraphSchemaAction_K2AddComponent > Action = FK2ActionMenuBuilder : : CreateAddComponentAction ( TempOuter , Blueprint , DestinationComponentType , Asset ) ;
2014-03-14 14:13:41 -04:00
Action - > PerformAction ( Graph , NULL , GraphPosition ) ;
}
}
}
}
void UEdGraphSchema_K2 : : DroppedAssetsOnNode ( const TArray < FAssetData > & Assets , const FVector2D & GraphPosition , UEdGraphNode * Node ) const
{
// @TODO: Should dropping on component node change the component?
}
void UEdGraphSchema_K2 : : DroppedAssetsOnPin ( const TArray < FAssetData > & Assets , const FVector2D & GraphPosition , UEdGraphPin * Pin ) const
{
// If dropping onto an 'object' pin, try and set the literal
2014-04-23 17:58:27 -04:00
if ( ( Pin - > PinType . PinCategory = = PC_Object ) | | ( Pin - > PinType . PinCategory = = PC_Interface ) )
2014-03-14 14:13:41 -04:00
{
UClass * PinClass = Cast < UClass > ( Pin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( PinClass ! = NULL )
{
// Find first asset of type of the pin
UObject * Asset = FAssetData : : GetFirstAssetDataOfClass ( Assets , PinClass ) . GetAsset ( ) ;
if ( Asset ! = NULL )
{
TrySetDefaultObject ( * Pin , Asset ) ;
}
}
}
}
void UEdGraphSchema_K2 : : GetAssetsNodeHoverMessage ( const TArray < FAssetData > & Assets , const UEdGraphNode * HoverNode , FString & OutTooltipText , bool & OutOkIcon ) const
{
// No comment at the moment because this doesn't do anything
OutTooltipText = TEXT ( " " ) ;
OutOkIcon = false ;
}
void UEdGraphSchema_K2 : : GetAssetsPinHoverMessage ( const TArray < FAssetData > & Assets , const UEdGraphPin * HoverPin , FString & OutTooltipText , bool & OutOkIcon ) const
{
OutTooltipText = TEXT ( " " ) ;
OutOkIcon = false ;
// If dropping onto an 'object' pin, try and set the literal
2014-04-23 17:58:27 -04:00
if ( ( HoverPin - > PinType . PinCategory = = PC_Object ) | | ( HoverPin - > PinType . PinCategory = = PC_Interface ) )
2014-03-14 14:13:41 -04:00
{
UClass * PinClass = Cast < UClass > ( HoverPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( PinClass ! = NULL )
{
// Find first asset of type of the pin
FAssetData AssetData = FAssetData : : GetFirstAssetDataOfClass ( Assets , PinClass ) ;
if ( AssetData . IsValid ( ) )
{
OutOkIcon = true ;
OutTooltipText = FString : : Printf ( TEXT ( " Assign %s to this pin " ) , * ( AssetData . AssetName . ToString ( ) ) ) ;
}
else
{
OutOkIcon = false ;
OutTooltipText = FString : : Printf ( TEXT ( " Not compatible with this pin " ) ) ;
}
}
}
}
bool UEdGraphSchema_K2 : : FadeNodeWhenDraggingOffPin ( const UEdGraphNode * Node , const UEdGraphPin * Pin ) const
{
if ( Node & & Pin & & ( PC_Delegate = = Pin - > PinType . PinCategory ) & & ( EGPD_Input = = Pin - > Direction ) )
{
//When dragging off a delegate pin, we should duck the alpha of all nodes except the Custom Event nodes that are compatible with the delegate signature
//This would help reinforce the connection between delegates and their matching events, and make it easier to see at a glance what could be matched up.
if ( const UK2Node_Event * EventNode = Cast < const UK2Node_Event > ( Node ) )
{
const UEdGraphPin * DelegateOutPin = EventNode - > FindPin ( UK2Node_Event : : DelegateOutputName ) ;
if ( ( NULL ! = DelegateOutPin ) & &
( ECanCreateConnectionResponse : : CONNECT_RESPONSE_DISALLOW ! = CanCreateConnection ( DelegateOutPin , Pin ) . Response ) )
{
return false ;
}
}
if ( const UK2Node_CreateDelegate * CreateDelegateNode = Cast < const UK2Node_CreateDelegate > ( Node ) )
{
const UEdGraphPin * DelegateOutPin = CreateDelegateNode - > GetDelegateOutPin ( ) ;
if ( ( NULL ! = DelegateOutPin ) & &
( ECanCreateConnectionResponse : : CONNECT_RESPONSE_DISALLOW ! = CanCreateConnection ( DelegateOutPin , Pin ) . Response ) )
{
return false ;
}
}
return true ;
}
return false ;
}
2014-04-23 16:39:43 -04:00
struct FBackwardCompatibilityConversionHelper
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:39:43 -04:00
static bool ConvertNode (
UK2Node * OldNode ,
const FString & BlueprintPinName ,
UK2Node * NewNode ,
const FString & ClassPinName ,
const UEdGraphSchema_K2 & Schema ,
bool bOnlyWithDefaultBlueprint )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:39:43 -04:00
check ( OldNode & & NewNode ) ;
const auto Blueprint = OldNode - > GetBlueprint ( ) ;
auto Graph = OldNode - > GetGraph ( ) ;
if ( ! Graph )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:39:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error bp: '%s' node: '%s'. No graph containing the node. " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* OldNode - > GetName ( ) ,
* BlueprintPinName ) ;
return false ;
}
2014-03-14 14:13:41 -04:00
2014-04-23 16:39:43 -04:00
auto OldBlueprintPin = OldNode - > FindPin ( BlueprintPinName ) ;
if ( ! OldBlueprintPin )
2014-07-08 18:23:43 -04:00
{
2014-04-23 16:39:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error bp: '%s' node: '%s'. No bp pin found '%s' " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* OldNode - > GetName ( ) ,
* BlueprintPinName ) ;
return false ;
}
const bool bNondefaultBPConnected = ( OldBlueprintPin - > LinkedTo . Num ( ) > 0 ) ;
2014-05-21 07:40:05 -04:00
const bool bTryConvert = ! bNondefaultBPConnected | | ! bOnlyWithDefaultBlueprint ;
2014-04-23 16:39:43 -04:00
if ( bTryConvert )
{
// CREATE NEW NODE
NewNode - > SetFlags ( RF_Transactional ) ;
Graph - > AddNode ( NewNode , false , false ) ;
NewNode - > CreateNewGuid ( ) ;
NewNode - > PostPlacedNewNode ( ) ;
NewNode - > AllocateDefaultPins ( ) ;
NewNode - > NodePosX = OldNode - > NodePosX ;
NewNode - > NodePosY = OldNode - > NodePosY ;
const auto ClassPin = NewNode - > FindPin ( ClassPinName ) ;
if ( ! ClassPin )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:39:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error bp: '%s' node: '%s'. No class pin found '%s' " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* NewNode - > GetName ( ) ,
* ClassPinName ) ;
return false ;
}
auto TargetClass = Cast < UClass > ( ClassPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( ! TargetClass )
{
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error bp: '%s' node: '%s'. No class found '%s' " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* NewNode - > GetName ( ) ,
* ClassPinName ) ;
return false ;
}
2014-03-14 14:13:41 -04:00
2014-04-23 16:39:43 -04:00
// REPLACE BLUEPRINT WITH CLASS
if ( ! bNondefaultBPConnected )
{
// DEFAULT VALUE
2014-03-14 14:13:41 -04:00
const auto UsedBlueprint = Cast < UBlueprint > ( OldBlueprintPin - > DefaultObject ) ;
2014-05-21 07:40:05 -04:00
ensure ( ! OldBlueprintPin - > DefaultObject | | UsedBlueprint ) ;
ensure ( ! UsedBlueprint | | * UsedBlueprint - > GeneratedClass ) ;
UClass * UsedClass = UsedBlueprint ? * UsedBlueprint - > GeneratedClass : NULL ;
Schema . TrySetDefaultObject ( * ClassPin , UsedClass ) ;
if ( ClassPin - > DefaultObject ! = UsedClass )
2014-04-23 16:39:43 -04:00
{
2014-05-21 07:40:05 -04:00
auto ErrorStr = Schema . IsPinDefaultValid ( ClassPin , FString ( ) , UsedClass , FText ( ) ) ;
2014-04-23 16:39:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot set class' in blueprint: %s node: '%s' actor bp: %s, reason: %s " ) ,
2014-03-14 14:13:41 -04:00
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
2014-04-23 16:39:43 -04:00
* OldNode - > GetName ( ) ,
2014-03-14 14:13:41 -04:00
UsedBlueprint ? * UsedBlueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
ErrorStr . IsEmpty ( ) ? TEXT ( " Unknown " ) : * ErrorStr ) ;
2014-04-23 16:39:43 -04:00
return false ;
}
}
else
{
// LINK
auto CastNode = NewObject < UK2Node_ClassDynamicCast > ( Graph ) ;
2014-04-23 19:09:44 -04:00
CastNode - > SetFlags ( RF_Transactional ) ;
2014-04-23 16:39:43 -04:00
CastNode - > TargetType = TargetClass ;
Graph - > AddNode ( CastNode , false , false ) ;
CastNode - > CreateNewGuid ( ) ;
CastNode - > PostPlacedNewNode ( ) ;
CastNode - > AllocateDefaultPins ( ) ;
const int32 OffsetOnGraph = 200 ;
CastNode - > NodePosX = OldNode - > NodePosX - OffsetOnGraph ;
CastNode - > NodePosY = OldNode - > NodePosY ;
auto ExecPin = OldNode - > GetExecPin ( ) ;
auto ExecCastPin = CastNode - > GetExecPin ( ) ;
check ( ExecCastPin ) ;
if ( ! ExecPin | | ! Schema . MovePinLinks ( * ExecPin , * ExecCastPin ) . CanSafeConnect ( ) )
{
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot connect' in blueprint: %s, pin: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* ExecCastPin - > PinName ) ;
return false ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 16:39:43 -04:00
auto ValidCastPin = CastNode - > GetValidCastPin ( ) ;
check ( ValidCastPin ) ;
if ( ! Schema . TryCreateConnection ( ValidCastPin , ExecPin ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 16:39:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot connect' in blueprint: %s, pin: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* ValidCastPin - > PinName ) ;
return false ;
}
2014-04-23 18:14:04 -04:00
auto InValidCastPin = CastNode - > GetInvalidCastPin ( ) ;
check ( InValidCastPin ) ;
if ( ! Schema . TryCreateConnection ( InValidCastPin , ExecPin ) )
{
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot connect' in blueprint: %s, pin: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* InValidCastPin - > PinName ) ;
return false ;
}
2014-04-23 16:39:43 -04:00
auto CastSourcePin = CastNode - > GetCastSourcePin ( ) ;
check ( CastSourcePin ) ;
if ( ! Schema . MovePinLinks ( * OldBlueprintPin , * CastSourcePin ) . CanSafeConnect ( ) )
{
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot connect' in blueprint: %s, pin: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* CastSourcePin - > PinName ) ;
return false ;
}
auto CastResultPin = CastNode - > GetCastResultPin ( ) ;
check ( CastResultPin ) ;
if ( ! Schema . TryCreateConnection ( CastResultPin , ClassPin ) )
{
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot connect' in blueprint: %s, pin: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* CastResultPin - > PinName ) ;
return false ;
}
}
// MOVE OTHER PINS
2014-07-08 18:23:43 -04:00
TArray < UEdGraphPin * > OldPins ;
OldPins . Add ( OldBlueprintPin ) ;
2014-04-23 16:39:43 -04:00
for ( auto PinIter = NewNode - > Pins . CreateIterator ( ) ; PinIter ; + + PinIter )
2014-07-08 18:23:43 -04:00
{
UEdGraphPin * const Pin = * PinIter ;
check ( Pin ) ;
if ( ClassPin ! = Pin )
2014-04-23 16:39:43 -04:00
{
2014-06-16 11:10:42 -04:00
const auto OldPin = OldNode - > FindPin ( Pin - > PinName ) ;
if ( NULL ! = OldPin )
2014-07-08 18:23:43 -04:00
{
OldPins . Add ( OldPin ) ;
2014-07-08 10:44:06 -04:00
if ( ! Schema . MovePinLinks ( * OldPin , * Pin ) . CanSafeConnect ( ) )
{
2014-07-08 18:23:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot connect' in blueprint: %s, pin: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
* Pin - > PinName ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-07-08 18:23:43 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-07-08 18:23:43 -04:00
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'missing old pin' in blueprint: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
2014-03-14 14:13:41 -04:00
Pin ? * Pin - > PinName : TEXT ( " Unknown " ) ) ;
}
}
2014-07-08 18:23:43 -04:00
}
OldNode - > BreakAllNodeLinks ( ) ;
for ( auto PinIter = OldNode - > Pins . CreateIterator ( ) ; PinIter ; + + PinIter )
{
if ( ! OldPins . Contains ( * PinIter ) )
{
UEdGraphPin * Pin = * PinIter ;
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'missing new pin' in blueprint: %s " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ,
Pin ? * Pin - > PinName : TEXT ( " Unknown " ) ) ;
}
}
2014-04-23 16:39:43 -04:00
Graph - > RemoveNode ( OldNode ) ;
return true ;
}
return false ;
}
struct FFunctionCallParams
{
const FName OldFuncName ;
const FName NewFuncName ;
const FString & BlueprintPinName ;
const FString & ClassPinName ;
const UClass * FuncScope ;
FFunctionCallParams ( FName InOldFunc , FName InNewFunc , const FString & InBlueprintPinName , const FString & InClassPinName , const UClass * InFuncScope )
: OldFuncName ( InOldFunc ) , NewFuncName ( InNewFunc ) , BlueprintPinName ( InBlueprintPinName ) , ClassPinName ( InClassPinName ) , FuncScope ( InFuncScope )
{
check ( FuncScope ) ;
}
2014-05-21 07:40:05 -04:00
FFunctionCallParams ( const FBlueprintCallableFunctionRedirect & FunctionRedirect )
: OldFuncName ( * FunctionRedirect . OldFunctionName )
, NewFuncName ( * FunctionRedirect . NewFunctionName )
, BlueprintPinName ( FunctionRedirect . BlueprintParamName )
, ClassPinName ( FunctionRedirect . ClassParamName )
, FuncScope ( NULL )
{
FuncScope = FindObject < UClass > ( ANY_PACKAGE , * FunctionRedirect . ClassName ) ;
}
2014-04-23 16:39:43 -04:00
} ;
static void ConvertFunctionCallNodes ( const FFunctionCallParams & ConversionParams , TArray < UK2Node_CallFunction * > & Nodes , UEdGraph * Graph , const UEdGraphSchema_K2 & Schema , bool bOnlyWithDefaultBlueprint )
{
2014-05-21 07:40:05 -04:00
if ( ConversionParams . FuncScope )
{
2014-04-23 16:39:43 -04:00
const UFunction * OldFunc = ConversionParams . FuncScope - > FindFunctionByName ( ConversionParams . OldFuncName ) ;
check ( OldFunc ) ;
const UFunction * NewFunc = ConversionParams . FuncScope - > FindFunctionByName ( ConversionParams . NewFuncName ) ;
check ( NewFunc ) ;
for ( auto It = Nodes . CreateIterator ( ) ; It ; + + It )
{
if ( OldFunc = = ( * It ) - > GetTargetFunction ( ) )
{
auto NewNode = NewObject < UK2Node_CallFunction > ( Graph ) ;
NewNode - > SetFromFunction ( NewFunc ) ;
ConvertNode ( * It , ConversionParams . BlueprintPinName , NewNode ,
ConversionParams . ClassPinName , Schema , bOnlyWithDefaultBlueprint ) ;
}
}
}
2014-05-21 07:40:05 -04:00
}
2014-04-23 16:39:43 -04:00
} ;
void UEdGraphSchema_K2 : : BackwardCompatibilityNodeConversion ( UEdGraph * Graph , bool bOnlySafeChanges ) const
{
if ( Graph )
{
{
static const FString BlueprintPinName ( TEXT ( " Blueprint " ) ) ;
static const FString ClassPinName ( TEXT ( " Class " ) ) ;
TArray < UK2Node_SpawnActor * > SpawnActorNodes ;
Graph - > GetNodesOfClass ( SpawnActorNodes ) ;
for ( auto It = SpawnActorNodes . CreateIterator ( ) ; It ; + + It )
{
FBackwardCompatibilityConversionHelper : : ConvertNode (
* It , BlueprintPinName , NewObject < UK2Node_SpawnActorFromClass > ( Graph ) ,
ClassPinName , * this , bOnlySafeChanges ) ;
}
}
{
2014-05-19 09:22:29 -04:00
auto Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( Graph ) ;
if ( Blueprint & & * Blueprint - > SkeletonGeneratedClass )
2014-04-23 16:39:43 -04:00
{
2014-05-19 09:22:29 -04:00
TArray < UK2Node_CallFunction * > Nodes ;
Graph - > GetNodesOfClass ( Nodes ) ;
2014-05-21 07:40:05 -04:00
for ( const auto & FunctionRedirect : EditoronlyBPFunctionRedirects )
2014-05-19 09:22:29 -04:00
{
2014-05-21 07:40:05 -04:00
FBackwardCompatibilityConversionHelper : : ConvertFunctionCallNodes (
FBackwardCompatibilityConversionHelper : : FFunctionCallParams ( FunctionRedirect ) ,
Nodes , Graph , * this , bOnlySafeChanges ) ;
2014-05-19 09:22:29 -04:00
}
}
else
2014-04-23 16:39:43 -04:00
{
2014-05-19 09:22:29 -04:00
UE_LOG ( LogBlueprint , Log , TEXT ( " BackwardCompatibilityNodeConversion: Blueprint '%s' cannot be fully converted. It has no skeleton class! " ) ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ) ;
2014-03-14 14:13:41 -04:00
}
}
/** Fix the old Make/Break Vector, Make/Break Vector 2D, and Make/Break Rotator nodes to use the native function call versions */
TArray < UK2Node_MakeStruct * > MakeStructNodes ;
Graph - > GetNodesOfClass < UK2Node_MakeStruct > ( MakeStructNodes ) ;
for ( auto It = MakeStructNodes . CreateIterator ( ) ; It ; + + It )
{
UK2Node_MakeStruct * OldMakeStructNode = * It ;
check ( NULL ! = OldMakeStructNode ) ;
2014-04-02 18:09:23 -04:00
// user may have since deleted the struct type
if ( OldMakeStructNode - > StructType = = NULL )
{
continue ;
}
2014-03-14 14:13:41 -04:00
// Check to see if the struct has a native make/break that we should try to convert to.
2014-06-30 16:03:48 -04:00
if ( OldMakeStructNode - > StructType & & OldMakeStructNode - > StructType - > HasMetaData ( TEXT ( " HasNativeMake " ) ) )
2014-03-14 14:13:41 -04:00
{
UFunction * MakeNodeFunction = NULL ;
// If any pins need to change their names during the conversion, add them to the map.
TMap < FString , FString > OldPinToNewPinMap ;
if ( OldMakeStructNode - > StructType - > GetName ( ) = = TEXT ( " Rotator " ) )
{
MakeNodeFunction = FindObject < UClass > ( ANY_PACKAGE , TEXT ( " KismetMathLibrary " ) ) - > FindFunctionByName ( TEXT ( " MakeRot " ) ) ;
OldPinToNewPinMap . Add ( TEXT ( " Rotator " ) , TEXT ( " ReturnValue " ) ) ;
}
else if ( OldMakeStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector " ) )
{
MakeNodeFunction = FindObject < UClass > ( ANY_PACKAGE , TEXT ( " KismetMathLibrary " ) ) - > FindFunctionByName ( TEXT ( " MakeVector " ) ) ;
OldPinToNewPinMap . Add ( TEXT ( " Vector " ) , TEXT ( " ReturnValue " ) ) ;
}
else if ( OldMakeStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector2D " ) )
{
MakeNodeFunction = FindObject < UClass > ( ANY_PACKAGE , TEXT ( " KismetMathLibrary " ) ) - > FindFunctionByName ( TEXT ( " MakeVector2D " ) ) ;
OldPinToNewPinMap . Add ( TEXT ( " Vector2D " ) , TEXT ( " ReturnValue " ) ) ;
}
if ( MakeNodeFunction )
{
UK2Node_CallFunction * CallFunctionNode = NewObject < UK2Node_CallFunction > ( Graph ) ;
check ( CallFunctionNode ) ;
CallFunctionNode - > SetFlags ( RF_Transactional ) ;
Graph - > AddNode ( CallFunctionNode , false , false ) ;
CallFunctionNode - > SetFromFunction ( MakeNodeFunction ) ;
CallFunctionNode - > CreateNewGuid ( ) ;
CallFunctionNode - > PostPlacedNewNode ( ) ;
CallFunctionNode - > AllocateDefaultPins ( ) ;
CallFunctionNode - > NodePosX = OldMakeStructNode - > NodePosX ;
CallFunctionNode - > NodePosY = OldMakeStructNode - > NodePosY ;
for ( int32 PinIdx = 0 ; PinIdx < OldMakeStructNode - > Pins . Num ( ) ; + + PinIdx )
{
UEdGraphPin * OldPin = OldMakeStructNode - > Pins [ PinIdx ] ;
UEdGraphPin * NewPin = NULL ;
// Check to see if the pin name is mapped to a new one, if it is use it, otherwise just search for the pin under the old name
FString * NewPinNamePtr = OldPinToNewPinMap . Find ( OldPin - > PinName ) ;
if ( NewPinNamePtr )
{
NewPin = CallFunctionNode - > FindPin ( * NewPinNamePtr ) ;
}
else
{
NewPin = CallFunctionNode - > FindPin ( OldPin - > PinName ) ;
}
check ( NewPin ) ;
if ( ! Graph - > GetSchema ( ) - > MovePinLinks ( * OldPin , * NewPin ) . CanSafeConnect ( ) )
{
const UBlueprint * Blueprint = OldMakeStructNode - > GetBlueprint ( ) ;
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot safetly move pin %s to %s' in blueprint: %s " ) ,
* OldPin - > PinName ,
* NewPin - > PinName ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ) ;
}
}
OldMakeStructNode - > DestroyNode ( ) ;
}
}
}
TArray < UK2Node_BreakStruct * > BreakStructNodes ;
Graph - > GetNodesOfClass < UK2Node_BreakStruct > ( BreakStructNodes ) ;
for ( auto It = BreakStructNodes . CreateIterator ( ) ; It ; + + It )
{
UK2Node_BreakStruct * OldBreakStructNode = * It ;
check ( NULL ! = OldBreakStructNode ) ;
2014-04-02 18:09:23 -04:00
// user may have since deleted the struct type
if ( OldBreakStructNode - > StructType = = NULL )
{
continue ;
}
2014-07-08 18:23:43 -04:00
// Check to see if the struct has a native make/break that we should try to convert to.
2014-06-30 16:03:48 -04:00
if ( OldBreakStructNode - > StructType & & OldBreakStructNode - > StructType - > HasMetaData ( TEXT ( " HasNativeBreak " ) ) )
2014-03-14 14:13:41 -04:00
{
UFunction * BreakNodeFunction = NULL ;
// If any pins need to change their names during the conversion, add them to the map.
TMap < FString , FString > OldPinToNewPinMap ;
if ( OldBreakStructNode - > StructType - > GetName ( ) = = TEXT ( " Rotator " ) )
{
BreakNodeFunction = FindObject < UClass > ( ANY_PACKAGE , TEXT ( " KismetMathLibrary " ) ) - > FindFunctionByName ( TEXT ( " BreakRot " ) ) ;
OldPinToNewPinMap . Add ( TEXT ( " Rotator " ) , TEXT ( " InRot " ) ) ;
}
else if ( OldBreakStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector " ) )
{
BreakNodeFunction = FindObject < UClass > ( ANY_PACKAGE , TEXT ( " KismetMathLibrary " ) ) - > FindFunctionByName ( TEXT ( " BreakVector " ) ) ;
OldPinToNewPinMap . Add ( TEXT ( " Vector " ) , TEXT ( " InVec " ) ) ;
}
else if ( OldBreakStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector2D " ) )
{
BreakNodeFunction = FindObject < UClass > ( ANY_PACKAGE , TEXT ( " KismetMathLibrary " ) ) - > FindFunctionByName ( TEXT ( " BreakVector2D " ) ) ;
OldPinToNewPinMap . Add ( TEXT ( " Vector2D " ) , TEXT ( " InVec " ) ) ;
}
if ( BreakNodeFunction )
{
UK2Node_CallFunction * CallFunctionNode = NewObject < UK2Node_CallFunction > ( Graph ) ;
check ( CallFunctionNode ) ;
CallFunctionNode - > SetFlags ( RF_Transactional ) ;
Graph - > AddNode ( CallFunctionNode , false , false ) ;
CallFunctionNode - > SetFromFunction ( BreakNodeFunction ) ;
CallFunctionNode - > CreateNewGuid ( ) ;
CallFunctionNode - > PostPlacedNewNode ( ) ;
CallFunctionNode - > AllocateDefaultPins ( ) ;
CallFunctionNode - > NodePosX = OldBreakStructNode - > NodePosX ;
CallFunctionNode - > NodePosY = OldBreakStructNode - > NodePosY ;
for ( int32 PinIdx = 0 ; PinIdx < OldBreakStructNode - > Pins . Num ( ) ; + + PinIdx )
{
UEdGraphPin * OldPin = OldBreakStructNode - > Pins [ PinIdx ] ;
UEdGraphPin * NewPin = NULL ;
// Check to see if the pin name is mapped to a new one, if it is use it, otherwise just search for the pin under the old name
FString * NewPinNamePtr = OldPinToNewPinMap . Find ( OldPin - > PinName ) ;
if ( NewPinNamePtr )
{
NewPin = CallFunctionNode - > FindPin ( * NewPinNamePtr ) ;
}
else
{
NewPin = CallFunctionNode - > FindPin ( OldPin - > PinName ) ;
}
check ( NewPin ) ;
if ( ! Graph - > GetSchema ( ) - > MovePinLinks ( * OldPin , * NewPin ) . CanSafeConnect ( ) )
{
const UBlueprint * Blueprint = OldBreakStructNode - > GetBlueprint ( ) ;
UE_LOG ( LogBlueprint , Warning , TEXT ( " BackwardCompatibilityNodeConversion Error 'cannot safetly move pin %s to %s' in blueprint: %s " ) ,
* OldPin - > PinName ,
* NewPin - > PinName ,
Blueprint ? * Blueprint - > GetName ( ) : TEXT ( " Unknown " ) ) ;
}
}
OldBreakStructNode - > DestroyNode ( ) ;
}
}
}
}
}
UEdGraphNode * UEdGraphSchema_K2 : : CreateSubstituteNode ( UEdGraphNode * Node , const UEdGraph * Graph , FObjectInstancingGraph * InstanceGraph ) const
{
// If this is an event node, create a unique custom event node as a substitute
UK2Node_Event * EventNode = Cast < UK2Node_Event > ( Node ) ;
if ( EventNode )
{
if ( ! Graph )
{
// Use the node's graph (outer) if an explicit graph was not specified
Graph = Node - > GetGraph ( ) ;
}
2014-07-25 18:40:53 -04:00
// Can only place events in ubergraphs
if ( GetGraphType ( Graph ) ! = EGraphType : : GT_Ubergraph )
{
return NULL ;
}
2014-03-14 14:13:41 -04:00
// Find the Blueprint that owns the graph
UBlueprint * Blueprint = Graph ? FBlueprintEditorUtils : : FindBlueprintForGraph ( Graph ) : NULL ;
if ( Blueprint & & Blueprint - > SkeletonGeneratedClass )
{
// Gather all names in use by the Blueprint class
TArray < FName > ExistingNamesInUse ;
FBlueprintEditorUtils : : GetFunctionNameList ( Blueprint , ExistingNamesInUse ) ;
FBlueprintEditorUtils : : GetClassVariableList ( Blueprint , ExistingNamesInUse ) ;
2014-06-04 15:06:27 -04:00
const ERenameFlags RenameFlags = ( Blueprint - > bIsRegeneratingOnLoad ? REN_ForceNoResetLoaders : 0 ) ;
2014-03-14 14:13:41 -04:00
// Allow the old object name to be used in the graph
FName ObjName = EventNode - > GetFName ( ) ;
UObject * Found = FindObject < UObject > ( EventNode - > GetOuter ( ) , * ObjName . ToString ( ) ) ;
if ( Found )
{
2014-06-04 15:06:27 -04:00
Found - > Rename ( NULL , NULL , REN_DontCreateRedirectors | RenameFlags ) ;
2014-03-14 14:13:41 -04:00
}
// Create a custom event node to replace the original event node imported from text
UK2Node_CustomEvent * CustomEventNode = ConstructObject < UK2Node_CustomEvent > ( UK2Node_CustomEvent : : StaticClass ( ) , EventNode - > GetOuter ( ) , ObjName , EventNode - > GetFlags ( ) , NULL , true , InstanceGraph ) ;
// Ensure that it is editable
CustomEventNode - > bIsEditable = true ;
// Set grid position to match that of the target node
CustomEventNode - > NodePosX = EventNode - > NodePosX ;
CustomEventNode - > NodePosY = EventNode - > NodePosY ;
// Build a function name that is appropriate for the event we're replacing
FString FunctionName ;
const UK2Node_ActorBoundEvent * ActorBoundEventNode = Cast < const UK2Node_ActorBoundEvent > ( EventNode ) ;
const UK2Node_ComponentBoundEvent * CompBoundEventNode = Cast < const UK2Node_ComponentBoundEvent > ( EventNode ) ;
if ( ActorBoundEventNode )
{
FString TargetName = TEXT ( " None " ) ;
if ( ActorBoundEventNode - > EventOwner )
{
TargetName = ActorBoundEventNode - > EventOwner - > GetActorLabel ( ) ;
}
FunctionName = FString : : Printf ( TEXT ( " %s_%s " ) , * ActorBoundEventNode - > DelegatePropertyName . ToString ( ) , * TargetName ) ;
}
else if ( CompBoundEventNode )
{
FunctionName = FString : : Printf ( TEXT ( " %s_%s " ) , * CompBoundEventNode - > DelegatePropertyName . ToString ( ) , * CompBoundEventNode - > ComponentPropertyName . ToString ( ) ) ;
}
else if ( EventNode - > CustomFunctionName ! = NAME_None )
{
FunctionName = EventNode - > CustomFunctionName . ToString ( ) ;
}
else if ( EventNode - > bOverrideFunction )
{
FunctionName = EventNode - > EventSignatureName . ToString ( ) ;
}
else
{
FunctionName = CustomEventNode - > GetName ( ) . Replace ( TEXT ( " K2Node_ " ) , TEXT ( " " ) , ESearchCase : : CaseSensitive ) ;
}
// Ensure that the new event name doesn't already exist as a variable or function name
if ( InstanceGraph )
{
FunctionName + = TEXT ( " _Copy " ) ;
CustomEventNode - > CustomFunctionName = FName ( * FunctionName , FNAME_Find ) ;
if ( CustomEventNode - > CustomFunctionName ! = NAME_None
& & ExistingNamesInUse . Contains ( CustomEventNode - > CustomFunctionName ) )
{
int32 i = 0 ;
FString TempFuncName ;
do
{
TempFuncName = FString : : Printf ( TEXT ( " %s_%d " ) , * FunctionName , + + i ) ;
CustomEventNode - > CustomFunctionName = FName ( * TempFuncName , FNAME_Find ) ;
}
while ( CustomEventNode - > CustomFunctionName ! = NAME_None
& & ExistingNamesInUse . Contains ( CustomEventNode - > CustomFunctionName ) ) ;
FunctionName = TempFuncName ;
}
}
// Should be a unique name now, go ahead and assign it
CustomEventNode - > CustomFunctionName = FName ( * FunctionName ) ;
// Copy the pins from the old node to the new one that's replacing it
CustomEventNode - > Pins = EventNode - > Pins ;
CustomEventNode - > UserDefinedPins = EventNode - > UserDefinedPins ;
// Clear out the pins from the old node so that links aren't broken later when it's destroyed
EventNode - > Pins . Empty ( ) ;
EventNode - > UserDefinedPins . Empty ( ) ;
// Fixup pins
for ( int32 PinIndex = 0 ; PinIndex < CustomEventNode - > Pins . Num ( ) ; + + PinIndex )
{
UEdGraphPin * Pin = CustomEventNode - > Pins [ PinIndex ] ;
check ( Pin ) ;
// Reparent the pin to the new custom event node
2014-06-04 15:06:27 -04:00
Pin - > Rename ( * Pin - > GetName ( ) , CustomEventNode , RenameFlags ) ;
2014-03-14 14:13:41 -04:00
// Don't include execution or delegate output pins as user-defined pins
if ( ! IsExecPin ( * Pin ) & & ! IsDelegateCategory ( Pin - > PinType . PinCategory ) )
{
// Check to see if this pin already exists as a user-defined pin on the custom event node
bool bFoundUserDefinedPin = false ;
for ( int32 UserDefinedPinIndex = 0 ; UserDefinedPinIndex < CustomEventNode - > UserDefinedPins . Num ( ) & & ! bFoundUserDefinedPin ; + + UserDefinedPinIndex )
{
const FUserPinInfo & UserDefinedPinInfo = * CustomEventNode - > UserDefinedPins [ UserDefinedPinIndex ] . Get ( ) ;
bFoundUserDefinedPin = Pin - > PinName = = UserDefinedPinInfo . PinName & & Pin - > PinType = = UserDefinedPinInfo . PinType ;
}
if ( ! bFoundUserDefinedPin )
{
// Add a new entry into the user-defined pin array for the custom event node
TSharedPtr < FUserPinInfo > UserPinInfo = MakeShareable ( new FUserPinInfo ( ) ) ;
UserPinInfo - > PinName = Pin - > PinName ;
UserPinInfo - > PinType = Pin - > PinType ;
CustomEventNode - > UserDefinedPins . Add ( UserPinInfo ) ;
}
}
}
// Return the new custom event node that we just created as a substitute for the original event node
return CustomEventNode ;
}
}
// Use the default logic in all other cases
return UEdGraphSchema : : CreateSubstituteNode ( Node , Graph , InstanceGraph ) ;
}
int32 UEdGraphSchema_K2 : : GetNodeSelectionCount ( const UEdGraph * Graph ) const
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( Graph ) ;
int32 SelectionCount = 0 ;
if ( Blueprint )
{
SelectionCount = FKismetEditorUtilities : : GetNumberOfSelectedNodes ( Blueprint ) ;
}
return SelectionCount ;
}
TSharedPtr < FEdGraphSchemaAction > UEdGraphSchema_K2 : : GetCreateCommentAction ( ) const
{
return TSharedPtr < FEdGraphSchemaAction > ( static_cast < FEdGraphSchemaAction * > ( new FEdGraphSchemaAction_K2AddComment ) ) ;
}
Added a new documentation node to the blueprints to display udn documentation excerpts in the grapheditor.
#TTP 312311 - ROCKET: TASK: Add a "Documentation Node"
#Branch UE4
#Proj BlueprintGraph, EdGraph, Kismet, KismetCompiler, GraphEditor, Documentation, EditorStyle
#Change Updated UEdGraphSchema to include an interface call to retrieve an FEdGraphSchemaAction to create documentation nodes. At this point only the K2 interfaces implement this.
#Change Updated UEdGraphSchema_K2 to include a call to retrieve an FEdGraphSchemaAction to create documentation nodes. This is used to add the actions to the blueprint palette and context menus.
#Add Added FEdGraphSchemaAction_K2AddDocumentation in EdGraphSchema_K2_Actions.h/cpp to implement the calls in UEdGraphSchema to create documenation nodes from palette and context menus.
#Change Modified FK2ActionMenuBuilder to provide a static call to create a documentation action in the same style as the comment. Additionally added calls to FK2ActionMenuBuilder::GetPaletteActions and FK2ActionMenuBuilder::GetContextAllowedNodeTypes to call this to add entries in the palette and context menus.
#Add Added a new Brush GraphEditor.Documentation_16x, for the context menu icon in SlateEditorStyle.cpp.
#Change Modified GetPaletteItemIcon in SBlueprintPalette.cpp to return the new icon for the DocumentationNode
#Change Modified FKismetCompilerContext::IsNodePure to include the Documentaton node in the drop through ensure test to prevent asserts on compling if a documentation node is present.
#Change Added an entry for Documentation node in FNodeFactory::CreateNodeWidget.
#Change Modified IDocumentationPage interface to provide the ability to provide a TextWrapAt Attribute so this can be set before creating excerpt content if desired.
#Change Modified the UDNParser to control text wrap at values in the created widgets using a float Attribute WrapAt, Added a set call in the DocumentationPage and made the default behaviour mimic the code it replaced.
#Add Added the class UEdGraphNode_Documentation implemented in EdGraphNode_Documentation.h and UEdGraph.cpp, this is the UObject implementation for the documentation nodes.
#Add Added the class SGraphNodeDocumentation as the GraphPanel implementation of the EdGraphNode_Documentation.
#Change Moved the resizable code from SGraphNodeComment into a SGraphNodeResizable and changed SGraphNodeComment and SGraphNodeDocumentation inherit from it to avoid duplicating code.
#Change Added a documentation specific details customisation so the excerpts can be displayed as combo button.
#Change Added FBlueprintDocumentationDetails into BlueprintDetailsCustomization.h/cpp to handle the user interaction with the documentation node in the BP Editor.
ReviewedBy Chris.Wood, Mike.Beach
[CL 2247425 by Ben Cosh in Main branch]
2014-08-07 15:33:55 -04:00
TSharedPtr < FEdGraphSchemaAction > UEdGraphSchema_K2 : : GetCreateDocumentNodeAction ( ) const
{
return TSharedPtr < FEdGraphSchemaAction > ( static_cast < FEdGraphSchemaAction * > ( new FEdGraphSchemaAction_K2AddDocumentation ) ) ;
}
2014-04-02 18:09:23 -04:00
bool UEdGraphSchema_K2 : : CanDuplicateGraph ( UEdGraph * InSourceGraph ) const
{
if ( GetGraphType ( InSourceGraph ) = = GT_Function )
{
UBlueprint * SourceBP = FBlueprintEditorUtils : : FindBlueprintForGraph ( InSourceGraph ) ;
// Do not duplicate graphs in Blueprint Interfaces
if ( SourceBP - > BlueprintType = = BPTYPE_Interface )
{
return false ;
}
// Do not duplicate functions from implemented interfaces
if ( FBlueprintEditorUtils : : FindFunctionInImplementedInterfaces ( SourceBP , InSourceGraph - > GetFName ( ) ) )
{
return false ;
}
// Do not duplicate inherited functions
if ( FindField < UFunction > ( SourceBP - > ParentClass , InSourceGraph - > GetFName ( ) ) )
{
return false ;
}
}
return true ;
}
2014-03-14 14:13:41 -04:00
UEdGraph * UEdGraphSchema_K2 : : DuplicateGraph ( UEdGraph * GraphToDuplicate ) const
{
UEdGraph * NewGraph = NULL ;
2014-04-02 18:09:23 -04:00
if ( CanDuplicateGraph ( GraphToDuplicate ) )
2014-03-14 14:13:41 -04:00
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( GraphToDuplicate ) ;
NewGraph = FEdGraphUtilities : : CloneGraph ( GraphToDuplicate , Blueprint ) ;
if ( NewGraph )
{
2014-08-26 15:01:56 -04:00
FName NewGraphName = FBlueprintEditorUtils : : FindUniqueKismetName ( Blueprint , GraphToDuplicate - > GetFName ( ) . GetPlainNameString ( ) ) ;
FEdGraphUtilities : : RenameGraphCloseToName ( NewGraph , NewGraphName . ToString ( ) ) ;
2014-05-29 17:43:17 -04:00
// can't have two graphs with the same guid... that'd be silly!
NewGraph - > GraphGuid = FGuid : : NewGuid ( ) ;
2014-03-14 14:13:41 -04:00
//Rename the entry node or any further renames will not update the entry node, also fixes a duplicate node issue on compile
for ( int32 NodeIndex = 0 ; NodeIndex < NewGraph - > Nodes . Num ( ) ; + + NodeIndex )
{
UEdGraphNode * Node = NewGraph - > Nodes [ NodeIndex ] ;
if ( UK2Node_FunctionEntry * EntryNode = Cast < UK2Node_FunctionEntry > ( Node ) )
{
if ( EntryNode - > SignatureName = = GraphToDuplicate - > GetFName ( ) )
{
EntryNode - > Modify ( ) ;
EntryNode - > SignatureName = NewGraph - > GetFName ( ) ;
break ;
}
}
// Rename any custom events to be unique
else if ( Node - > GetClass ( ) - > GetFName ( ) = = TEXT ( " K2Node_CustomEvent " ) )
{
UK2Node_CustomEvent * CustomEvent = Cast < UK2Node_CustomEvent > ( Node ) ;
CustomEvent - > RenameCustomEventCloseToName ( ) ;
}
}
}
}
return NewGraph ;
}
/**
* Attempts to best - guess the height of the node . This is necessary because we don ' t know the actual
* size of the node until the next Slate tick
*
* @ param Node The node to guess the height of
* @ return The estimated height of the specified node
*/
float UEdGraphSchema_K2 : : EstimateNodeHeight ( UEdGraphNode * Node )
{
float HeightEstimate = 0.0f ;
if ( Node ! = NULL )
{
float BaseNodeHeight = 48.0f ;
bool bConsiderNodePins = false ;
float HeightPerPin = 18.0f ;
if ( Node - > IsA ( UK2Node_CallFunction : : StaticClass ( ) ) )
{
BaseNodeHeight = 80.0f ;
bConsiderNodePins = true ;
HeightPerPin = 18.0f ;
}
else if ( Node - > IsA ( UK2Node_Event : : StaticClass ( ) ) )
{
BaseNodeHeight = 48.0f ;
bConsiderNodePins = true ;
HeightPerPin = 16.0f ;
}
HeightEstimate = BaseNodeHeight ;
if ( bConsiderNodePins )
{
int32 NumInputPins = 0 ;
int32 NumOutputPins = 0 ;
for ( int32 PinIndex = 0 ; PinIndex < Node - > Pins . Num ( ) ; PinIndex + + )
{
UEdGraphPin * CurrentPin = Node - > Pins [ PinIndex ] ;
if ( CurrentPin ! = NULL & & ! CurrentPin - > bHidden )
{
switch ( CurrentPin - > Direction )
{
case EGPD_Input :
{
NumInputPins + + ;
}
break ;
case EGPD_Output :
{
NumOutputPins + + ;
}
break ;
}
}
}
float MaxNumPins = float ( FMath : : Max < int32 > ( NumInputPins , NumOutputPins ) ) ;
HeightEstimate + = MaxNumPins * HeightPerPin ;
}
}
return HeightEstimate ;
}
2014-06-16 11:10:42 -04:00
bool UEdGraphSchema_K2 : : CollapseGatewayNode ( UK2Node * InNode , UEdGraphNode * InEntryNode , UEdGraphNode * InResultNode , FKismetCompilerContext * CompilerContext ) const
2014-03-14 14:13:41 -04:00
{
bool bSuccessful = true ;
2014-06-16 11:10:42 -04:00
// We iterate the array in reverse so we can both remove the subpins safely after we've read them and
// so we have split nested structs we combine them back together in the right order
for ( int32 BoundaryPinIndex = InNode - > Pins . Num ( ) - 1 ; BoundaryPinIndex > = 0 ; - - BoundaryPinIndex )
2014-03-14 14:13:41 -04:00
{
UEdGraphPin * const BoundaryPin = InNode - > Pins [ BoundaryPinIndex ] ;
bool bFunctionNode = InNode - > IsA ( UK2Node_CallFunction : : StaticClass ( ) ) ;
// For each pin in the gateway node, find the associated pin in the entry or result node.
UEdGraphNode * const GatewayNode = ( BoundaryPin - > Direction = = EGPD_Input ) ? InEntryNode : InResultNode ;
UEdGraphPin * GatewayPin = NULL ;
if ( GatewayNode )
{
2014-06-16 11:10:42 -04:00
// First handle struct combining if necessary
if ( BoundaryPin - > SubPins . Num ( ) > 0 )
{
InNode - > ExpandSplitPin ( CompilerContext , InNode - > GetGraph ( ) , BoundaryPin ) ;
}
for ( int32 PinIdx = GatewayNode - > Pins . Num ( ) - 1 ; PinIdx > = 0 ; - - PinIdx )
2014-03-14 14:13:41 -04:00
{
UEdGraphPin * const Pin = GatewayNode - > Pins [ PinIdx ] ;
2014-06-16 11:10:42 -04:00
// Expand any gateway pins as needed
if ( Pin - > SubPins . Num ( ) > 0 )
{
InNode - > ExpandSplitPin ( CompilerContext , GatewayNode - > GetGraph ( ) , Pin ) ;
}
2014-03-14 14:13:41 -04:00
// Function graphs have a single exec path through them, so only one exec pin for input and another for output. In this fashion, they must not be handled by name.
if ( InNode - > GetClass ( ) = = UK2Node_CallFunction : : StaticClass ( ) & & Pin - > PinType . PinCategory = = PC_Exec & & BoundaryPin - > PinType . PinCategory = = PC_Exec & & ( Pin - > Direction ! = BoundaryPin - > Direction ) )
{
GatewayPin = Pin ;
break ;
}
else if ( ( Pin - > PinName = = BoundaryPin - > PinName ) & & ( Pin - > Direction ! = BoundaryPin - > Direction ) )
{
GatewayPin = Pin ;
break ;
}
}
}
if ( GatewayPin )
{
CombineTwoPinNetsAndRemoveOldPins ( BoundaryPin , GatewayPin ) ;
}
else
{
2014-06-16 11:10:42 -04:00
if ( BoundaryPin - > LinkedTo . Num ( ) > 0 & & BoundaryPin - > ParentPin = = NULL )
2014-03-14 14:13:41 -04:00
{
UBlueprint * OwningBP = InNode - > GetBlueprint ( ) ;
if ( OwningBP )
{
// We had an input/output with a connection that wasn't twinned
bSuccessful = false ;
OwningBP - > Message_Warn ( FString : : Printf ( * NSLOCTEXT ( " K2Node " , " PinOnBoundryNode_Warning " , " Warning: Pin '%s' on boundary node '%s' could not be found in the composite node '%s' " ) . ToString ( ) ,
* ( BoundaryPin - > PinName ) ,
( GatewayNode ! = NULL ) ? * ( GatewayNode - > GetName ( ) ) : TEXT ( " (null) " ) ,
* ( GetName ( ) ) )
) ;
}
else
{
UE_LOG ( LogBlueprint , Warning , TEXT ( " %s " ) , * FString : : Printf ( * NSLOCTEXT ( " K2Node " , " PinOnBoundryNode_Warning " , " Warning: Pin '%s' on boundary node '%s' could not be found in the composite node '%s' " ) . ToString ( ) ,
* ( BoundaryPin - > PinName ) ,
( GatewayNode ! = NULL ) ? * ( GatewayNode - > GetName ( ) ) : TEXT ( " (null) " ) ,
* ( GetName ( ) ) )
) ;
}
}
else
{
// Associated pin was not found but there were no links on this side either, so no harm no foul
}
}
}
return bSuccessful ;
}
2014-07-08 18:23:43 -04:00
2014-03-14 14:13:41 -04:00
void UEdGraphSchema_K2 : : CombineTwoPinNetsAndRemoveOldPins ( UEdGraphPin * InPinA , UEdGraphPin * InPinB ) const
{
check ( InPinA ! = NULL ) ;
check ( InPinB ! = NULL ) ;
ensure ( InPinA - > Direction ! = InPinB - > Direction ) ;
if ( ( InPinA - > LinkedTo . Num ( ) = = 0 ) & & ( InPinA - > Direction = = EGPD_Input ) )
{
// Push the literal value of A to InPinB's connections
for ( int32 IndexB = 0 ; IndexB < InPinB - > LinkedTo . Num ( ) ; + + IndexB )
{
UEdGraphPin * FarB = InPinB - > LinkedTo [ IndexB ] ;
// TODO: Michael N. says this if check should be unnecessary once the underlying issue is fixed.
// (Probably should use a check() instead once it's removed though. See additional cases below.
if ( FarB ! = NULL )
{
FarB - > DefaultValue = InPinA - > DefaultValue ;
FarB - > DefaultObject = InPinA - > DefaultObject ;
FarB - > DefaultTextValue = InPinA - > DefaultTextValue ;
}
}
}
else if ( ( InPinB - > LinkedTo . Num ( ) = = 0 ) & & ( InPinB - > Direction = = EGPD_Input ) )
{
// Push the literal value of B to InPinA's connections
for ( int32 IndexA = 0 ; IndexA < InPinA - > LinkedTo . Num ( ) ; + + IndexA )
{
UEdGraphPin * FarA = InPinA - > LinkedTo [ IndexA ] ;
// TODO: Michael N. says this if check should be unnecessary once the underlying issue is fixed.
// (Probably should use a check() instead once it's removed though. See additional cases above and below.
if ( FarA ! = NULL )
{
FarA - > DefaultValue = InPinB - > DefaultValue ;
FarA - > DefaultObject = InPinB - > DefaultObject ;
FarA - > DefaultTextValue = InPinB - > DefaultTextValue ;
}
}
}
else
{
// Make direct connections between the things that connect to A or B, removing A and B from the picture
for ( int32 IndexA = 0 ; IndexA < InPinA - > LinkedTo . Num ( ) ; + + IndexA )
{
UEdGraphPin * FarA = InPinA - > LinkedTo [ IndexA ] ;
// TODO: Michael N. says this if check should be unnecessary once the underlying issue is fixed.
// (Probably should use a check() instead once it's removed though. See additional cases above.
if ( FarA ! = NULL )
{
for ( int32 IndexB = 0 ; IndexB < InPinB - > LinkedTo . Num ( ) ; + + IndexB )
{
UEdGraphPin * FarB = InPinB - > LinkedTo [ IndexB ] ;
FarA - > Modify ( ) ;
FarB - > Modify ( ) ;
FarA - > MakeLinkTo ( FarB ) ;
}
}
}
}
InPinA - > BreakAllPinLinks ( ) ;
InPinB - > BreakAllPinLinks ( ) ;
}
2014-06-16 11:10:42 -04:00
UK2Node * UEdGraphSchema_K2 : : CreateSplitPinNode ( UEdGraphPin * Pin , FKismetCompilerContext * CompilerContext , UEdGraph * SourceGraph ) const
{
UEdGraphNode * GraphNode = Pin - > GetOwningNode ( ) ;
UEdGraph * Graph = GraphNode - > GetGraph ( ) ;
UScriptStruct * StructType = CastChecked < UScriptStruct > ( Pin - > PinType . PinSubCategoryObject . Get ( ) ) ;
UK2Node * SplitPinNode = NULL ;
if ( Pin - > Direction = = EGPD_Input )
{
if ( UK2Node_MakeStruct : : CanBeMade ( StructType ) )
{
UK2Node_MakeStruct * MakeStructNode = ( CompilerContext ? CompilerContext - > SpawnIntermediateNode < UK2Node_MakeStruct > ( GraphNode , SourceGraph ) : NewObject < UK2Node_MakeStruct > ( Graph ) ) ;
MakeStructNode - > StructType = StructType ;
SplitPinNode = MakeStructNode ;
}
else
{
const FString & MetaData = StructType - > GetMetaData ( TEXT ( " HasNativeMake " ) ) ;
const UFunction * Function = FindObject < UFunction > ( NULL , * MetaData , true ) ;
UK2Node_CallFunction * CallFunctionNode = ( CompilerContext ? CompilerContext - > SpawnIntermediateNode < UK2Node_CallFunction > ( GraphNode , SourceGraph ) : NewObject < UK2Node_CallFunction > ( Graph ) ) ;
CallFunctionNode - > SetFromFunction ( Function ) ;
SplitPinNode = CallFunctionNode ;
}
}
else
{
if ( UK2Node_BreakStruct : : CanBeBroken ( StructType ) )
{
UK2Node_BreakStruct * BreakStructNode = ( CompilerContext ? CompilerContext - > SpawnIntermediateNode < UK2Node_BreakStruct > ( GraphNode , SourceGraph ) : NewObject < UK2Node_BreakStruct > ( Graph ) ) ;
BreakStructNode - > StructType = StructType ;
SplitPinNode = BreakStructNode ;
}
else
{
const FString & MetaData = StructType - > GetMetaData ( TEXT ( " HasNativeBreak " ) ) ;
const UFunction * Function = FindObject < UFunction > ( NULL , * MetaData , true ) ;
UK2Node_CallFunction * CallFunctionNode = ( CompilerContext ? CompilerContext - > SpawnIntermediateNode < UK2Node_CallFunction > ( GraphNode , SourceGraph ) : NewObject < UK2Node_CallFunction > ( Graph ) ) ;
CallFunctionNode - > SetFromFunction ( Function ) ;
SplitPinNode = CallFunctionNode ;
}
}
SplitPinNode - > AllocateDefaultPins ( ) ;
return SplitPinNode ;
}
void UEdGraphSchema_K2 : : SplitPin ( UEdGraphPin * Pin ) const
{
2014-07-08 10:44:06 -04:00
// Under some circumstances we can get here when PinSubCategoryObject is not set, so we just can't split the pin in that case
UScriptStruct * StructType = Cast < UScriptStruct > ( Pin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( StructType = = nullptr )
{
return ;
}
2014-06-16 11:10:42 -04:00
UEdGraphNode * GraphNode = Pin - > GetOwningNode ( ) ;
2014-07-07 13:47:02 -04:00
UK2Node * K2Node = Cast < UK2Node > ( GraphNode ) ;
2014-06-16 11:10:42 -04:00
UEdGraph * Graph = CastChecked < UEdGraph > ( GraphNode - > GetOuter ( ) ) ;
GraphNode - > Modify ( ) ;
Pin - > Modify ( ) ;
Pin - > bHidden = true ;
UK2Node * ProtoExpandNode = CreateSplitPinNode ( Pin ) ;
for ( UEdGraphPin * ProtoPin : ProtoExpandNode - > Pins )
{
if ( ProtoPin - > Direction = = Pin - > Direction & & ! ProtoPin - > bHidden )
{
const FString PinName = FString : : Printf ( TEXT ( " %s_%s " ) , * Pin - > PinName , * ProtoPin - > PinName ) ;
const FEdGraphPinType & ProtoPinType = ProtoPin - > PinType ;
2014-07-10 14:15:44 -04:00
UEdGraphPin * SubPin = GraphNode - > CreatePin ( Pin - > Direction , ProtoPinType . PinCategory , ProtoPinType . PinSubCategory , ProtoPinType . PinSubCategoryObject . Get ( ) , ProtoPinType . bIsArray , false , PinName ) ;
2014-06-16 11:10:42 -04:00
2014-07-07 13:47:02 -04:00
if ( K2Node ! = nullptr & & K2Node - > ShouldDrawCompact ( ) )
{
if ( Pin - > ParentPin )
{
2014-08-07 13:23:24 -04:00
SubPin - > PinFriendlyName = FText : : FromString ( FString : : Printf ( TEXT ( " %s %s " ) , * Pin - > GetDisplayName ( ) . ToString ( ) , * ProtoPin - > GetDisplayName ( ) . ToString ( ) ) ) ;
2014-07-07 13:47:02 -04:00
}
else
{
2014-08-07 13:23:24 -04:00
SubPin - > PinFriendlyName = ProtoPin - > GetDisplayName ( ) ;
2014-07-07 13:47:02 -04:00
}
}
else
2014-07-01 14:55:39 -04:00
{
2014-08-07 13:23:24 -04:00
SubPin - > PinFriendlyName = FText : : FromString ( FString : : Printf ( TEXT ( " %s %s " ) , * Pin - > GetDisplayName ( ) . ToString ( ) , * ProtoPin - > GetDisplayName ( ) . ToString ( ) ) ) ;
2014-07-01 14:55:39 -04:00
}
2014-06-16 11:10:42 -04:00
SubPin - > DefaultValue = ProtoPin - > DefaultValue ;
SubPin - > AutogeneratedDefaultValue = ProtoPin - > AutogeneratedDefaultValue ;
SubPin - > ParentPin = Pin ;
// CreatePin puts the Pin in the array, but we are going to insert it later, so pop it back out
GraphNode - > Pins . Pop ( ) ;
Pin - > SubPins . Add ( SubPin ) ;
}
}
ProtoExpandNode - > DestroyNode ( ) ;
if ( Pin - > Direction = = EGPD_Input )
{
TArray < FString > OriginalDefaults ;
2014-06-18 14:47:24 -04:00
if ( StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Vector " ) )
| | StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Rotator " ) ) )
2014-06-16 11:10:42 -04:00
{
Pin - > DefaultValue . ParseIntoArray ( & OriginalDefaults , TEXT ( " , " ) , false ) ;
2014-06-16 11:35:47 -04:00
for ( FString & Default : OriginalDefaults )
{
2014-07-02 13:49:04 -04:00
Default = FString : : SanitizeFloat ( FCString : : Atof ( * Default ) ) ;
2014-06-16 11:35:47 -04:00
}
2014-09-03 10:31:54 -04:00
// In some cases (particularly wildcards) the default value may not accurately reflect the normal component elements
while ( OriginalDefaults . Num ( ) < 3 )
{
OriginalDefaults . Add ( TEXT ( " 0.0 " ) ) ;
}
2014-06-16 11:10:42 -04:00
}
else if ( StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Vector2D " ) ) )
{
FVector2D V2D ;
V2D . InitFromString ( Pin - > DefaultValue ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( V2D . X ) ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( V2D . Y ) ) ;
}
else if ( StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " LinearColor " ) ) )
{
FLinearColor LC ;
LC . InitFromString ( Pin - > DefaultValue ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( LC . R ) ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( LC . G ) ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( LC . B ) ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( LC . A ) ) ;
}
check ( OriginalDefaults . Num ( ) = = 0 | | OriginalDefaults . Num ( ) = = Pin - > SubPins . Num ( ) ) ;
for ( int32 SubPinIndex = 0 ; SubPinIndex < OriginalDefaults . Num ( ) ; + + SubPinIndex )
{
UEdGraphPin * SubPin = Pin - > SubPins [ SubPinIndex ] ;
SubPin - > DefaultValue = OriginalDefaults [ SubPinIndex ] ;
}
}
GraphNode - > Pins . Insert ( Pin - > SubPins , GraphNode - > Pins . Find ( Pin ) + 1 ) ;
Graph - > NotifyGraphChanged ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( Graph ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
void UEdGraphSchema_K2 : : RecombinePin ( UEdGraphPin * Pin ) const
{
UEdGraphNode * GraphNode = Pin - > GetOwningNode ( ) ;
UEdGraphPin * ParentPin = Pin - > ParentPin ;
GraphNode - > Modify ( ) ;
ParentPin - > Modify ( ) ;
ParentPin - > bHidden = false ;
for ( int32 SubPinIndex = 0 ; SubPinIndex < ParentPin - > SubPins . Num ( ) ; + + SubPinIndex )
{
UEdGraphPin * SubPin = ParentPin - > SubPins [ SubPinIndex ] ;
if ( SubPin - > SubPins . Num ( ) > 0 )
{
RecombinePin ( SubPin - > SubPins [ 0 ] ) ;
}
GraphNode - > Pins . Remove ( SubPin ) ;
}
if ( Pin - > Direction = = EGPD_Input )
{
UScriptStruct * StructType = CastChecked < UScriptStruct > ( ParentPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
TArray < FString > OriginalDefaults ;
2014-06-18 14:47:24 -04:00
if ( StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Vector " ) )
| | StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Rotator " ) ) )
2014-06-16 11:10:42 -04:00
{
ParentPin - > DefaultValue = ParentPin - > SubPins [ 0 ] - > DefaultValue + TEXT ( " , " )
+ ParentPin - > SubPins [ 1 ] - > DefaultValue + TEXT ( " , " )
+ ParentPin - > SubPins [ 2 ] - > DefaultValue ;
}
else if ( StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " Vector2D " ) ) )
{
FVector2D V2D ;
V2D . X = FCString : : Atof ( * ParentPin - > SubPins [ 0 ] - > DefaultValue ) ;
V2D . Y = FCString : : Atof ( * ParentPin - > SubPins [ 1 ] - > DefaultValue ) ;
ParentPin - > DefaultValue = V2D . ToString ( ) ;
}
else if ( StructType = = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) , TEXT ( " LinearColor " ) ) )
{
FLinearColor LC ;
LC . R = FCString : : Atof ( * ParentPin - > SubPins [ 0 ] - > DefaultValue ) ;
LC . G = FCString : : Atof ( * ParentPin - > SubPins [ 1 ] - > DefaultValue ) ;
LC . B = FCString : : Atof ( * ParentPin - > SubPins [ 2 ] - > DefaultValue ) ;
LC . A = FCString : : Atof ( * ParentPin - > SubPins [ 3 ] - > DefaultValue ) ;
ParentPin - > DefaultValue = LC . ToString ( ) ;
}
}
ParentPin - > SubPins . Empty ( ) ;
UEdGraph * Graph = CastChecked < UEdGraph > ( GraphNode - > GetOuter ( ) ) ;
Graph - > NotifyGraphChanged ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( Graph ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
2014-03-14 14:13:41 -04:00
2014-07-07 18:00:01 -04:00
void UEdGraphSchema_K2 : : ConfigureVarNode ( UK2Node_Variable * InVarNode , FName InVariableName , UStruct * InVariableSource , UBlueprint * InTargetBlueprint )
{
// See if this is a 'self context' (ie. blueprint class is owner (or child of owner) of dropped var class)
if ( ( InVariableSource = = NULL ) | | InTargetBlueprint - > SkeletonGeneratedClass - > IsChildOf ( InVariableSource ) )
{
InVarNode - > VariableReference . SetSelfMember ( InVariableName ) ;
}
2014-07-17 12:05:16 -04:00
else if ( InVariableSource - > IsA ( UClass : : StaticClass ( ) ) )
2014-07-07 18:00:01 -04:00
{
2014-07-17 12:05:16 -04:00
InVarNode - > VariableReference . SetExternalMember ( InVariableName , CastChecked < UClass > ( InVariableSource ) ) ;
2014-07-07 18:00:01 -04:00
}
else
{
2014-07-17 12:05:16 -04:00
FGuid LocalVarGuid = FBlueprintEditorUtils : : FindLocalVariableGuidByName ( InTargetBlueprint , InVariableSource , InVariableName ) ;
if ( LocalVarGuid . IsValid ( ) )
{
InVarNode - > VariableReference . SetLocalMember ( InVariableName , InVariableSource , LocalVarGuid ) ;
}
2014-07-07 18:00:01 -04:00
}
}
UK2Node_VariableGet * UEdGraphSchema_K2 : : SpawnVariableGetNode ( const FVector2D GraphPosition , class UEdGraph * ParentGraph , FName VariableName , UStruct * Source ) const
{
UK2Node_VariableGet * NodeTemplate = NewObject < UK2Node_VariableGet > ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( ParentGraph ) ;
UEdGraphSchema_K2 : : ConfigureVarNode ( NodeTemplate , VariableName , Source , Blueprint ) ;
return FEdGraphSchemaAction_K2NewNode : : SpawnNodeFromTemplate < UK2Node_VariableGet > ( ParentGraph , NodeTemplate , GraphPosition ) ;
}
UK2Node_VariableSet * UEdGraphSchema_K2 : : SpawnVariableSetNode ( const FVector2D GraphPosition , class UEdGraph * ParentGraph , FName VariableName , UStruct * Source ) const
{
UK2Node_VariableSet * NodeTemplate = NewObject < UK2Node_VariableSet > ( ) ;
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( ParentGraph ) ;
UEdGraphSchema_K2 : : ConfigureVarNode ( NodeTemplate , VariableName , Source , Blueprint ) ;
return FEdGraphSchemaAction_K2NewNode : : SpawnNodeFromTemplate < UK2Node_VariableSet > ( ParentGraph , NodeTemplate , GraphPosition ) ;
}
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
# undef LOCTEXT_NAMESPACE