2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 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"
2015-06-05 11:45:49 -04:00
# include "Kismet/KismetMathLibrary.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"
2014-12-15 15:30:07 -05:00
# include "BlueprintEditorSettings.h"
2014-03-14 14:13:41 -04:00
# 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"
2015-04-16 11:47:54 -04:00
# include "ComponentTypeRegistry.h"
# include "BlueprintComponentNodeSpawner.h"
2014-04-23 20:18:55 -04:00
# include "AssetRegistryModule.h"
2014-05-29 17:06:50 -04:00
# include "Blueprint/AIBlueprintHelperLibrary.h"
2015-06-29 16:03:22 -04:00
# include "HotReloadInterface.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"
2015-05-15 16:44:55 -04:00
# include "K2Node_ConvertAsset.h"
2014-10-14 22:50:06 -04:00
# include "GenericCommands.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 " ) ) ;
2015-02-17 07:17:54 -05:00
const FName FBlueprintMetadata : : MD_ChildCanTick ( TEXT ( " ChildCanTick " ) ) ;
const FName FBlueprintMetadata : : MD_ChildCannotTick ( TEXT ( " ChildCannotTick " ) ) ;
2015-02-17 09:13:35 -05:00
const FName FBlueprintMetadata : : MD_IgnoreCategoryKeywordsInSubclasses ( TEXT ( " IgnoreCategoryKeywordsInSubclasses " ) ) ;
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 " ) ) ;
2015-06-26 11:59:50 -04:00
const FName FBlueprintMetadata : : MD_DisplayName ( TEXT ( " DisplayName " ) ) ;
2015-06-30 14:42:07 -04:00
const FName FBlueprintMetadata : : MD_InternalUseParam ( TEXT ( " InternalUseParam " ) ) ;
2014-03-14 14:13:41 -04:00
const FName FBlueprintMetadata : : MD_ExposeOnSpawn ( TEXT ( " ExposeOnSpawn " ) ) ;
2015-07-09 10:25:29 -04:00
const FName FBlueprintMetadata : : MD_HideSelfPin ( TEXT ( " HideSelfPin " ) ) ;
2014-03-14 14:13:41 -04:00
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 " ) ) ;
2015-04-21 14:12:38 -04:00
const FName FBlueprintMetadata : : MD_ArrayParam ( TEXT ( " ArrayParm " ) ) ;
const FName FBlueprintMetadata : : MD_ArrayDependentParam ( TEXT ( " ArrayTypeDependentParams " ) ) ;
2014-03-14 14:13:41 -04:00
//////////////////////////////////////////////////////////////////////////
# define LOCTEXT_NAMESPACE "KismetSchema"
2015-06-03 14:47:53 -04:00
UEdGraphSchema_K2 : : FPinTypeTreeInfo : : FPinTypeTreeInfo ( const FText & InFriendlyName , const FString & CategoryName , const UEdGraphSchema_K2 * Schema , const FText & InTooltip , bool bInReadOnly /*=false*/ , FTypesDatabase * TypesDatabase /*=nullptr*/ )
2015-07-02 10:25:42 -04:00
: PossibleObjectReferenceTypes ( 0 )
2014-03-14 14:13:41 -04:00
{
2015-06-03 14:47:53 -04:00
Init ( InFriendlyName , CategoryName , Schema , InTooltip , bInReadOnly , TypesDatabase ) ;
2014-03-14 14:13:41 -04:00
}
2015-05-28 03:57:54 -04:00
struct FUnloadedAssetData
{
FStringAssetReference StringAssetReference ;
FText AssetFriendlyName ;
FText Tooltip ;
2015-07-02 10:25:42 -04:00
uint8 PossibleObjectReferenceTypes ;
2015-05-28 03:57:54 -04:00
FUnloadedAssetData ( )
2015-07-02 10:25:42 -04:00
: PossibleObjectReferenceTypes ( 0 )
2015-05-28 03:57:54 -04:00
{ }
2015-07-02 10:25:42 -04:00
FUnloadedAssetData ( const FAssetData & InAsset , uint8 InPossibleObjectReferenceTypes = 0 )
2015-05-28 03:57:54 -04:00
: StringAssetReference ( InAsset . ToStringReference ( ) )
, AssetFriendlyName ( FText : : FromString ( FName : : NameToDisplayString ( InAsset . AssetName . ToString ( ) , false ) ) )
2015-07-02 10:25:42 -04:00
, PossibleObjectReferenceTypes ( InPossibleObjectReferenceTypes )
2015-05-28 03:57:54 -04:00
{
const FString * TooltipPtr = InAsset . TagsAndValues . Find ( TEXT ( " Tooltip " ) ) ;
Tooltip = FText : : FromString ( ( TooltipPtr & & ! TooltipPtr - > IsEmpty ( ) ) ? * TooltipPtr : InAsset . ObjectPath . ToString ( ) ) ;
}
} ;
struct FLoadedAssetData
{
FText Tooltip ;
UObject * Object ;
2015-07-02 10:25:42 -04:00
uint8 PossibleObjectReferenceTypes ;
2015-05-28 03:57:54 -04:00
2015-07-02 10:25:42 -04:00
FLoadedAssetData ( )
: Object ( nullptr )
, PossibleObjectReferenceTypes ( 0 ) { }
FLoadedAssetData ( UObject * InObject , uint8 InPossibleObjectReferenceTypes = 0 )
2015-05-28 03:57:54 -04:00
: Object ( InObject )
2015-07-02 10:25:42 -04:00
, PossibleObjectReferenceTypes ( InPossibleObjectReferenceTypes )
2015-05-28 03:57:54 -04:00
{
UStruct * Struct = Cast < UStruct > ( Object ) ;
Tooltip = Struct ? Struct - > GetToolTipText ( ) : FText : : GetEmpty ( ) ;
}
} ;
struct FTypesDatabase
{
typedef TSharedPtr < TArray < FLoadedAssetData > > FLoadedTypesList ;
TMap < FString , FLoadedTypesList > LoadedTypesMap ;
typedef TSharedPtr < TArray < FUnloadedAssetData > > FUnLoadedTypesList ;
TMap < FString , FUnLoadedTypesList > UnLoadedTypesMap ;
} ;
2014-11-13 10:35:54 -05:00
/** Helper class to gather variable types */
class FGatherTypesHelper
2014-04-23 20:18:55 -04:00
{
2014-11-13 10:35:54 -05:00
private :
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-11-13 10:35:54 -05:00
public :
2015-07-02 10:25:42 -04:00
static void FillLoadedTypesDatabase ( FTypesDatabase & TypesDatabase , bool bIndexTypesOnly )
2015-05-28 03:57:54 -04:00
{
// Loaded types
TypesDatabase . LoadedTypesMap . Reset ( ) ;
//(Type == UEdGraphSchema_K2::PC_Enum)
{
FTypesDatabase : : FLoadedTypesList LoadedTypesList = MakeShareable ( new TArray < FLoadedAssetData > ( ) ) ;
// 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 ) )
{
LoadedTypesList - > Add ( FLoadedAssetData ( CurrentEnum ) ) ;
}
}
TypesDatabase . LoadedTypesMap . Add ( UEdGraphSchema_K2 : : PC_Enum , LoadedTypesList ) ;
}
2015-07-02 10:25:42 -04:00
if ( ! bIndexTypesOnly )
{
//(Type == UEdGraphSchema_K2::PC_Struct)
{
FTypesDatabase : : FLoadedTypesList LoadedTypesList = MakeShareable ( new TArray < FLoadedAssetData > ( ) ) ;
// 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 ) )
{
LoadedTypesList - > Add ( FLoadedAssetData ( ScriptStruct ) ) ;
}
}
TypesDatabase . LoadedTypesMap . Add ( UEdGraphSchema_K2 : : PC_Struct , LoadedTypesList ) ;
}
//(Type == UEdGraphSchema_K2::PC_Class || Type == UEdGraphSchema_K2::PC_AssetClass) UEdGraphSchema_K2::PC_Interface)
//(Type == UEdGraphSchema_K2::PC_Object || Type == UEdGraphSchema_K2::PC_Asset)
{
FTypesDatabase : : FLoadedTypesList InterfaceLoadedTypesList = MakeShareable ( new TArray < FLoadedAssetData > ( ) ) ;
FTypesDatabase : : FLoadedTypesList AllObjectLoadedTypesList = MakeShareable ( new TArray < FLoadedAssetData > ( ) ) ;
// Generate a list of all potential objects which have "BlueprintType=true" in their metadata
for ( TObjectIterator < UClass > ClassIt ; ClassIt ; + + ClassIt )
{
UClass * CurrentClass = * ClassIt ;
const bool bIsInterface = CurrentClass - > IsChildOf ( UInterface : : StaticClass ( ) ) ;
const bool bIsBlueprintType = UEdGraphSchema_K2 : : IsAllowableBlueprintVariableType ( CurrentClass ) ;
const bool bIsDeprecated = CurrentClass - > HasAnyClassFlags ( CLASS_Deprecated ) ;
if ( bIsBlueprintType & & ! bIsDeprecated )
{
if ( bIsInterface )
{
InterfaceLoadedTypesList - > Add ( FLoadedAssetData ( CurrentClass ) ) ;
}
else
{
AllObjectLoadedTypesList - > Add ( FLoadedAssetData ( CurrentClass , static_cast < uint8 > ( EObjectReferenceType : : AllTypes ) ) ) ;
}
}
}
TypesDatabase . LoadedTypesMap . Add ( UEdGraphSchema_K2 : : AllObjectTypes , AllObjectLoadedTypesList ) ;
TypesDatabase . LoadedTypesMap . Add ( UEdGraphSchema_K2 : : PC_Interface , InterfaceLoadedTypesList ) ;
}
}
2015-05-28 03:57:54 -04:00
}
2015-07-02 10:25:42 -04:00
static void FillUnLoadedTypesDatabase ( FTypesDatabase & TypesDatabase , bool bIndexTypesOnly )
2015-05-28 03:57:54 -04:00
{
// Loaded types
TypesDatabase . UnLoadedTypesMap . Reset ( ) ;
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
{
TArray < FAssetData > AssetData ;
AssetRegistryModule . Get ( ) . GetAssetsByClass ( UUserDefinedEnum : : StaticClass ( ) - > GetFName ( ) , AssetData ) ;
FTypesDatabase : : FUnLoadedTypesList UnLoadedTypesList = MakeShareable ( new TArray < FUnloadedAssetData > ( ) ) ;
for ( int32 AssetIndex = 0 ; AssetIndex < AssetData . Num ( ) ; + + AssetIndex )
{
const FAssetData & Asset = AssetData [ AssetIndex ] ;
if ( Asset . IsValid ( ) & & ! Asset . IsAssetLoaded ( ) )
{
UnLoadedTypesList - > Add ( FUnloadedAssetData ( Asset ) ) ;
}
}
TypesDatabase . UnLoadedTypesMap . Add ( UEdGraphSchema_K2 : : PC_Enum , UnLoadedTypesList ) ;
}
2015-07-02 10:25:42 -04:00
if ( ! bIndexTypesOnly )
2015-05-28 03:57:54 -04:00
{
{
2015-07-02 10:25:42 -04:00
TArray < FAssetData > AssetData ;
AssetRegistryModule . Get ( ) . GetAssetsByClass ( UUserDefinedStruct : : StaticClass ( ) - > GetFName ( ) , AssetData ) ;
2015-05-28 03:57:54 -04:00
2015-07-02 10:25:42 -04:00
FTypesDatabase : : FUnLoadedTypesList UnLoadedTypesList = MakeShareable ( new TArray < FUnloadedAssetData > ( ) ) ;
for ( int32 AssetIndex = 0 ; AssetIndex < AssetData . Num ( ) ; + + AssetIndex )
2015-05-28 03:57:54 -04:00
{
2015-07-02 10:25:42 -04:00
const FAssetData & Asset = AssetData [ AssetIndex ] ;
if ( Asset . IsValid ( ) & & ! Asset . IsAssetLoaded ( ) )
2015-05-28 03:57:54 -04:00
{
2015-07-02 10:25:42 -04:00
UnLoadedTypesList - > Add ( FUnloadedAssetData ( Asset ) ) ;
}
}
2015-05-28 03:57:54 -04:00
2015-07-02 10:25:42 -04:00
TypesDatabase . UnLoadedTypesMap . Add ( UEdGraphSchema_K2 : : PC_Struct , UnLoadedTypesList ) ;
}
//else if (Schema->PC_Object == CategoryName || Schema->PC_Class == CategoryName || Schema->PC_Interface == CategoryName || Schema->PC_Asset == CategoryName || Schema->PC_AssetClass == CategoryName)
{
TArray < FAssetData > AssetData ;
AssetRegistryModule . Get ( ) . GetAssetsByClass ( UBlueprint : : StaticClass ( ) - > GetFName ( ) , AssetData ) ;
const FString BPInterfaceTypeAllowed ( TEXT ( " BPTYPE_Interface " ) ) ;
const FString BPNormalTypeAllowed ( TEXT ( " BPTYPE_Normal " ) ) ;
FTypesDatabase : : FUnLoadedTypesList UnLoadedInterfacesList = MakeShareable ( new TArray < FUnloadedAssetData > ( ) ) ;
FTypesDatabase : : FUnLoadedTypesList UnLoadedClassesList = MakeShareable ( new TArray < FUnloadedAssetData > ( ) ) ;
for ( int32 AssetIndex = 0 ; AssetIndex < AssetData . Num ( ) ; + + AssetIndex )
{
const FAssetData & Asset = AssetData [ AssetIndex ] ;
if ( Asset . IsValid ( ) & & ! Asset . IsAssetLoaded ( ) )
{
const FString * BlueprintTypeStr = Asset . TagsAndValues . Find ( " BlueprintType " ) ;
const bool bNormalBP = BlueprintTypeStr & & ( * BlueprintTypeStr = = BPNormalTypeAllowed ) ;
const bool bInterfaceBP = BlueprintTypeStr & & ( * BlueprintTypeStr = = BPInterfaceTypeAllowed ) ;
if ( bNormalBP | | bInterfaceBP )
2015-05-28 03:57:54 -04:00
{
2015-07-02 10:25:42 -04:00
uint32 ClassFlags = 0 ;
const FString * ClassFlagsStr = Asset . TagsAndValues . Find ( " ClassFlags " ) ;
if ( ClassFlagsStr )
2015-05-28 03:57:54 -04:00
{
2015-07-02 10:25:42 -04:00
ClassFlags = FCString : : Atoi ( * * ClassFlagsStr ) ;
2015-05-28 03:57:54 -04:00
}
2015-07-02 10:25:42 -04:00
if ( ! ( ClassFlags & CLASS_Deprecated ) )
2015-05-28 03:57:54 -04:00
{
2015-07-02 10:25:42 -04:00
if ( bNormalBP )
{
UnLoadedClassesList - > Add ( FUnloadedAssetData ( Asset , static_cast < uint8 > ( EObjectReferenceType : : AllTypes ) ) ) ;
}
else if ( bInterfaceBP )
{
UnLoadedInterfacesList - > Add ( FUnloadedAssetData ( Asset ) ) ;
}
2015-05-28 03:57:54 -04:00
}
}
}
}
2015-07-02 10:25:42 -04:00
TypesDatabase . UnLoadedTypesMap . Add ( UEdGraphSchema_K2 : : PC_Interface , UnLoadedInterfacesList ) ;
TypesDatabase . UnLoadedTypesMap . Add ( UEdGraphSchema_K2 : : AllObjectTypes , UnLoadedClassesList ) ;
2015-05-28 03:57:54 -04:00
}
}
}
2015-07-02 10:25:42 -04:00
/**
* Gathers all valid sub - types ( loaded and unloaded ) of a passed category and sorts them alphabetically
* @ param FriendlyName Friendly name to be used for the tooltip if there is no available data
* @ param CategoryName Category ( type ) to find sub - types of
* @ param TypesDatabase Types database
* @ param OutChildren All the gathered children
*/
2015-05-28 03:57:54 -04:00
static void Gather ( const FText & FriendlyName , const FString & CategoryName , FTypesDatabase & TypesDatabase , TArray < FPinTypeTreeInfoPtr > & OutChildren )
{
FEdGraphPinType LoadedPinSubtype ;
LoadedPinSubtype . PinCategory = ( CategoryName = = UEdGraphSchema_K2 : : PC_Enum ? UEdGraphSchema_K2 : : PC_Byte : CategoryName ) ;
LoadedPinSubtype . PinSubCategory = TEXT ( " " ) ;
LoadedPinSubtype . PinSubCategoryObject = NULL ;
auto LoadedSubTypesPtr = TypesDatabase . LoadedTypesMap . Find ( CategoryName ) ;
if ( LoadedSubTypesPtr & & LoadedSubTypesPtr - > IsValid ( ) )
{
for ( auto LoadedAssetData : * LoadedSubTypesPtr - > Get ( ) )
{
2015-07-02 10:25:42 -04:00
OutChildren . Add ( MakeShareable ( new UEdGraphSchema_K2 : : FPinTypeTreeInfo ( LoadedPinSubtype . PinCategory
, LoadedAssetData . Object
, LoadedAssetData . Tooltip . IsEmpty ( ) ? FriendlyName : LoadedAssetData . Tooltip
, false
, LoadedAssetData . PossibleObjectReferenceTypes ) ) ) ;
2015-05-28 03:57:54 -04:00
}
}
auto UnLoadedSubTypesPtr = TypesDatabase . UnLoadedTypesMap . Find ( CategoryName ) ;
if ( UnLoadedSubTypesPtr & & UnLoadedSubTypesPtr - > IsValid ( ) )
{
for ( FUnloadedAssetData & It : * UnLoadedSubTypesPtr - > Get ( ) )
{
2015-07-02 10:25:42 -04:00
FPinTypeTreeInfoPtr TypeTreeInfo = MakeShareable ( new UEdGraphSchema_K2 : : FPinTypeTreeInfo ( It . AssetFriendlyName
, CategoryName
, It . StringAssetReference
, It . Tooltip
, false
, It . PossibleObjectReferenceTypes ) ) ;
2015-05-28 03:57:54 -04:00
OutChildren . Add ( TypeTreeInfo ) ;
}
}
OutChildren . Sort ( FCompareChildren ( ) ) ;
}
2014-11-13 10:35:54 -05:00
/** Loads an asset based on the AssetReference through the asset registry */
2014-04-23 20:18:55 -04:00
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 ( ) ;
}
2014-11-13 10:35:54 -05:00
return nullptr ;
2014-04-23 20:18:55 -04:00
}
} ;
const FEdGraphPinType & UEdGraphSchema_K2 : : FPinTypeTreeInfo : : GetPinType ( bool bForceLoadedSubCategoryObject )
{
2014-11-13 10:35:54 -05:00
if ( bForceLoadedSubCategoryObject )
2014-04-23 20:18:55 -04:00
{
2014-11-13 10:35:54 -05:00
// Only attempt to load the sub category object if we need to
if ( SubCategoryObjectAssetReference . IsValid ( ) & & ( ! PinType . PinSubCategoryObject . IsValid ( ) | | FStringAssetReference ( PinType . PinSubCategoryObject . Get ( ) ) ! = SubCategoryObjectAssetReference ) )
{
UObject * LoadedObject = FGatherTypesHelper : : LoadAsset ( SubCategoryObjectAssetReference ) ;
if ( UBlueprint * BlueprintObject = Cast < UBlueprint > ( LoadedObject ) )
{
PinType . PinSubCategoryObject = * BlueprintObject - > GeneratedClass ;
}
else
{
PinType . PinSubCategoryObject = LoadedObject ;
}
}
}
else
{
if ( SubCategoryObjectAssetReference . IsValid ( ) )
{
const FAssetRegistryModule & AssetRegistryModule = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
const FAssetData AssetData = AssetRegistryModule . Get ( ) . GetAssetByObjectPath ( * SubCategoryObjectAssetReference . ToString ( ) ) ;
if ( ! AssetData . IsAssetLoaded ( ) )
{
UObject * LoadedObject = FindObject < UClass > ( ANY_PACKAGE , * AssetData . AssetClass . ToString ( ) ) ;
// If the unloaded asset is a Blueprint, we need to pull the generated class and assign that
if ( UBlueprint * BlueprintObject = Cast < UBlueprint > ( LoadedObject ) )
{
PinType . PinSubCategoryObject = * BlueprintObject - > GeneratedClass ;
}
else
{
PinType . PinSubCategoryObject = LoadedObject ;
}
}
else
{
PinType . PinSubCategoryObject = AssetData . GetAsset ( ) ;
}
}
2014-04-23 20:18:55 -04:00
}
return PinType ;
}
2015-05-28 03:57:54 -04:00
void UEdGraphSchema_K2 : : FPinTypeTreeInfo : : Init ( const FText & InFriendlyName , const FString & CategoryName , const UEdGraphSchema_K2 * Schema , const FText & InTooltip , bool bInReadOnly , FTypesDatabase * TypesDatabase )
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-11-13 10:35:54 -05:00
PinType . PinCategory = ( CategoryName = = PC_Enum ? PC_Byte : CategoryName ) ;
2014-03-14 14:13:41 -04:00
PinType . PinSubCategory = TEXT ( " " ) ;
PinType . PinSubCategoryObject = NULL ;
bReadOnly = bInReadOnly ;
2015-05-28 03:57:54 -04:00
CachedDescription = GenerateDescription ( ) ;
2014-09-08 12:56:34 -04:00
if ( Schema - > DoesTypeHaveSubtypes ( CategoryName ) )
2014-03-14 14:13:41 -04:00
{
2015-05-28 03:57:54 -04:00
if ( TypesDatabase )
{
FGatherTypesHelper : : Gather ( InFriendlyName , CategoryName , * TypesDatabase , Children ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2015-07-02 10:25:42 -04:00
UEdGraphSchema_K2 : : FPinTypeTreeInfo : : FPinTypeTreeInfo ( const FString & CategoryName , UObject * SubCategoryObject , const FText & InTooltip , bool bInReadOnly /*=false*/ , uint8 InPossibleObjectReferenceTypes )
: PossibleObjectReferenceTypes ( InPossibleObjectReferenceTypes )
2014-03-14 14:13:41 -04:00
{
check ( ! CategoryName . IsEmpty ( ) ) ;
check ( SubCategoryObject ) ;
Tooltip = InTooltip ;
PinType . PinCategory = CategoryName ;
PinType . PinSubCategoryObject = SubCategoryObject ;
bReadOnly = bInReadOnly ;
2015-05-28 03:57:54 -04:00
CachedDescription = GenerateDescription ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-07-02 10:25:42 -04:00
UEdGraphSchema_K2 : : FPinTypeTreeInfo : : FPinTypeTreeInfo ( const FText & InFriendlyName , const FString & CategoryName , const FStringAssetReference & SubCategoryObject , const FText & InTooltip , bool bInReadOnly , uint8 InPossibleObjectReferenceTypes )
: PossibleObjectReferenceTypes ( InPossibleObjectReferenceTypes )
2015-05-29 11:14:00 -04:00
{
FriendlyName = InFriendlyName ;
check ( ! CategoryName . IsEmpty ( ) ) ;
check ( SubCategoryObject . IsValid ( ) ) ;
Tooltip = InTooltip ;
PinType . PinCategory = CategoryName ;
SubCategoryObjectAssetReference = SubCategoryObject ;
PinType . PinSubCategoryObject = SubCategoryObjectAssetReference . ResolveObject ( ) ;
bReadOnly = bInReadOnly ;
2015-05-28 03:57:54 -04:00
CachedDescription = GenerateDescription ( ) ;
2014-04-23 20:18:55 -04:00
}
2015-05-28 03:57:54 -04:00
FText UEdGraphSchema_K2 : : FPinTypeTreeInfo : : GenerateDescription ( )
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 ( ) )
{
2015-02-06 04:43:02 -05:00
FText DisplayName ;
2015-04-09 12:18:12 -04:00
if ( UField * SubCategoryField = Cast < UField > ( PinType . PinSubCategoryObject . Get ( ) ) )
2014-08-01 11:07:59 -04:00
{
2015-04-09 12:18:12 -04:00
DisplayName = SubCategoryField - > GetDisplayNameText ( ) ;
2015-02-06 04:43:02 -05:00
}
else
{
2015-04-09 12:18:12 -04:00
DisplayName = FText : : FromString ( FName : : NameToDisplayString ( PinType . PinSubCategoryObject - > GetName ( ) , PinType . PinCategory = = PC_Boolean ) ) ;
2014-08-01 11:07:59 -04:00
}
2015-02-06 04:43:02 -05:00
return 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
}
}
2015-05-28 03:57:54 -04:00
FText UEdGraphSchema_K2 : : FPinTypeTreeInfo : : GetDescription ( ) const
{
return CachedDescription ;
}
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 " ) ) ;
2014-11-13 10:35:54 -05:00
const FString UEdGraphSchema_K2 : : PC_Enum ( TEXT ( " enum " ) ) ;
2015-05-15 16:44:55 -04:00
const FString UEdGraphSchema_K2 : : PC_Asset ( TEXT ( " asset " ) ) ;
const FString UEdGraphSchema_K2 : : PC_AssetClass ( TEXT ( " assetclass " ) ) ;
2014-09-04 13:55:54 -04:00
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 " ) ) ;
2015-05-08 10:46:42 -04:00
const FText UEdGraphSchema_K2 : : VR_DefaultCategory ( LOCTEXT ( " Default " , " Default " ) ) ;
2014-09-04 13:55:54 -04:00
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 ;
2015-04-02 11:16:23 -04:00
int32 UEdGraphSchema_K2 : : CurrentCacheRefreshID = 0 ;
2014-09-05 17:51:04 -04:00
2015-07-02 10:25:42 -04:00
const FString UEdGraphSchema_K2 : : AllObjectTypes ( TEXT ( " ObjectTypes " ) ) ;
2014-10-14 10:29:11 -04:00
UEdGraphSchema_K2 : : UEdGraphSchema_K2 ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
2014-09-04 17:31:51 -04:00
// Initialize cached static references to well-known struct types
if ( VectorStruct = = nullptr )
{
2015-05-05 23:07:23 -04:00
VectorStruct = TBaseStructure < FVector > : : Get ( ) ;
RotatorStruct = TBaseStructure < FRotator > : : Get ( ) ;
TransformStruct = TBaseStructure < FTransform > : : Get ( ) ;
LinearColorStruct = TBaseStructure < FLinearColor > : : Get ( ) ;
ColorStruct = TBaseStructure < FColor > : : Get ( ) ;
2014-09-04 17:31:51 -04:00
}
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 ;
}
2015-04-16 11:47:54 -04:00
bool UEdGraphSchema_K2 : : CanFunctionBeUsedInGraph ( const UClass * InClass , const UFunction * InFunction , const UEdGraph * InDestGraph , uint32 InAllowedFunctionTypes , bool bInCalledForEach , 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 ) )
{
2015-05-19 16:42:30 -04:00
const FString & ContextParam = InFunction - > GetMetaData ( FBlueprintMetadata : : MD_WorldContext ) ;
if ( InFunction - > FindPropertyByName ( FName ( * ContextParam ) ) ! = nullptr )
2014-09-10 16:39:25 -04:00
{
2015-05-19 16:42:30 -04:00
auto BP = FBlueprintEditorUtils : : FindBlueprintForGraph ( InDestGraph ) ;
const bool bIsFunctLib = BP & & ( EBlueprintType : : BPTYPE_FunctionLibrary = = BP - > BlueprintType ) ;
UClass * ParentClass = BP ? BP - > ParentClass : NULL ;
const bool bIncompatibleParrent = ParentClass & & ( ! ParentClass - > GetDefaultObject ( ) - > ImplementsGetWorld ( ) & & ! ParentClass - > HasMetaData ( FBlueprintMetadata : : MD_ShowWorldContextPin ) ) ;
if ( ! bIsFunctLib & & bIncompatibleParrent )
2014-10-07 00:54:59 -04:00
{
2015-05-19 16:42:30 -04:00
if ( OutReason ! = nullptr )
{
* OutReason = LOCTEXT ( " FunctionRequiresWorldContext " , " Function requires a world context. " ) ;
}
2014-10-07 00:54:59 -04:00
2015-05-19 16:42:30 -04:00
return false ;
}
}
2014-09-10 16:39:25 -04:00
}
}
2014-03-14 14:13:41 -04:00
const bool bFunctionStatic = InFunction - > HasAllFunctionFlags ( FUNC_Static ) ;
const bool bHasReturnParams = ( InFunction - > GetReturnProperty ( ) ! = NULL ) ;
2015-04-21 14:12:38 -04:00
const bool bHasArrayPointerParms = InFunction - > HasMetaData ( FBlueprintMetadata : : MD_ArrayParam ) ;
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
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
{
2015-02-06 09:41:28 -05:00
if ( Function & & Cast < UClass > ( Function - > GetOuter ( ) ) )
2014-03-14 14:13:41 -04:00
{
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
}
2015-02-21 19:06:39 -05:00
bool UEdGraphSchema_K2 : : HasFunctionAnyOutputParameter ( const UFunction * InFunction )
2014-03-14 14:13:41 -04:00
{
2015-02-21 19:06:39 -05:00
check ( InFunction ) ;
for ( TFieldIterator < UProperty > PropIt ( InFunction ) ; PropIt & & ( PropIt - > PropertyFlags & CPF_Parm ) ; + + PropIt )
2014-03-14 14:13:41 -04:00
{
2015-02-21 19:06:39 -05:00
UProperty * FuncParam = * PropIt ;
if ( FuncParam - > HasAnyPropertyFlags ( CPF_ReturnParm ) | | ( FuncParam - > HasAnyPropertyFlags ( CPF_OutParm ) & & ! FuncParam - > HasAnyPropertyFlags ( CPF_ReferenceParm ) & & ! FuncParam - > HasAnyPropertyFlags ( CPF_ConstParm ) ) )
2014-03-14 14:13:41 -04:00
{
2015-02-21 19:06:39 -05:00
return true ;
2014-03-14 14:13:41 -04:00
}
}
2015-02-21 19:06:39 -05:00
return false ;
}
2014-03-14 14:13:41 -04:00
bool UEdGraphSchema_K2 : : FunctionCanBePlacedAsEvent ( const UFunction * InFunction )
{
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
// First check we are override-able, non-static and non-const
if ( ! InFunction | | ! CanKismetOverrideFunction ( InFunction ) | | InFunction - > HasAnyFunctionFlags ( FUNC_Static | FUNC_Const ) )
2014-03-14 14:13:41 -04:00
{
return false ;
}
// Then look to see if we have any output, return, or reference params
2015-02-21 19:06:39 -05:00
return ! HasFunctionAnyOutputParameter ( InFunction ) ;
2014-03-14 14:13:41 -04:00
}
bool UEdGraphSchema_K2 : : FunctionCanBeUsedInDelegate ( const UFunction * InFunction )
{
if ( ! InFunction | |
! CanUserKismetCallFunction ( InFunction ) | |
InFunction - > HasMetaData ( FBlueprintMetadata : : MD_Latent ) | |
InFunction - > HasAllFunctionFlags ( FUNC_BlueprintPure ) )
{
return false ;
}
2015-02-21 19:06:39 -05:00
return true ;
2014-03-14 14:13:41 -04:00
}
2015-03-27 12:54:58 -04:00
FText 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 ) ;
2015-03-02 15:51:37 -05:00
MetaData . ParseIntoArray ( AutoEmitParameterNames , TEXT ( " , " ) , true ) ;
2014-03-14 14:13:41 -04:00
}
}
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
bool UEdGraphSchema_K2 : : FunctionHasParamOfType ( const UFunction * InFunction , UEdGraph const * InGraph , const FEdGraphPinType & DesiredPinType , bool bWantOutput ) const
2014-03-14 14:13:41 -04:00
{
TSet < FString > HiddenPins ;
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
FBlueprintEditorUtils : : GetHiddenPinsForFunction ( InGraph , InFunction , HiddenPins ) ;
2014-03-14 14:13:41 -04:00
// 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 ) )
{
2015-07-28 16:17:47 -04:00
Node - > SetExtraFlags ( Node - > GetFunctionFlags ( ) | ExtraFlags ) ;
2014-03-14 14:13:41 -04:00
}
}
}
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
}
}
}
2015-01-08 11:39:23 -05:00
bool UEdGraphSchema_K2 : : IsActorValidForLevelScriptRefs ( const AActor * TestActor , const UBlueprint * Blueprint ) const
2014-03-14 14:13:41 -04:00
{
check ( Blueprint ) ;
2015-01-09 13:46:34 -05:00
2014-03-14 14:13:41 -04:00
return TestActor
2015-01-09 13:46:34 -05:00
& & FBlueprintEditorUtils : : IsLevelScriptBlueprint ( Blueprint )
2015-01-08 11:39:23 -05:00
& & ( TestActor - > GetLevel ( ) = = FBlueprintEditorUtils : : GetLevelFromBlueprint ( Blueprint ) )
2014-03-14 14:13:41 -04:00
& & 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 ) ;
2015-01-13 10:30:34 -05:00
LiteralNode - > ReconstructNode ( ) ;
2014-03-14 14:13:41 -04:00
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( CastChecked < UEdGraph > ( SourceNode - > GetOuter ( ) ) ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
}
}
void UEdGraphSchema_K2 : : AddSelectedReplaceableNodes ( UBlueprint * Blueprint , const UEdGraphNode * InGraphNode , FMenuBuilder * MenuBuilder ) const
{
2015-01-08 11:39:23 -05:00
//Only allow replace object reference functionality for literal nodes
const UK2Node_Literal * LiteralNode = Cast < UK2Node_Literal > ( InGraphNode ) ;
if ( LiteralNode )
2014-03-14 14:13:41 -04:00
{
2015-01-08 11:39:23 -05:00
USelection * SelectedActors = GEditor - > GetSelectedActors ( ) ;
for ( FSelectionIterator Iter ( * SelectedActors ) ; Iter ; + + Iter )
2014-03-14 14:13:41 -04:00
{
2015-01-08 11:39:23 -05:00
// 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 , Blueprint ) )
2014-03-14 14:13:41 -04:00
{
2015-01-08 11:39:23 -05:00
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 ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
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
2015-03-12 14:17:48 -04:00
UStruct * MemberScope = Variable - > VariableReference . GetMemberScope ( Variable - > GetBlueprintClassFromNode ( ) ) ;
if ( MemberScope = = nullptr | | ! FBlueprintEditorUtils : : FindLocalVariable ( OwnerBlueprint , MemberScope , 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 )
{
2015-06-24 11:23:23 -04:00
bCanSplit = UK2Node_MakeStruct : : CanBeMade ( StructType , true , true ) ;
2014-06-16 11:10:42 -04:00
if ( ! bCanSplit )
{
const FString & MetaData = StructType - > GetMetaData ( TEXT ( " HasNativeMake " ) ) ;
UFunction * Function = FindObject < UFunction > ( NULL , * MetaData , true ) ;
bCanSplit = ( Function ! = NULL ) ;
}
}
else
{
2015-06-24 11:23:23 -04:00
bCanSplit = UK2Node_BreakStruct : : CanBeBroken ( StructType , true , true ) ;
2014-06-16 11:10:42 -04:00
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
2014-12-04 15:44:12 -05:00
| | & SubCategoryObject = = ColorStruct
| | & SubCategoryObject = = FCollisionProfileName : : StaticStruct ( ) ;
2014-07-14 17:15:42 -04:00
}
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 ) ;
2015-06-11 15:39:07 -04:00
if ( FBlueprintEditorUtils : : DoesSupportLocalVariables ( CurrentGraph ) )
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . PromoteToLocalVariable ) ;
}
2014-07-08 18:23:43 -04:00
}
2015-06-24 11:23:23 -04:00
if ( InGraphPin - > PinType . PinCategory = = PC_Struct & & InGraphNode - > AllowSplitPins ( ) )
2014-05-08 15:03:09 -04:00
{
2015-06-24 11:23:23 -04:00
// If the pin cannot be split, create an error tooltip to use
FText Tooltip ;
if ( PinHasSplittableStructType ( InGraphPin ) )
{
Tooltip = FGraphEditorCommands : : Get ( ) . SplitStructPin - > GetDescription ( ) ;
}
else
{
Tooltip = LOCTEXT ( " SplitStructPin_Error " , " Cannot split the struct pin, it may be missing Blueprint exposed properties! " ) ;
}
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . SplitStructPin , NAME_None , FGraphEditorCommands : : Get ( ) . SplitStructPin - > GetLabel ( ) , Tooltip ) ;
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 ) ;
// 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 ) ;
}
// 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
}
2015-06-01 14:36:32 -04:00
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . FindReferences ) ;
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 ( ) ) )
{
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 ) ;
}
2015-08-14 09:34:31 -04:00
2015-08-14 10:20:02 -04:00
MenuBuilder - > AddSubMenu ( LOCTEXT ( " AlignmentHeader " , " Alignment " ) , FText ( ) , FNewMenuDelegate : : CreateLambda ( [ ] ( FMenuBuilder & InMenuBuilder ) {
2015-08-14 09:34:31 -04:00
2015-08-14 10:20:02 -04:00
InMenuBuilder . BeginSection ( " EdGraphSchemaAlignment " , LOCTEXT ( " AlignHeader " , " Align " ) ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AlignNodesTop ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AlignNodesMiddle ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AlignNodesBottom ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AlignNodesLeft ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AlignNodesCenter ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . AlignNodesRight ) ;
InMenuBuilder . EndSection ( ) ;
2015-08-14 09:34:31 -04:00
2015-08-14 10:20:02 -04:00
InMenuBuilder . BeginSection ( " EdGraphSchemaDistribution " , LOCTEXT ( " DistributionHeader " , " Distribution " ) ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . DistributeNodesHorizontally ) ;
InMenuBuilder . AddMenuEntry ( FGraphEditorCommands : : Get ( ) . DistributeNodesVertically ) ;
InMenuBuilder . EndSection ( ) ;
2015-08-14 09:34:31 -04:00
} ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-08-14 09:34:31 -04:00
2014-03-14 14:13:41 -04:00
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
}
}
2015-04-09 11:34:39 -04:00
MenuBuilder - > BeginSection ( " EdGraphSchemaDocumentation " , LOCTEXT ( " DocumentationHeader " , " Documentation " ) ) ;
{
MenuBuilder - > AddMenuEntry ( FGraphEditorCommands : : Get ( ) . GoToDocumentation ) ;
}
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
{
2015-02-26 13:07:09 -05:00
UEdGraph * FunctionGraph = FBlueprintEditorUtils : : GetTopLevelGraph ( Variable - > GetGraph ( ) ) ;
Variable - > VariableReference . SetLocalMember ( FName ( * VariableName ) , FunctionGraph - > GetName ( ) , FBlueprintEditorUtils : : FindLocalVariableGuidByName ( OwnerBlueprint , FunctionGraph , * VariableName ) ) ;
2014-10-07 16:04:29 -04:00
}
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 (
2015-04-22 17:04:42 -04:00
FExecuteAction : : CreateUObject ( this , & UEdGraphSchema_K2 : : BreakSinglePinLink , const_cast < UEdGraphPin * > ( InGraphPin ) , * Links ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
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
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 ( " " ) ) ;
}
}
2014-10-30 12:46:32 -04:00
static FText GetPinIncompatibilityMessage ( const UEdGraphPin * PinA , const UEdGraphPin * PinB )
{
const FEdGraphPinType & PinAType = PinA - > PinType ;
const FEdGraphPinType & PinBType = PinB - > PinType ;
FFormatNamedArguments MessageArgs ;
MessageArgs . Add ( TEXT ( " PinAName " ) , PinA - > GetDisplayName ( ) ) ;
MessageArgs . Add ( TEXT ( " PinBName " ) , PinB - > GetDisplayName ( ) ) ;
MessageArgs . Add ( TEXT ( " PinAType " ) , UEdGraphSchema_K2 : : TypeToText ( PinAType ) ) ;
MessageArgs . Add ( TEXT ( " PinBType " ) , UEdGraphSchema_K2 : : TypeToText ( PinBType ) ) ;
const UEdGraphPin * InputPin = ( PinA - > Direction = = EGPD_Input ) ? PinA : PinB ;
const FEdGraphPinType & InputType = InputPin - > PinType ;
const UEdGraphPin * OutputPin = ( InputPin = = PinA ) ? PinB : PinA ;
const FEdGraphPinType & OutputType = OutputPin - > PinType ;
FText MessageFormat = LOCTEXT ( " DefaultPinIncompatibilityMessage " , " {PinAType} is not compatible with {PinBType}. " ) ;
if ( OutputType . PinCategory = = UEdGraphSchema_K2 : : PC_Struct )
{
if ( InputType . PinCategory = = UEdGraphSchema_K2 : : PC_Struct )
{
MessageFormat = LOCTEXT ( " StructsIncompatible " , " Only exactly matching structures are considered compatible. " ) ;
2014-11-03 10:42:15 -05:00
const UStruct * OutStruct = Cast < const UStruct > ( OutputType . PinSubCategoryObject . Get ( ) ) ;
const UStruct * InStruct = Cast < const UStruct > ( InputType . PinSubCategoryObject . Get ( ) ) ;
2014-10-30 12:46:32 -04:00
if ( ( OutStruct ! = nullptr ) & & ( InStruct ! = nullptr ) & & OutStruct - > IsChildOf ( InStruct ) )
{
MessageFormat = LOCTEXT ( " ChildStructIncompatible " , " Only exactly matching structures are considered compatible. Derived structures are disallowed. " ) ;
}
}
}
else if ( OutputType . PinCategory = = UEdGraphSchema_K2 : : PC_Class )
{
if ( ( InputType . PinCategory = = UEdGraphSchema_K2 : : PC_Object ) | |
( InputType . PinCategory = = UEdGraphSchema_K2 : : PC_Interface ) )
{
MessageArgs . Add ( TEXT ( " OutputName " ) , OutputPin - > GetDisplayName ( ) ) ;
MessageArgs . Add ( TEXT ( " InputName " ) , InputPin - > GetDisplayName ( ) ) ;
MessageFormat = LOCTEXT ( " ClassObjectIncompatible " , " '{PinAName}' and '{PinBName}' are incompatible ('{OutputName}' is an object type, and '{InputName}' is a reference to an object instance). " ) ;
}
}
else if ( ( OutputType . PinCategory = = UEdGraphSchema_K2 : : PC_Object ) ) //|| (OutputType.PinCategory == UEdGraphSchema_K2::PC_Interface))
{
if ( InputType . PinCategory = = UEdGraphSchema_K2 : : PC_Class )
{
MessageArgs . Add ( TEXT ( " OutputName " ) , OutputPin - > GetDisplayName ( ) ) ;
MessageArgs . Add ( TEXT ( " InputName " ) , InputPin - > GetDisplayName ( ) ) ;
MessageArgs . Add ( TEXT ( " InputType " ) , UEdGraphSchema_K2 : : TypeToText ( InputType ) ) ;
MessageFormat = LOCTEXT ( " CannotGetClass " , " '{PinAName}' and '{PinBName}' are not inherently compatible ('{InputName}' is an object type, and '{OutputName}' is a reference to an object instance). \n We cannot use {OutputName}'s class because it is not a child of {InputType}. " ) ;
}
}
return FText : : Format ( MessageFormat , MessageArgs ) ;
}
2014-03-14 14:13:41 -04:00
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 ;
2015-06-29 12:18:57 -04:00
UClass * DummyClass ;
2014-03-14 14:13:41 -04:00
UK2Node * DummyNode ;
2015-06-29 12:18:57 -04:00
const bool bCanAutocast = SearchForAutocastFunction ( OutputPin , InputPin , /*out*/ DummyName , DummyClass ) ;
2014-03-14 14:13:41 -04:00
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-10-30 12:46:32 -04:00
FText IncompatibilityReasonText = GetPinIncompatibilityMessage ( PinA , PinB ) ;
return FPinConnectionResponse ( CONNECT_RESPONSE_DISALLOW , IncompatibilityReasonText . 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 ) ;
2015-02-17 16:28:07 -05:00
if ( bModified & & ! PinA - > HasAnyFlags ( RF_Transient ) )
2014-03-14 14:13:41 -04:00
{
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
}
return bModified ;
}
2015-06-30 05:20:10 -04:00
struct FAutocastFunctionMap : private FNoncopyable
2015-06-29 12:18:57 -04:00
{
private :
2015-06-30 05:20:10 -04:00
static FAutocastFunctionMap * AutocastFunctionMap ;
2015-06-29 12:18:57 -04:00
TMap < FString , TWeakObjectPtr < UFunction > > InnerMap ;
2015-06-30 05:20:10 -04:00
FDelegateHandle OnHotReloadDelegateHandle ;
FDelegateHandle OnModulesChangedDelegateHandle ;
2015-06-29 12:18:57 -04:00
static FString GenerateTypeData ( const FEdGraphPinType & PinType )
{
auto Obj = PinType . PinSubCategoryObject . Get ( ) ;
return FString : : Printf ( TEXT ( " %s;%s;%s " ) , * PinType . PinCategory , * PinType . PinSubCategory , Obj ? * Obj - > GetPathName ( ) : TEXT ( " " ) ) ;
}
static FString GenerateCastData ( const FEdGraphPinType & InputPinType , const FEdGraphPinType & OutputPinType )
{
return FString : : Printf ( TEXT ( " %s;%s " ) , * GenerateTypeData ( InputPinType ) , * GenerateTypeData ( OutputPinType ) ) ;
}
2015-06-30 05:20:10 -04:00
static bool IsInputParam ( uint64 PropertyFlags )
2015-06-29 12:18:57 -04:00
{
const uint64 ConstOutParamFlag = CPF_OutParm | CPF_ConstParm ;
2015-06-30 05:20:10 -04:00
const uint64 IsConstOut = PropertyFlags & ConstOutParamFlag ;
return ( CPF_Parm = = ( PropertyFlags & ( CPF_Parm | CPF_ReturnParm ) ) )
2015-06-29 12:18:57 -04:00
& & ( ( 0 = = IsConstOut ) | | ( ConstOutParamFlag = = IsConstOut ) ) ;
}
static const UProperty * GetFirstInputProperty ( const UFunction * Function )
{
for ( auto Property : TFieldRange < const UProperty > ( Function ) )
{
2015-06-30 05:20:10 -04:00
if ( Property & & IsInputParam ( Property - > PropertyFlags ) )
2015-06-29 12:18:57 -04:00
{
return Property ;
}
}
return nullptr ;
}
void InsertFunction ( UFunction * Function , const UEdGraphSchema_K2 * Schema )
{
FEdGraphPinType InputPinType ;
Schema - > ConvertPropertyToPinType ( GetFirstInputProperty ( Function ) , InputPinType ) ;
FEdGraphPinType OutputPinType ;
Schema - > ConvertPropertyToPinType ( Function - > GetReturnProperty ( ) , OutputPinType ) ;
InnerMap . Add ( GenerateCastData ( InputPinType , OutputPinType ) , Function ) ;
}
public :
static bool IsAutocastFunction ( const UFunction * Function )
{
const FName BlueprintAutocast ( TEXT ( " BlueprintAutocast " ) ) ;
return Function
& & Function - > HasMetaData ( BlueprintAutocast )
& & Function - > HasAllFunctionFlags ( FUNC_Static | FUNC_Native | FUNC_Public | FUNC_BlueprintPure )
& & Function - > GetReturnProperty ( )
2015-06-30 05:20:10 -04:00
& & GetFirstInputProperty ( Function ) ;
2015-06-29 12:18:57 -04:00
}
void Refresh ( )
{
2015-06-30 05:20:10 -04:00
# ifdef SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME
static_assert ( false , " Macro redefinition. " ) ;
# endif
# define SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME 0
# if SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME
const auto StartTime = FPlatformTime : : Seconds ( ) ;
# endif //SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME
2015-06-29 12:18:57 -04:00
InnerMap . Empty ( ) ;
auto Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
TArray < UClass * > Libraries ;
GetDerivedClasses ( UBlueprintFunctionLibrary : : StaticClass ( ) , Libraries ) ;
for ( auto Library : Libraries )
{
2015-06-30 05:20:10 -04:00
if ( Library & & ( CLASS_Native = = ( Library - > ClassFlags & ( CLASS_Native | CLASS_Deprecated | CLASS_NewerVersionExists ) ) ) )
2015-06-29 12:18:57 -04:00
{
for ( auto Function : TFieldRange < UFunction > ( Library , EFieldIteratorFlags : : ExcludeSuper , EFieldIteratorFlags : : ExcludeDeprecated ) )
{
if ( IsAutocastFunction ( Function ) )
{
InsertFunction ( Function , Schema ) ;
}
}
}
}
2015-06-30 05:20:10 -04:00
# if SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME
const auto EndTime = FPlatformTime : : Seconds ( ) ;
UE_LOG ( LogBlueprint , Warning , TEXT ( " FAutocastFunctionMap::Refresh took %fs " ) , EndTime - StartTime ) ;
# endif //SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME
# undef SCHEMA_K2_AUTOCASTFUNCTIONMAP_LOG_TIME
2015-06-29 12:18:57 -04:00
}
2015-06-30 05:20:10 -04:00
UFunction * Find ( const FEdGraphPinType & InputPinType , const FEdGraphPinType & OutputPinType ) const
2015-06-29 12:18:57 -04:00
{
2015-06-30 05:20:10 -04:00
const TWeakObjectPtr < UFunction > * FuncPtr = InnerMap . Find ( GenerateCastData ( InputPinType , OutputPinType ) ) ;
2015-06-29 12:18:57 -04:00
return FuncPtr ? FuncPtr - > Get ( ) : nullptr ;
}
static FAutocastFunctionMap & Get ( )
{
if ( AutocastFunctionMap = = nullptr )
{
AutocastFunctionMap = new FAutocastFunctionMap ( ) ;
}
return * AutocastFunctionMap ;
}
static void OnProjectHotReloaded ( bool bWasTriggeredAutomatically )
{
2015-06-30 05:20:10 -04:00
if ( AutocastFunctionMap )
{
AutocastFunctionMap - > Refresh ( ) ;
}
}
static void OnModulesChanged ( FName ModuleThatChanged , EModuleChangeReason ReasonForChange )
{
if ( AutocastFunctionMap )
{
AutocastFunctionMap - > Refresh ( ) ;
}
2015-06-29 12:18:57 -04:00
}
FAutocastFunctionMap ( )
{
Refresh ( ) ;
IHotReloadInterface & HotReloadSupport = FModuleManager : : LoadModuleChecked < IHotReloadInterface > ( " HotReload " ) ;
2015-06-30 05:20:10 -04:00
OnHotReloadDelegateHandle = HotReloadSupport . OnHotReload ( ) . AddStatic ( & FAutocastFunctionMap : : OnProjectHotReloaded ) ;
OnModulesChangedDelegateHandle = FModuleManager : : Get ( ) . OnModulesChanged ( ) . AddStatic ( & OnModulesChanged ) ;
}
~ FAutocastFunctionMap ( )
{
if ( auto HotReloadSupport = FModuleManager : : GetModulePtr < IHotReloadInterface > ( " HotReload " ) )
{
HotReloadSupport - > OnHotReload ( ) . Remove ( OnHotReloadDelegateHandle ) ;
}
FModuleManager : : Get ( ) . OnModulesChanged ( ) . Remove ( OnModulesChangedDelegateHandle ) ;
2015-06-29 12:18:57 -04:00
}
} ;
2015-06-30 05:20:10 -04:00
FAutocastFunctionMap * FAutocastFunctionMap : : AutocastFunctionMap = nullptr ;
2015-06-29 12:18:57 -04:00
bool UEdGraphSchema_K2 : : SearchForAutocastFunction ( const UEdGraphPin * OutputPin , const UEdGraphPin * InputPin , /*out*/ FName & TargetFunction , /*out*/ UClass * & FunctionOwner ) const
2014-03-14 14:13:41 -04:00
{
// 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 ;
2015-06-30 05:20:10 -04:00
FunctionOwner = nullptr ;
2014-03-14 14:13:41 -04:00
if ( OutputPin - > PinType . bIsArray ! = InputPin - > PinType . bIsArray )
{
2015-06-30 05:20:10 -04:00
return false ;
2014-03-14 14:13:41 -04:00
}
2015-06-30 05:20:10 -04:00
// SPECIAL CASES, not supported by FAutocastFunctionMap
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-10-30 12:46:32 -04:00
else if ( OutputPin - > PinType . PinCategory = = PC_Object )
{
UClass const * OutputClass = Cast < UClass const > ( OutputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( InputPin - > PinType . PinCategory = = PC_Class )
{
UClass const * InputClass = Cast < UClass const > ( InputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( ( OutputClass ! = nullptr ) & &
( InputClass ! = nullptr ) & &
OutputClass - > IsChildOf ( InputClass ) )
{
TargetFunction = TEXT ( " GetObjectClass " ) ;
}
}
2015-02-23 18:40:19 -05:00
else if ( InputPin - > PinType . PinCategory = = PC_String )
{
TargetFunction = TEXT ( " GetDisplayName " ) ;
}
2014-10-30 12:46:32 -04:00
}
2015-06-30 05:20:10 -04:00
else if ( OutputPin - > PinType . PinCategory = = PC_Struct )
{
const UScriptStruct * OutputStructType = Cast < const UScriptStruct > ( OutputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( OutputStructType = = TBaseStructure < FRotator > : : Get ( ) )
{
const UScriptStruct * InputStructType = Cast < const UScriptStruct > ( InputPin - > PinType . PinSubCategoryObject . Get ( ) ) ;
if ( ( InputPin - > PinType . PinCategory = = PC_Struct ) & & ( InputStructType = = TBaseStructure < FTransform > : : Get ( ) ) )
{
TargetFunction = TEXT ( " MakeTransform " ) ;
}
}
}
2014-03-14 14:13:41 -04:00
2015-06-29 12:18:57 -04:00
if ( TargetFunction = = NAME_None )
{
2015-06-30 05:20:10 -04:00
const auto & AutocastFunctionMap = FAutocastFunctionMap : : Get ( ) ;
2015-06-29 12:18:57 -04:00
if ( auto Func = AutocastFunctionMap . Find ( OutputPin - > PinType , InputPin - > PinType ) )
{
TargetFunction = Func - > GetFName ( ) ;
FunctionOwner = Func - > GetOwnerClass ( ) ;
}
}
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 ( ) ) ;
2015-03-12 14:17:48 -04:00
UClass * FunctionClass = CallFunctionNode - > FunctionReference . GetMemberParentClass ( CallFunctionNode - > GetBlueprintClassFromNode ( ) ) ;
2014-03-14 14:13:41 -04:00
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 )
{
2014-12-15 15:30:07 -05:00
FEdGraphPinType const & InputType = InputPin - > PinType ;
FEdGraphPinType const & OutputType = OutputPin - > PinType ;
2014-03-14 14:13:41 -04:00
// CHECK BYTE TO ENUM CAST
2014-12-15 15:30:07 -05:00
UEnum * Enum = Cast < UEnum > ( InputType . PinSubCategoryObject . Get ( ) ) ;
const bool bInputIsEnum = ! InputType . bIsArray & & ( PC_Byte = = InputType . PinCategory ) & & Enum ;
const bool bOutputIsByte = ! OutputType . bIsArray & & ( PC_Byte = = OutputType . PinCategory ) ;
if ( bInputIsEnum & & bOutputIsByte )
2014-03-14 14:13:41 -04:00
{
bCanConvert = true ;
if ( bCreateNode )
{
auto CastByteToEnum = NewObject < UK2Node_CastByteToEnum > ( ) ;
CastByteToEnum - > Enum = Enum ;
CastByteToEnum - > bSafe = true ;
TargetNode = CastByteToEnum ;
}
}
2014-12-15 15:30:07 -05:00
else
{
UClass * InputClass = Cast < UClass > ( InputType . PinSubCategoryObject . Get ( ) ) ;
2015-05-15 16:44:55 -04:00
UClass * OutputClass = Cast < UClass > ( OutputType . PinSubCategoryObject . Get ( ) ) ;
2014-12-15 15:30:07 -05:00
if ( ( OutputType . PinCategory = = PC_Interface ) & & ( InputType . PinCategory = = PC_Object ) )
{
bCanConvert = ( InputClass & & OutputClass ) & & ( InputClass - > ImplementsInterface ( OutputClass ) | | OutputClass - > IsChildOf ( InputClass ) ) ;
}
else if ( OutputType . PinCategory = = PC_Object )
{
UBlueprintEditorSettings const * BlueprintSettings = GetDefault < UBlueprintEditorSettings > ( ) ;
if ( ( InputType . PinCategory = = PC_Object ) & & BlueprintSettings - > bAutoCastObjectConnections )
{
bCanConvert = ( InputClass & & OutputClass ) & & InputClass - > IsChildOf ( OutputClass ) ;
}
}
if ( bCanConvert & & bCreateNode )
{
UK2Node_DynamicCast * DynCastNode = NewObject < UK2Node_DynamicCast > ( ) ;
DynCastNode - > TargetType = InputClass ;
DynCastNode - > SetPurity ( true ) ;
TargetNode = DynCastNode ;
}
2015-05-15 16:44:55 -04:00
if ( ! bCanConvert & & InputClass & & OutputClass & & OutputClass - > IsChildOf ( InputClass ) )
{
2015-05-15 19:19:37 -04:00
const bool bConvertAsset = ( OutputType . PinCategory = = PC_Asset ) & & ( InputType . PinCategory = = PC_Object ) ;
const bool bConvertAssetClass = ( OutputType . PinCategory = = PC_AssetClass ) & & ( InputType . PinCategory = = PC_Class ) ;
if ( bConvertAsset | | bConvertAssetClass )
2015-05-15 16:44:55 -04:00
{
bCanConvert = true ;
if ( bCreateNode )
{
2015-05-15 19:19:37 -04:00
UK2Node_ConvertAsset * ConvertAssetNode = NewObject < UK2Node_ConvertAsset > ( ) ;
TargetNode = ConvertAssetNode ;
2015-05-15 16:44:55 -04:00
}
}
}
2014-12-15 15:30:07 -05:00
}
2014-03-14 14:13:41 -04:00
}
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 ;
2015-06-29 12:18:57 -04:00
UClass * ClassContainingConversionFunction = nullptr ;
2014-03-14 14:13:41 -04:00
TSubclassOf < UK2Node > ConversionNodeClass ;
UK2Node * TemplateConversionNode = NULL ;
2015-06-29 12:18:57 -04:00
if ( SearchForAutocastFunction ( OutputPin , InputPin , /*out*/ TargetFunctionName , /*out*/ ClassContainingConversionFunction ) )
2014-03-14 14:13:41 -04:00
{
// Create a new call function node for the casting operator
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
{
2015-06-25 04:54:12 -04:00
check ( Pin ) ;
2014-03-14 14:13:41 -04:00
2014-10-30 13:46:46 -04:00
FFormatNamedArguments MessageArgs ;
MessageArgs . Add ( TEXT ( " PinName " ) , Pin - > GetDisplayName ( ) ) ;
2015-06-25 04:54:12 -04:00
const UBlueprint * OwningBP = FBlueprintEditorUtils : : FindBlueprintForNode ( Pin - > GetOwningNodeUnchecked ( ) ) ;
if ( ! OwningBP )
{
FText MsgFormat = LOCTEXT ( " NoBlueprintFoundForPin " , " No Blueprint was found for the pin '{PinName}'. " ) ;
return FText : : Format ( MsgFormat , MessageArgs ) . ToString ( ) ;
}
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
{
2014-10-30 13:46:46 -04:00
FText MsgFormat = LOCTEXT ( " BadArrayDefaultVal " , " Array inputs (like '{PinName}') must have an input wired into them (try connecting a MakeArray node). " ) ;
return FText : : Format ( MsgFormat , MessageArgs ) . ToString ( ) ;
2014-05-29 16:49:22 -04:00
}
2014-06-16 11:10:42 -04:00
else if ( bIsReference )
2014-05-29 16:49:22 -04:00
{
2014-12-11 16:20:22 -05:00
FText MsgFormat = LOCTEXT ( " BadRefDefaultVal " , " '{PinName}' must have an input wired into it ( \" by ref \" params expect a valid input to operate on). " ) ;
2014-10-30 13:46:46 -04:00
return FText : : Format ( MsgFormat , MessageArgs ) . ToString ( ) ;
2014-05-29 16:49:22 -04:00
}
}
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
2015-06-13 09:54:57 -04:00
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNode ( Pin ? Pin - > GetOwningNodeUnchecked ( ) : nullptr ) ;
return ensure ( Blueprint ) ? FKismetDebugUtilities : : IsPinBeingWatched ( Blueprint , Pin ) : false ;
2014-03-14 14:13:41 -04:00
}
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 " ) ) ;
}
}
}
2015-05-15 16:44:55 -04:00
else if ( ( PinCategory = = PC_Class ) | | ( PinCategory = = PC_AssetClass ) )
2014-03-14 14:13:41 -04:00
{
// 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
}
2015-05-15 16:44:55 -04:00
else if ( ( PinCategory = = PC_Object ) | | ( PinCategory = = PC_Interface ) | | ( PinCategory = = PC_Asset ) )
2014-03-14 14:13:41 -04:00
{
2015-05-15 16:44:55 -04:00
if ( PinSubCategoryObject = = NULL & & ( PinSubCategory ! = PSC_Self ) )
2014-03-14 14:13:41 -04:00
{
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 ) ) ) ;
}
2015-05-15 16:44:55 -04:00
if ( ( PinCategory = = PC_Asset ) & & NewDefaultObject & & ! NewDefaultObject - > IsAsset ( ) )
{
DVSV_RETURN_MSG ( FString : : Printf ( TEXT ( " %s is not an asset (specified on pin %s) " ) , * NewDefaultObject - > GetPathName ( ) , * ( PinName ) ) ) ;
}
2014-03-14 14:13:41 -04:00
}
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
}
2015-05-15 16:44:55 -04:00
else if ( TypeString = = PC_Asset )
{
return Settings - > AssetPinTypeColor ;
}
else if ( TypeString = = PC_AssetClass )
{
return Settings - > AssetClassPinTypeColor ;
}
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
}
2015-01-07 09:52:40 -05:00
FText UEdGraphSchema_K2 : : GetPinDisplayName ( const UEdGraphPin * Pin ) const
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
FText DisplayName = FText : : GetEmpty ( ) ;
2014-03-14 14:13:41 -04:00
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 ) & &
2015-01-07 09:52:40 -05:00
( ( DisplayName . ToString ( ) = = PN_Execute ) | | ( DisplayName . ToString ( ) = = PN_Then ) ) )
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
DisplayName = FText : : GetEmpty ( ) ;
2014-03-14 14:13:41 -04:00
}
}
if ( GEditor & & GetDefault < UEditorStyleSettings > ( ) - > bShowFriendlyNames )
{
2015-01-07 09:52:40 -05:00
DisplayName = FText : : FromString ( FName : : NameToDisplayString ( DisplayName . ToString ( ) , 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
{
2015-06-24 21:45:09 -04:00
if ( Pin . HasAnyFlags ( RF_Transient ) )
{
return ;
}
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
{
2015-01-07 09:52:40 -05:00
Args . Add ( TEXT ( " DisplayName " ) , GetPinDisplayName ( & Pin ) ) ;
2014-09-05 17:51:04 -04:00
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
}
}
2015-03-11 16:41:45 -04:00
void UEdGraphSchema_K2 : : LinkDataPinFromOutputToInput ( UEdGraphNode * InOutputNode , UEdGraphNode * InInputNode ) const
{
for ( auto PinIter = InOutputNode - > Pins . CreateIterator ( ) ; PinIter ; + + PinIter )
{
UEdGraphPin * const OutputPin = * PinIter ;
if ( ( OutputPin - > Direction = = EGPD_Output ) & & ( ! IsExecPin ( * OutputPin ) ) )
{
UEdGraphPin * const InputPin = InInputNode - > FindPinChecked ( OutputPin - > PinName ) ;
OutputPin - > MakeLinkTo ( InputPin ) ;
}
}
}
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 )
{
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
// Add modifier flags from the declaration
2015-07-28 18:17:18 -04:00
EntryNode - > SetExtraFlags ( EntryNode - > GetFunctionFlags ( ) | ( InterfaceToImplement - > FunctionFlags & ( FUNC_Const | FUNC_Static | FUNC_BlueprintPure ) ) ) ;
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
2015-03-11 16:41:45 -04:00
UK2Node * NextNode = EntryNode ;
2015-03-16 14:42:38 -04:00
UEdGraphPin * NextExec = FindExecutionPin ( * EntryNode , EGPD_Output ) ;
2015-03-11 16:41:45 -04:00
bool bHasParentNode = false ;
// Create node for call parent function
if ( ( ( Class - > GetClassFlags ( ) & CLASS_Interface ) = = 0 ) & &
( InterfaceToImplement - > FunctionFlags & FUNC_BlueprintCallable ) )
{
FGraphNodeCreator < UK2Node_CallParentFunction > FunctionParentCreator ( Graph ) ;
UK2Node_CallParentFunction * ParentNode = FunctionParentCreator . CreateNode ( ) ;
ParentNode - > SetFromFunction ( InterfaceToImplement ) ;
ParentNode - > NodePosX = EntryNode - > NodePosX + EntryNode - > NodeWidth + 256 ;
ParentNode - > NodePosY = EntryNode - > NodePosY ;
FunctionParentCreator . Finalize ( ) ;
2015-03-16 14:42:38 -04:00
UEdGraphPin * ParentNodeExec = FindExecutionPin ( * ParentNode , EGPD_Input ) ;
2015-03-11 16:41:45 -04:00
2015-03-16 14:42:38 -04:00
// If the parent node has an execution pin, then we should as well (we're overriding them, after all)
// but perhaps this assumption is not valid in the case where a function becomes pure after being
// initially declared impure - for that reason I'm checking for validity on both ParentNodeExec and NextExec
if ( ParentNodeExec & & NextExec )
{
NextExec - > MakeLinkTo ( ParentNodeExec ) ;
NextExec = FindExecutionPin ( * ParentNode , EGPD_Output ) ;
}
2015-03-11 16:41:45 -04:00
NextNode = ParentNode ;
bHasParentNode = true ;
}
2014-03-14 14:13:41 -04:00
// 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 ;
2015-03-11 16:41:45 -04:00
ReturnNode - > NodePosX = NextNode - > NodePosX + NextNode - > NodeWidth + 256 ;
2014-03-14 14:13:41 -04:00
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 * ResultNodeExec = FindExecutionPin ( * ReturnNode , EGPD_Input ) ;
2015-03-16 14:42:38 -04:00
if ( ResultNodeExec & & NextExec )
{
NextExec - > MakeLinkTo ( ResultNodeExec ) ;
}
2015-03-11 16:41:45 -04:00
if ( bHasParentNode )
{
LinkDataPinFromOutputToInput ( NextNode , ReturnNode ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
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 ) )
{
2015-05-15 16:44:55 -04:00
TypeOut . PinCategory = PC_AssetClass ;
2014-03-14 14:13:41 -04:00
TypeOut . PinSubCategoryObject = AssetClassProperty - > MetaClass ;
}
2015-05-15 16:44:55 -04:00
else if ( const UAssetObjectProperty * AssetObjectProperty = Cast < const UAssetObjectProperty > ( TestProperty ) )
{
TypeOut . PinCategory = PC_Asset ;
TypeOut . PinSubCategoryObject = AssetObjectProperty - > PropertyClass ;
}
2014-03-14 14:13:41 -04:00
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 ;
2015-03-12 16:02:38 -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 ;
2015-03-12 16:02:38 -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 " ) ) ;
2014-11-13 10:35:54 -05:00
CategoryDescriptions . Add ( PC_Enum , LOCTEXT ( " EnumCategory " , " Enum " ) ) ;
2015-05-28 04:52:58 -04:00
CategoryDescriptions . Add ( PC_Asset , LOCTEXT ( " AssetCategory " , " Asset ID " ) ) ;
CategoryDescriptions . Add ( PC_AssetClass , LOCTEXT ( " AssetClassCategory " , " Class Asset ID " ) ) ;
2015-07-02 10:25:42 -04:00
CategoryDescriptions . Add ( AllObjectTypes , LOCTEXT ( " AllObjectTypes " , " Object Types " ) ) ;
2014-09-05 13:06:18 -04:00
}
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
{
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 ;
}
2015-07-02 10:25:42 -04:00
void UEdGraphSchema_K2 : : GetVariableTypeTree ( TArray < TSharedPtr < FPinTypeTreeInfo > > & TypeTree , bool bAllowExec , bool bAllowWildcard ) const
{
GetVariableTypeTreeImpl ( TypeTree , bAllowExec , bAllowWildcard , false ) ;
}
void UEdGraphSchema_K2 : : GetVariableTypeTreeImpl ( TArray < TSharedPtr < FPinTypeTreeInfo > > & TypeTree , bool bAllowExec , bool bAllowWildCard , bool bIndexTypesOnly ) const
2014-03-14 14:13:41 -04:00
{
2015-05-28 03:57:54 -04:00
# ifdef SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
static_assert ( false , " Macro redefinition. " ) ;
# endif
# define SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME 0
# if SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
const auto StartTime = FPlatformTime : : Seconds ( ) ;
# endif //SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
FTypesDatabase TypesDatabase ;
2015-07-02 10:25:42 -04:00
FGatherTypesHelper : : FillLoadedTypesDatabase ( TypesDatabase , bIndexTypesOnly ) ;
2015-05-28 03:57:54 -04:00
# if SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
const auto DatabaseLoadedTime = FPlatformTime : : Seconds ( ) ;
# endif //SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
2015-07-02 10:25:42 -04:00
FGatherTypesHelper : : FillUnLoadedTypesDatabase ( TypesDatabase , bIndexTypesOnly ) ;
2015-05-28 03:57:54 -04:00
# if SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
const auto DatabaseUnLoadedTime = FPlatformTime : : Seconds ( ) ;
# endif //SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
2014-03-14 14:13:41 -04:00
// 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 " ) ) ) ) ;
2015-07-02 10:25:42 -04:00
if ( ! bIndexTypesOnly )
{
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
2015-07-02 10:25:42 -04:00
// Add in special first-class struct types
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( PC_Struct , TBaseStructure < FVector > : : Get ( ) , LOCTEXT ( " VectorType " , " A 3D vector " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( PC_Struct , TBaseStructure < FRotator > : : Get ( ) , LOCTEXT ( " RotatorType " , " A 3D rotation " ) ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( PC_Struct , TBaseStructure < FTransform > : : Get ( ) , 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
}
2015-05-28 03:57:54 -04:00
FTypesDatabase * TypesDatabasePtr = & TypesDatabase ;
2014-03-14 14:13:41 -04:00
// Add the types that have subtrees
2015-07-02 10:25:42 -04:00
if ( ! bIndexTypesOnly )
{
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Struct , true ) , PC_Struct , this , LOCTEXT ( " StructType " , " Struct (value) types. " ) , true , TypesDatabasePtr ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Interface , true ) , PC_Interface , this , LOCTEXT ( " InterfaceType " , " Interface pointer. " ) , true , TypesDatabasePtr ) ) ) ;
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( AllObjectTypes , true ) , AllObjectTypes , this , LOCTEXT ( " ObjectType " , " Object pointer. " ) , true , TypesDatabasePtr ) ) ) ;
}
2015-05-28 03:57:54 -04:00
TypeTree . Add ( MakeShareable ( new FPinTypeTreeInfo ( GetCategoryText ( PC_Enum , true ) , PC_Enum , this , LOCTEXT ( " EnumType " , " Enumeration types. " ) , true , TypesDatabasePtr ) ) ) ;
# if SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
const auto EndTime = FPlatformTime : : Seconds ( ) ;
UE_LOG ( LogBlueprint , Log , TEXT ( " UEdGraphSchema_K2::GetVariableTypeTree times - LoadedTypesDatabase: %f UnLoadedTypesDatabase: %f FPinTypeTreeInfo: %f " ) , DatabaseLoadedTime - StartTime , DatabaseUnLoadedTime - DatabaseLoadedTime , EndTime - DatabaseUnLoadedTime ) ;
# endif //SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
# undef SCHEMA_K2_GETVARIABLETYPETREE_LOG_TIME
2014-03-14 14:13:41 -04:00
}
void UEdGraphSchema_K2 : : GetVariableIndexTypeTree ( TArray < TSharedPtr < FPinTypeTreeInfo > > & TypeTree , bool bAllowExec , bool bAllowWildcard ) const
{
2015-07-02 10:25:42 -04:00
GetVariableTypeTreeImpl ( TypeTree , bAllowExec , bAllowWildcard , 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
{
2015-07-02 10:25:42 -04:00
return ( Category = = PC_Struct ) | | ( Category = = PC_Object ) | | ( Category = = PC_Asset ) | | ( Category = = PC_AssetClass ) | | ( Category = = PC_Interface ) | | ( Category = = PC_Class ) | | ( Category = = PC_Enum ) | | ( Category = = AllObjectTypes ) ;
2014-03-14 14:13:41 -04:00
}
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 )
{
2014-11-19 05:58:05 -05:00
if ( ( Output . PinSubCategory = = Input . PinSubCategory )
& & ( Output . PinSubCategoryObject = = Input . PinSubCategoryObject )
& & ( Output . PinSubCategoryMemberReference = = Input . PinSubCategoryMemberReference ) )
2014-03-14 14:13:41 -04:00
{
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 ) ;
}
2015-05-15 16:44:55 -04:00
else if ( ( ( Output . PinCategory = = PC_Asset ) & & ( Input . PinCategory = = PC_Asset ) )
| | ( ( Output . PinCategory = = PC_AssetClass ) & & ( Input . PinCategory = = PC_AssetClass ) ) )
{
const UClass * OutputObject = ( Output . PinSubCategory = = PSC_Self ) ? CallingContext : Cast < const UClass > ( Output . PinSubCategoryObject . Get ( ) ) ;
const UClass * InputObject = ( Input . PinSubCategory = = PSC_Self ) ? CallingContext : Cast < const UClass > ( Input . PinSubCategoryObject . Get ( ) ) ;
if ( ( OutputObject ! = NULL ) & & ( InputObject ! = NULL ) )
{
return OutputObject - > IsChildOf ( InputObject ) ;
}
}
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-12-18 13:22:56 -05:00
auto CanUseFunction = [ ] ( const UFunction * Func ) - > bool
{
return Func & & ( Func - > HasAllFlags ( RF_LoadCompleted ) | | ! Func - > HasAnyFlags ( RF_NeedLoad | RF_WasLoaded ) ) ;
} ;
2015-03-12 16:02:38 -04:00
const UFunction * OutFunction = FMemberReference : : ResolveSimpleMemberReference < UFunction > ( Output . PinSubCategoryMemberReference ) ;
2014-12-18 13:22:56 -05:00
if ( ! CanUseFunction ( OutFunction ) )
{
OutFunction = NULL ;
}
2015-04-27 12:46:38 -04:00
if ( ! OutFunction & & Output . PinSubCategoryMemberReference . GetMemberParentClass ( ) )
2014-11-19 05:58:05 -05:00
{
2015-04-27 12:46:38 -04:00
const UClass * ParentClass = Output . PinSubCategoryMemberReference . GetMemberParentClass ( ) ;
const UBlueprint * BPOwner = Cast < UBlueprint > ( ParentClass - > ClassGeneratedBy ) ;
2014-11-19 05:58:05 -05:00
if ( BPOwner & & BPOwner - > SkeletonGeneratedClass & & ( BPOwner - > SkeletonGeneratedClass ! = ParentClass ) )
{
OutFunction = BPOwner - > SkeletonGeneratedClass - > FindFunctionByName ( Output . PinSubCategoryMemberReference . MemberName ) ;
}
}
2015-03-12 16:02:38 -04:00
const UFunction * InFunction = FMemberReference : : ResolveSimpleMemberReference < UFunction > ( Input . PinSubCategoryMemberReference ) ;
2014-12-18 13:22:56 -05:00
if ( ! CanUseFunction ( InFunction ) )
{
InFunction = NULL ;
}
2015-04-27 12:46:38 -04:00
if ( ! InFunction & & Input . PinSubCategoryMemberReference . GetMemberParentClass ( ) )
2014-11-19 05:58:05 -05:00
{
2015-04-27 12:46:38 -04:00
const UClass * ParentClass = Input . PinSubCategoryMemberReference . GetMemberParentClass ( ) ;
const UBlueprint * BPOwner = Cast < UBlueprint > ( ParentClass - > ClassGeneratedBy ) ;
2014-11-19 05:58:05 -05:00
if ( BPOwner & & BPOwner - > SkeletonGeneratedClass & & ( BPOwner - > SkeletonGeneratedClass ! = ParentClass ) )
{
InFunction = BPOwner - > SkeletonGeneratedClass - > FindFunctionByName ( Input . PinSubCategoryMemberReference . MemberName ) ;
}
}
2014-05-22 14:14:52 -04:00
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_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-11-17 23:10:10 -05: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 ;
}
2014-12-10 10:57:36 -05:00
else if ( Pin . PinType . PinCategory = = PC_Text )
{
// Set Text pins by string as if it were text.
TrySetDefaultText ( Pin , FText : : FromString ( NewDefaultValue ) ) ;
UseDefaultObject = nullptr ;
UseDefaultValue . Empty ( ) ;
return ;
}
2014-03-14 14:13:41 -04:00
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
{
2015-02-17 15:52:38 -05:00
InPin . DefaultTextValue = FText : : ChangeKey ( TEXT ( " " ) , InPin . GetOwningNode ( ) - > NodeGuid . ToString ( ) + TEXT ( " _ " ) + InPin . PinName + FString : : FromInt ( InPin . GetOwningNode ( ) - > Pins . Find ( & InPin ) ) , InNewDefaultText ) ;
}
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
{
2015-03-23 16:48:53 -04:00
TArray < FString > AutoCreateParameterNames ;
FString MetaData = TargetFunction - > GetMetaData ( FBlueprintMetadata : : MD_AutoCreateRefTerm ) ;
MetaData . ParseIntoArray ( AutoCreateParameterNames , TEXT ( " , " ) , true ) ;
bIsAutoCreateRefTerm = AutoCreateParameterNames . Contains ( Pin - > PinName ) ;
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
2014-11-12 09:23:51 -05:00
if ( bShow & & ObjectClass - > IsChildOf ( AActor : : StaticClass ( ) ) )
{
// Only show the picker for Actor classes if the class is placeable and we are in the level script
bShow = ! ObjectClass - > HasAllClassFlags ( CLASS_NotPlaceable )
& & FBlueprintEditorUtils : : IsLevelScriptBlueprint ( FBlueprintEditorUtils : : FindBlueprintForNode ( Pin - > GetOwningNode ( ) ) ) ;
}
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
}
2015-07-31 14:26:31 -04:00
else if ( Cast < UK2Node_CreateDelegate > ( Pin - > GetOwningNode ( ) ) )
{
bShow = false ;
}
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
{
2015-02-17 15:52:38 -05:00
if ( ( Function ! = nullptr ) & & ( Param ! = nullptr ) )
2014-06-16 11:10:42 -04:00
{
2015-02-17 15:52:38 -05:00
bool bHasAutomaticValue = false ;
2014-06-16 11:10:42 -04:00
const FString MetadataDefaultValue = Function - > GetMetaData ( * Param - > GetName ( ) ) ;
if ( ! MetadataDefaultValue . IsEmpty ( ) )
{
// Specified default value in the metadata
2015-02-17 15:52:38 -05:00
Pin - > AutogeneratedDefaultValue = MetadataDefaultValue ;
bHasAutomaticValue = true ;
2014-06-16 11:10:42 -04:00
}
else
{
const FName MetadataCppDefaultValueKey ( * ( FString ( TEXT ( " CPP_Default_ " ) ) + Param - > GetName ( ) ) ) ;
const FString MetadataCppDefaultValue = Function - > GetMetaData ( MetadataCppDefaultValueKey ) ;
2015-02-17 15:52:38 -05:00
if ( ! MetadataCppDefaultValue . IsEmpty ( ) )
2014-06-16 11:10:42 -04:00
{
2015-02-17 15:52:38 -05:00
Pin - > AutogeneratedDefaultValue = MetadataCppDefaultValue ;
bHasAutomaticValue = true ;
}
}
if ( bHasAutomaticValue )
{
if ( Pin - > PinType . PinCategory = = PC_Text )
{
Pin - > DefaultTextValue = FText : : AsCultureInvariant ( Pin - > AutogeneratedDefaultValue ) ;
}
else
{
Pin - > DefaultValue = Pin - > AutogeneratedDefaultValue ;
2014-06-16 11:10:42 -04:00
}
}
}
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 > ( ) ;
2015-07-20 04:31:26 -04:00
const UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForNode ( Pin - > GetOwningNodeUnchecked ( ) ) ;
const UClass * CallingContext = Blueprint
? ( ( Blueprint - > GeneratedClass ! = nullptr ) ? Blueprint - > GeneratedClass : Blueprint - > ParentClass )
: nullptr ;
2014-03-14 14:13:41 -04:00
// Break any newly invalid links
TArray < UEdGraphPin * > BrokenLinks ;
2015-07-20 04:31:26 -04:00
for ( int32 Index = 0 ; Index < Pin - > LinkedTo . Num ( ) ; )
2014-03-14 14:13:41 -04:00
{
UEdGraphPin * OtherPin = Pin - > LinkedTo [ Index ] ;
2015-07-20 04:31:26 -04:00
if ( K2Schema - > ArePinsCompatible ( Pin , OtherPin , CallingContext ) )
2014-03-14 14:13:41 -04:00
{
+ + 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 ;
}
2015-05-15 16:44:55 -04:00
else if ( PinType . PinCategory = = K2Schema - > PC_Asset )
{
static FName SetAssetName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetAssetPropertyByName ) ) ;
SetFunctionName = SetAssetName ;
}
else if ( PinType . PinCategory = = K2Schema - > PC_AssetClass )
{
static FName SetAssetClassName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetAssetClassPropertyByName ) ) ;
SetFunctionName = SetAssetClassName ;
}
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-11-19 11:55:51 -05:00
else if ( PinType . PinCategory = = K2Schema - > PC_Struct & & PinType . PinSubCategoryObject = = FCollisionProfileName : : StaticStruct ( ) )
{
static FName SetStructureName ( GET_FUNCTION_NAME_CHECKED ( UKismetSystemLibrary , SetCollisionProfileNameProperty ) ) ;
SetFunctionName = SetStructureName ;
}
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 ( ) ;
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
if ( ! OwningBlueprint | | ( OwningBlueprint - > BlueprintType = = BPTYPE_MacroLibrary ) | | ( OwningBlueprint - > BlueprintType = = BPTYPE_FunctionLibrary ) | | IsStaticFunctionGraph ( Node - > GetGraph ( ) ) )
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
{
2015-02-03 15:01:50 -05:00
DisplayInfo . PlainName = FText : : FromString ( Function - > GetName ( ) ) ;
2014-09-01 12:04:47 -04:00
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 " ) ;
}
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
// Add pure/static/const to notes if set
if ( Function )
2014-07-08 18:23:43 -04:00
{
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
if ( Function - > HasAnyFunctionFlags ( FUNC_BlueprintPure ) )
{
DisplayInfo . Notes . Add ( TEXT ( " pure " ) ) ;
}
// since 'static' is implied in a function library, not going to display it (to be consistent with previous behavior)
if ( Function - > HasAnyFunctionFlags ( FUNC_Static ) & & Blueprint - > BlueprintType ! = BPTYPE_FunctionLibrary )
{
DisplayInfo . Notes . Add ( TEXT ( " static " ) ) ;
}
else if ( Function - > HasAnyFunctionFlags ( FUNC_Const ) )
{
DisplayInfo . Notes . Add ( TEXT ( " const " ) ) ;
}
2014-07-08 18:23:43 -04:00
}
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 ;
}
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
bool UEdGraphSchema_K2 : : IsConstFunctionGraph ( const UEdGraph * TestEdGraph , bool * bOutIsEnforcingConstCorrectness ) const
{
check ( TestEdGraph ) ;
const EGraphType GraphType = GetGraphType ( TestEdGraph ) ;
if ( GraphType = = GT_Function )
{
// Find the entry node for the function graph and see if the 'const' flag is set
for ( auto I = TestEdGraph - > Nodes . CreateConstIterator ( ) ; I ; + + I )
{
UEdGraphNode * Node = * I ;
if ( auto EntryNode = Cast < UK2Node_FunctionEntry > ( Node ) )
{
if ( bOutIsEnforcingConstCorrectness ! = nullptr )
{
* bOutIsEnforcingConstCorrectness = EntryNode - > bEnforceConstCorrectness ;
}
2015-07-28 16:17:47 -04:00
return ( EntryNode - > GetFunctionFlags ( ) & FUNC_Const ) ! = 0 ;
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
}
}
}
if ( bOutIsEnforcingConstCorrectness ! = nullptr )
{
* bOutIsEnforcingConstCorrectness = false ;
}
return false ;
}
bool UEdGraphSchema_K2 : : IsStaticFunctionGraph ( const UEdGraph * TestEdGraph ) const
{
check ( TestEdGraph ) ;
2014-12-10 09:32:46 -05:00
const auto Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( TestEdGraph ) ;
if ( Blueprint & & ( EBlueprintType : : BPTYPE_FunctionLibrary = = Blueprint - > BlueprintType ) )
{
return true ;
}
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
const EGraphType GraphType = GetGraphType ( TestEdGraph ) ;
if ( GraphType = = GT_Function )
{
// Find the entry node for the function graph and see if the 'static' flag is set
for ( auto I = TestEdGraph - > Nodes . CreateConstIterator ( ) ; I ; + + I )
{
UEdGraphNode * Node = * I ;
if ( auto EntryNode = Cast < UK2Node_FunctionEntry > ( Node ) )
{
2015-07-28 16:17:47 -04:00
return ( EntryNode - > GetFunctionFlags ( ) & FUNC_Static ) ! = 0 ;
[UE-2345] BP - enforce const-correctness in native const class method overrides
this change introduces enforcement of 'const-correctness' into implemented function graphs.
summary:
if you have a function declared in C++ like this:
UFUNCTION(BlueprintImplementableEvent)
int32 MyFunctionThatReturnsSomeValue() const;
if you implement that (BPIE) function in a Blueprint that's parented to that native class, it will now be flagged as 'const'. this makes any properties of 'self' read-only within the context of that graph, which means the compiler will emit an error if you try to set a property or otherwise call a non-const, non-static function with 'self' as the target.
if there happens to already be an implemented const function in a Blueprint that was in place prior to this change, the compiler will emit a warning instead of an error, in order to allow existing Blueprints that may currently be "violating" const within the context of a const BPIE function to still compile, while still alerting to issues that should probably be addressed.
notes:
1) this also applies to BlueprintNativeEvent (BPNE) implementations, and also when implementing BPIE/BPNE interface methods that are also declared as const
2) a const BPIE/BPNE function with no return value and no output parameters will be implemented as a "normal" impure function, and not as an event as in the non-const case
3) a const BPIE/BPNE function with a return value and/or output parameters will currently be implemented as a pure function, regardless of whether or not BlueprintCallable is specified
4) this CL also retains some consolidation of static function validation code that i had previously done, mostly to allow static functions to more easily be whitelisted for const function graphs
#codereview Nick.Whiting, Michael.Noland
[CL 2368059 by Phillip Kavan in Main branch]
2014-11-21 17:47:17 -05:00
}
}
}
return false ;
}
2014-03-14 14:13:41 -04:00
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 ) ;
2015-04-16 11:47:54 -04:00
FComponentTypeEntry ComponentType = { FString ( ) , FString ( ) , DestinationComponentType } ;
IBlueprintNodeBinder : : FBindingSet Bindings ;
Bindings . Add ( Asset ) ;
UBlueprintComponentNodeSpawner : : Create ( ComponentType ) - > Invoke ( Graph , Bindings , GraphPosition ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
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 ) ;
2015-01-20 14:04:44 -05:00
Graph - > AddNode ( NewNode , false , false ) ;
2014-04-23 16:39:43 -04:00
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 ;
2015-01-20 14:04:44 -05:00
Graph - > AddNode ( CastNode , false , false ) ;
2014-04-23 16:39:43 -04:00
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 " ) )
{
2015-07-08 17:06:15 -04:00
MakeNodeFunction = UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_FUNCTION_NAME_CHECKED ( UKismetMathLibrary , MakeRotator ) ) ;
2014-03-14 14:13:41 -04:00
OldPinToNewPinMap . Add ( TEXT ( " Rotator " ) , TEXT ( " ReturnValue " ) ) ;
}
else if ( OldMakeStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector " ) )
{
2015-06-05 11:45:49 -04:00
MakeNodeFunction = UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_FUNCTION_NAME_CHECKED ( UKismetMathLibrary , MakeVector ) ) ;
2014-03-14 14:13:41 -04:00
OldPinToNewPinMap . Add ( TEXT ( " Vector " ) , TEXT ( " ReturnValue " ) ) ;
}
else if ( OldMakeStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector2D " ) )
{
2015-06-05 11:45:49 -04:00
MakeNodeFunction = UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_FUNCTION_NAME_CHECKED ( UKismetMathLibrary , MakeVector2D ) ) ;
2014-03-14 14:13:41 -04:00
OldPinToNewPinMap . Add ( TEXT ( " Vector2D " ) , TEXT ( " ReturnValue " ) ) ;
}
if ( MakeNodeFunction )
{
UK2Node_CallFunction * CallFunctionNode = NewObject < UK2Node_CallFunction > ( Graph ) ;
check ( CallFunctionNode ) ;
CallFunctionNode - > SetFlags ( RF_Transactional ) ;
2015-01-20 14:04:44 -05:00
Graph - > AddNode ( CallFunctionNode , false , false ) ;
2014-03-14 14:13:41 -04:00
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 " ) )
{
2015-07-08 17:06:15 -04:00
BreakNodeFunction = UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_FUNCTION_NAME_CHECKED ( UKismetMathLibrary , BreakRotator ) ) ;
2014-03-14 14:13:41 -04:00
OldPinToNewPinMap . Add ( TEXT ( " Rotator " ) , TEXT ( " InRot " ) ) ;
}
else if ( OldBreakStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector " ) )
{
2015-06-05 11:45:49 -04:00
BreakNodeFunction = UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_FUNCTION_NAME_CHECKED ( UKismetMathLibrary , BreakVector ) ) ;
2014-03-14 14:13:41 -04:00
OldPinToNewPinMap . Add ( TEXT ( " Vector " ) , TEXT ( " InVec " ) ) ;
}
else if ( OldBreakStructNode - > StructType - > GetName ( ) = = TEXT ( " Vector2D " ) )
{
2015-06-05 11:45:49 -04:00
BreakNodeFunction = UKismetMathLibrary : : StaticClass ( ) - > FindFunctionByName ( GET_FUNCTION_NAME_CHECKED ( UKismetMathLibrary , BreakVector2D ) ) ;
2014-03-14 14:13:41 -04:00
OldPinToNewPinMap . Add ( TEXT ( " Vector2D " ) , TEXT ( " InVec " ) ) ;
}
if ( BreakNodeFunction )
{
UK2Node_CallFunction * CallFunctionNode = NewObject < UK2Node_CallFunction > ( Graph ) ;
check ( CallFunctionNode ) ;
CallFunctionNode - > SetFlags ( RF_Transactional ) ;
2015-01-20 14:04:44 -05:00
Graph - > AddNode ( CallFunctionNode , false , false ) ;
2014-03-14 14:13:41 -04:00
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
2015-02-03 05:40:57 -05:00
UK2Node_CustomEvent * CustomEventNode = NewObject < UK2Node_CustomEvent > ( EventNode - > GetOuter ( ) , ObjName , EventNode - > GetFlags ( ) , nullptr , true , InstanceGraph ) ;
2014-03-14 14:13:41 -04:00
// 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 )
{
2015-02-06 09:41:28 -05:00
FunctionName = EventNode - > EventReference . GetMemberName ( ) . ToString ( ) ;
2014-03-14 14:13:41 -04:00
}
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 ( ) ;
2015-02-20 12:28:58 -05:00
bool bOriginalWasCustomEvent = Cast < UK2Node_CustomEvent > ( Node ) ! = nullptr ;
2014-03-14 14:13:41 -04:00
// 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
2015-02-20 12:28:58 -05:00
if ( ! bOriginalWasCustomEvent & & ! IsExecPin ( * Pin ) & & ! IsDelegateCategory ( Pin - > PinType . PinCategory ) )
2014-03-14 14:13:41 -04:00
{
// 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
{
2015-05-11 13:54:10 -04:00
EGraphType GraphType = GetGraphType ( InSourceGraph ) ;
if ( GraphType = = GT_Function )
2014-04-02 18:09:23 -04:00
{
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 ;
}
}
2015-05-11 13:54:10 -04:00
return GraphType = = GT_Function | | GraphType = = GT_Macro ;
2014-04-02 18:09:23 -04:00
}
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 ( ) ;
2015-04-08 16:00:28 -04:00
UScriptStruct * StructType = CastChecked < UScriptStruct > ( Pin - > PinType . PinSubCategoryObject . Get ( ) , ECastCheckedType : : NullAllowed ) ;
2015-04-08 15:25:57 -04:00
if ( ! StructType )
{
if ( CompilerContext )
{
CompilerContext - > MessageLog . Error ( TEXT ( " No structure in SubCategoryObject in pin @@ " ) , Pin ) ;
}
StructType = GetFallbackStruct ( ) ;
}
2014-06-16 11:10:42 -04:00
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
2015-02-17 17:07:09 -05:00
if ( K2Node ! = nullptr & & K2Node - > ShouldDrawCompact ( ) & & ! Pin - > ParentPin )
2014-07-07 13:47:02 -04:00
{
2015-02-17 17:07:09 -05:00
SubPin - > PinFriendlyName = ProtoPin - > GetDisplayName ( ) ;
2014-07-07 13:47:02 -04:00
}
else
2014-07-01 14:55:39 -04:00
{
2015-02-17 17:07:09 -05:00
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " PinDisplayName " ) , Pin - > GetDisplayName ( ) ) ;
2015-04-08 14:46:23 -04:00
Arguments . Add ( TEXT ( " ProtoPinDisplayName " ) , ProtoPin - > GetDisplayName ( ) ) ;
2015-02-17 17:07:09 -05:00
SubPin - > PinFriendlyName = FText : : Format ( LOCTEXT ( " SplitPinFriendlyNameFormat " , " {PinDisplayName} {ProtoPinDisplayName} " ) , Arguments ) ;
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
2015-03-27 20:23:08 -04:00
GraphNode - > Pins . Pop ( /*bAllowShrinking=*/ false ) ;
2014-06-16 11:10:42 -04:00
Pin - > SubPins . Add ( SubPin ) ;
}
}
ProtoExpandNode - > DestroyNode ( ) ;
if ( Pin - > Direction = = EGPD_Input )
{
TArray < FString > OriginalDefaults ;
2015-05-05 23:07:23 -04:00
if ( StructType = = TBaseStructure < FVector > : : Get ( )
| | StructType = = TBaseStructure < FRotator > : : Get ( ) )
2014-06-16 11:10:42 -04:00
{
2015-03-02 15:51:37 -05: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
}
2015-05-05 23:07:23 -04:00
else if ( StructType = = TBaseStructure < FVector2D > : : Get ( ) )
2014-06-16 11:10:42 -04:00
{
FVector2D V2D ;
V2D . InitFromString ( Pin - > DefaultValue ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( V2D . X ) ) ;
OriginalDefaults . Add ( FString : : SanitizeFloat ( V2D . Y ) ) ;
}
2015-05-05 23:07:23 -04:00
else if ( StructType = = TBaseStructure < FLinearColor > : : Get ( ) )
2014-06-16 11:10:42 -04:00
{
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 ;
2015-05-05 23:07:23 -04:00
if ( StructType = = TBaseStructure < FVector > : : Get ( )
| | StructType = = TBaseStructure < FRotator > : : Get ( ) )
2014-06-16 11:10:42 -04:00
{
ParentPin - > DefaultValue = ParentPin - > SubPins [ 0 ] - > DefaultValue + TEXT ( " , " )
+ ParentPin - > SubPins [ 1 ] - > DefaultValue + TEXT ( " , " )
+ ParentPin - > SubPins [ 2 ] - > DefaultValue ;
}
2015-05-05 23:07:23 -04:00
else if ( StructType = = TBaseStructure < FVector2D > : : Get ( ) )
2014-06-16 11:10:42 -04:00
{
FVector2D V2D ;
V2D . X = FCString : : Atof ( * ParentPin - > SubPins [ 0 ] - > DefaultValue ) ;
V2D . Y = FCString : : Atof ( * ParentPin - > SubPins [ 1 ] - > DefaultValue ) ;
ParentPin - > DefaultValue = V2D . ToString ( ) ;
}
2015-05-05 23:07:23 -04:00
else if ( StructType = = TBaseStructure < FLinearColor > : : Get ( ) )
2014-06-16 11:10:42 -04:00
{
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 ) ;
2015-03-18 23:32:57 -04:00
}
void UEdGraphSchema_K2 : : OnPinConnectionDoubleCicked ( UEdGraphPin * PinA , UEdGraphPin * PinB , const FVector2D & GraphPosition ) const
{
const FScopedTransaction Transaction ( LOCTEXT ( " CreateRerouteNodeOnWire " , " Create Reroute Node " ) ) ;
//@TODO: This constant is duplicated from inside of SGraphNodeKnot
const FVector2D NodeSpacerSize ( 42.0f , 24.0f ) ;
const FVector2D KnotTopLeft = GraphPosition - ( NodeSpacerSize * 0.5f ) ;
// Create a new knot
UEdGraph * ParentGraph = PinA - > GetOwningNode ( ) - > GetGraph ( ) ;
UK2Node_Knot * NewKnot = FEdGraphSchemaAction_K2NewNode : : SpawnNodeFromTemplate < UK2Node_Knot > ( ParentGraph , NewObject < UK2Node_Knot > ( ) , KnotTopLeft ) ;
// Move the connections across (only notifying the knot, as the other two didn't really change)
PinA - > BreakLinkTo ( PinB ) ;
PinA - > MakeLinkTo ( ( PinA - > Direction = = EGPD_Output ) ? NewKnot - > GetInputPin ( ) : NewKnot - > GetOutputPin ( ) ) ;
PinB - > MakeLinkTo ( ( PinB - > Direction = = EGPD_Output ) ? NewKnot - > GetInputPin ( ) : NewKnot - > GetOutputPin ( ) ) ;
NewKnot - > PostReconstructNode ( ) ;
// Dirty the blueprint
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraphChecked ( CastChecked < UEdGraph > ( ParentGraph ) ) ;
FBlueprintEditorUtils : : MarkBlueprintAsModified ( Blueprint ) ;
2014-06-16 11:10:42 -04:00
}
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 ) ;
}
2015-03-31 10:32:10 -04:00
UEdGraphPin * UEdGraphSchema_K2 : : DropPinOnNode ( UEdGraphNode * InTargetNode , const FString & InSourcePinName , const FEdGraphPinType & InSourcePinType , EEdGraphPinDirection InSourcePinDirection ) const
{
UEdGraphPin * ResultPin = nullptr ;
if ( UK2Node_EditablePinBase * EditablePinNode = Cast < UK2Node_EditablePinBase > ( InTargetNode ) )
{
EditablePinNode - > Modify ( ) ;
if ( InSourcePinDirection = = EGPD_Output & & Cast < UK2Node_FunctionEntry > ( InTargetNode ) )
{
if ( UK2Node_EditablePinBase * ResultNode = FBlueprintEditorUtils : : FindOrCreateFunctionResultNode ( EditablePinNode ) )
{
EditablePinNode = ResultNode ;
}
else
{
// If we did not successfully find or create a result node, just fail out
return nullptr ;
}
}
else if ( InSourcePinDirection = = EGPD_Input & & Cast < UK2Node_FunctionResult > ( InTargetNode ) )
{
TArray < UK2Node_FunctionEntry * > FunctionEntryNode ;
InTargetNode - > GetGraph ( ) - > GetNodesOfClass ( FunctionEntryNode ) ;
if ( FunctionEntryNode . Num ( ) = = 1 )
{
EditablePinNode = FunctionEntryNode [ 0 ] ;
}
else
{
// If we did not successfully find the entry node, just fail out
return nullptr ;
}
}
FString NewPinName = InSourcePinName ;
ResultPin = EditablePinNode - > CreateUserDefinedPin ( NewPinName , InSourcePinType , ( InSourcePinDirection = = EGPD_Input ) ? EGPD_Output : EGPD_Input ) ;
FParamsChangedHelper ParamsChangedHelper ;
ParamsChangedHelper . ModifiedBlueprints . Add ( FBlueprintEditorUtils : : FindBlueprintForNode ( InTargetNode ) ) ;
FBlueprintEditorUtils : : MarkBlueprintAsStructurallyModified ( FBlueprintEditorUtils : : FindBlueprintForNode ( InTargetNode ) ) ;
ParamsChangedHelper . Broadcast ( FBlueprintEditorUtils : : FindBlueprintForNode ( InTargetNode ) , EditablePinNode , InTargetNode - > GetGraph ( ) ) ;
for ( auto GraphIt = ParamsChangedHelper . ModifiedGraphs . CreateIterator ( ) ; GraphIt ; + + GraphIt )
{
if ( UEdGraph * ModifiedGraph = * GraphIt )
{
ModifiedGraph - > NotifyGraphChanged ( ) ;
}
}
// Now update all the blueprints that got modified
for ( auto BlueprintIt = ParamsChangedHelper . ModifiedBlueprints . CreateIterator ( ) ; BlueprintIt ; + + BlueprintIt )
{
if ( UBlueprint * Blueprint = * BlueprintIt )
{
Blueprint - > BroadcastChanged ( ) ;
}
}
}
return ResultPin ;
}
bool UEdGraphSchema_K2 : : SupportsDropPinOnNode ( UEdGraphNode * InTargetNode , const FEdGraphPinType & InSourcePinType , EEdGraphPinDirection InSourcePinDirection , FText & OutErrorMessage ) const
{
bool bIsSupported = false ;
if ( UK2Node_EditablePinBase * EditablePinNode = Cast < UK2Node_EditablePinBase > ( InTargetNode ) )
{
if ( InSourcePinDirection = = EGPD_Output & & Cast < UK2Node_FunctionEntry > ( InTargetNode ) )
{
// Just check with the Function Entry and see if it's legal, we'll create/use a result node if the user drops
bIsSupported = EditablePinNode - > CanCreateUserDefinedPin ( InSourcePinType , InSourcePinDirection , OutErrorMessage ) ;
if ( bIsSupported )
{
OutErrorMessage = LOCTEXT ( " AddConnectResultNode " , " Add Pin to Result Node " ) ;
}
}
else if ( InSourcePinDirection = = EGPD_Input & & Cast < UK2Node_FunctionResult > ( InTargetNode ) )
{
// Just check with the Function Result and see if it's legal, we'll create/use a result node if the user drops
bIsSupported = EditablePinNode - > CanCreateUserDefinedPin ( InSourcePinType , InSourcePinDirection , OutErrorMessage ) ;
if ( bIsSupported )
{
OutErrorMessage = LOCTEXT ( " AddPinEntryNode " , " Add Pin to Entry Node " ) ;
}
}
else
{
bIsSupported = EditablePinNode - > CanCreateUserDefinedPin ( InSourcePinType , ( InSourcePinDirection = = EGPD_Input ) ? EGPD_Output : EGPD_Input , OutErrorMessage ) ;
if ( bIsSupported )
{
OutErrorMessage = LOCTEXT ( " AddPinToNode " , " Add Pin to Node " ) ;
}
}
}
return bIsSupported ;
}
2015-04-02 11:16:23 -04:00
bool UEdGraphSchema_K2 : : IsCacheVisualizationOutOfDate ( int32 InVisualizationCacheID ) const
{
return CurrentCacheRefreshID ! = InVisualizationCacheID ;
}
int32 UEdGraphSchema_K2 : : GetCurrentVisualizationCacheID ( ) const
{
return CurrentCacheRefreshID ;
}
void UEdGraphSchema_K2 : : ForceVisualizationCacheClear ( ) const
{
+ + CurrentCacheRefreshID ;
}
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
# undef LOCTEXT_NAMESPACE