2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "BlueprintGraphPrivatePCH.h"
# include "DynamicCastHandler.h"
# define LOCTEXT_NAMESPACE "DynamicCastHandler"
//////////////////////////////////////////////////////////////////////////
// FKCHandler_DynamicCast
void FKCHandler_DynamicCast : : RegisterNets ( FKismetFunctionContext & Context , UEdGraphNode * Node )
{
FNodeHandlingFunctor : : RegisterNets ( Context , Node ) ;
// Create a term to determine if the cast was successful or not
FBPTerminal * BoolTerm = new ( Context . IsEventGraph ( ) ? Context . EventGraphLocals : Context . Locals ) FBPTerminal ( ) ;
BoolTerm - > Type . PinCategory = CompilerContext . GetSchema ( ) - > PC_Boolean ;
BoolTerm - > Source = Node ;
BoolTerm - > Name = Context . NetNameMap - > MakeValidName ( Node ) + TEXT ( " _CastSuccess " ) ;
BoolTerm - > bIsLocal = true ;
BoolTermMap . Add ( Node , BoolTerm ) ;
}
void FKCHandler_DynamicCast : : RegisterNet ( FKismetFunctionContext & Context , UEdGraphPin * Net )
{
FBPTerminal * Term = new ( Context . IsEventGraph ( ) ? Context . EventGraphLocals : Context . Locals ) FBPTerminal ( ) ;
Term - > CopyFromPin ( Net , Context . NetNameMap - > MakeValidName ( Net ) ) ;
Context . NetMap . Add ( Net , Term ) ;
}
void FKCHandler_DynamicCast : : Compile ( FKismetFunctionContext & Context , UEdGraphNode * Node )
{
const UK2Node_DynamicCast * DynamicCastNode = CastChecked < UK2Node_DynamicCast > ( Node ) ;
if ( DynamicCastNode - > TargetType = = NULL )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " BadCastNoTargetType_Error " , " Node @@ has an invalid target type, please delete and recreate it " ) . ToString ( ) , Node ) ;
}
// Successful interface cast execution
2014-04-23 17:45:37 -04:00
UEdGraphPin * SuccessPin = DynamicCastNode - > GetValidCastPin ( ) ;
2014-03-14 14:13:41 -04:00
UEdGraphNode * SuccessNode = NULL ;
if ( SuccessPin - > LinkedTo . Num ( ) > 0 )
{
SuccessNode = SuccessPin - > LinkedTo [ 0 ] - > GetOwningNode ( ) ;
}
// Failed interface cast execution
2014-04-23 17:45:37 -04:00
UEdGraphPin * FailurePin = DynamicCastNode - > GetInvalidCastPin ( ) ;
2014-03-14 14:13:41 -04:00
UEdGraphNode * FailureNode = NULL ;
if ( FailurePin - > LinkedTo . Num ( ) > 0 )
{
FailureNode = FailurePin - > LinkedTo [ 0 ] - > GetOwningNode ( ) ;
}
// Self Pin
UEdGraphPin * SourceObjectPin = DynamicCastNode - > GetCastSourcePin ( ) ;
UEdGraphPin * PinToTry = FEdGraphUtilities : : GetNetFromPin ( SourceObjectPin ) ;
FBPTerminal * * ObjectToCast = Context . NetMap . Find ( PinToTry ) ;
if ( ! ObjectToCast )
{
ObjectToCast = Context . LiteralHackMap . Find ( PinToTry ) ;
2014-04-02 18:09:23 -04:00
if ( ! ObjectToCast | | ! ( * ObjectToCast ) )
2014-03-14 14:13:41 -04:00
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " InvalidConnectionOnNode_Error " , " Node @@ has an invalid connection on @@ " ) . ToString ( ) , Node , SourceObjectPin ) ;
return ;
}
}
// Output pin
2014-04-02 18:09:23 -04:00
const UEdGraphPin * CastOutputPin = DynamicCastNode - > GetCastResultPin ( ) ;
if ( ! CastOutputPin )
2014-03-14 14:13:41 -04:00
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " InvalidDynamicCastClass_Error " , " Node @@ has an invalid target class " ) . ToString ( ) , Node ) ;
return ;
}
2014-04-02 18:09:23 -04:00
FBPTerminal * * CastResultTerm = Context . NetMap . Find ( CastOutputPin ) ;
if ( ! CastResultTerm | | ! ( * CastResultTerm ) )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " InvalidDynamicCastClass_Error " , " Node @@ has an invalid target class. (Inner compiler error?) " ) . ToString ( ) , Node ) ;
return ;
}
2014-03-14 14:13:41 -04:00
// Create a literal term from the class specified in the node
FBPTerminal * ClassTerm = new ( Context . IsEventGraph ( ) ? Context . EventGraphLocals : Context . Locals ) FBPTerminal ( ) ;
ClassTerm - > Name = DynamicCastNode - > TargetType - > GetName ( ) ;
ClassTerm - > bIsLiteral = true ;
2014-04-02 18:09:23 -04:00
ClassTerm - > Source = Node ;
2014-03-14 14:13:41 -04:00
ClassTerm - > ObjectLiteral = DynamicCastNode - > TargetType ;
// Find the boolean intermediate result term, so we can track whether the cast was successful
FBPTerminal * BoolTerm = * BoolTermMap . Find ( DynamicCastNode ) ;
2014-04-02 18:09:23 -04:00
UClass const * const InputObjClass = Cast < UClass > ( ( * ObjectToCast ) - > Type . PinSubCategoryObject . Get ( ) ) ;
UClass const * const OutputObjClass = Cast < UClass > ( ( * CastResultTerm ) - > Type . PinSubCategoryObject . Get ( ) ) ;
const bool bIsOutputInterface = ( ( OutputObjClass ! = NULL ) & & OutputObjClass - > HasAnyClassFlags ( CLASS_Interface ) ) ;
const bool bIsInputInterface = ( ( InputObjClass ! = NULL ) & & InputObjClass - > HasAnyClassFlags ( CLASS_Interface ) ) ;
EKismetCompiledStatementType CastOpType = KCST_DynamicCast ;
if ( bIsInputInterface )
{
check ( bIsOutputInterface ) ;
CastOpType = KCST_CrossInterfaceCast ;
}
else if ( bIsOutputInterface )
{
CastOpType = KCST_CastObjToInterface ;
}
if ( KCST_MetaCast = = CastType )
{
if ( bIsInputInterface | | bIsOutputInterface )
{
CompilerContext . MessageLog . Error ( * LOCTEXT ( " InvalidClassDynamicCastClass_Error " , " Node @@ has an invalid target class. Interfaces are not supported. " ) . ToString ( ) , Node ) ;
return ;
}
CastOpType = KCST_MetaCast ;
}
2014-03-14 14:13:41 -04:00
// Cast Statement
FBlueprintCompiledStatement & CastStatement = Context . AppendStatementForNode ( Node ) ;
2014-04-02 18:09:23 -04:00
CastStatement . Type = CastOpType ;
CastStatement . LHS = * CastResultTerm ;
2014-03-14 14:13:41 -04:00
CastStatement . RHS . Add ( ClassTerm ) ;
CastStatement . RHS . Add ( * ObjectToCast ) ;
// Check result of cast statement
FBlueprintCompiledStatement & CheckResultStatement = Context . AppendStatementForNode ( Node ) ;
2014-04-02 18:09:23 -04:00
const UClass * SubObjectClass = Cast < UClass > ( ( * CastResultTerm ) - > Type . PinSubCategoryObject . Get ( ) ) ;
2014-03-14 14:13:41 -04:00
const bool bIsInterfaceCast = ( SubObjectClass ! = NULL & & SubObjectClass - > HasAnyClassFlags ( CLASS_Interface ) ) ;
CheckResultStatement . Type = KCST_ObjectToBool ;
CheckResultStatement . LHS = BoolTerm ;
2014-04-02 18:09:23 -04:00
CheckResultStatement . RHS . Add ( * CastResultTerm ) ;
2014-03-14 14:13:41 -04:00
// Failure condition...skip to the failed output
FBlueprintCompiledStatement & FailCastGoto = Context . AppendStatementForNode ( Node ) ;
FailCastGoto . Type = KCST_GotoIfNot ;
FailCastGoto . LHS = BoolTerm ;
2014-04-23 17:45:37 -04:00
Context . GotoFixupRequestMap . Add ( & FailCastGoto , FailurePin ) ;
2014-03-14 14:13:41 -04:00
// Successful cast...hit the success output node
FBlueprintCompiledStatement & SuccessCastGoto = Context . AppendStatementForNode ( Node ) ;
SuccessCastGoto . Type = KCST_UnconditionalGoto ;
SuccessCastGoto . LHS = BoolTerm ;
2014-04-23 17:45:37 -04:00
Context . GotoFixupRequestMap . Add ( & SuccessCastGoto , SuccessPin ) ;
2014-03-14 14:13:41 -04:00
}
# undef LOCTEXT_NAMESPACE