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"
# include "DynamicCastHandler.h"
# define LOCTEXT_NAMESPACE "DynamicCastHandler"
//////////////////////////////////////////////////////////////////////////
// FKCHandler_DynamicCast
void FKCHandler_DynamicCast : : RegisterNets ( FKismetFunctionContext & Context , UEdGraphNode * Node )
{
FNodeHandlingFunctor : : RegisterNets ( Context , Node ) ;
2015-04-08 18:03:05 -04:00
if ( const UK2Node_DynamicCast * DynamicCastNode = Cast < UK2Node_DynamicCast > ( Node ) )
{
UEdGraphPin * BoolSuccessPin = DynamicCastNode - > GetBoolSuccessPin ( ) ;
// this is to support backwards compatibility (when a cast node is generating code, but has yet to be reconstructed)
// @TODO: remove this at some point, when backwards compatibility isn't a concern
if ( BoolSuccessPin = = nullptr )
{
// Create a term to determine if the cast was successful or not
FBPTerminal * BoolTerm = Context . CreateLocalTerminal ( ) ;
BoolTerm - > Type . PinCategory = CompilerContext . GetSchema ( ) - > PC_Boolean ;
BoolTerm - > Source = Node ;
BoolTerm - > Name = Context . NetNameMap - > MakeValidName ( Node ) + TEXT ( " _CastSuccess " ) ;
BoolTermMap . Add ( Node , BoolTerm ) ;
}
}
2014-03-14 14:13:41 -04:00
}
void FKCHandler_DynamicCast : : RegisterNet ( FKismetFunctionContext & Context , UEdGraphPin * Net )
{
2014-09-26 11:32:41 -04:00
FBPTerminal * Term = Context . CreateLocalTerminalFromPinAutoChooseScope ( Net , Context . NetNameMap - > MakeValidName ( Net ) ) ;
2014-03-14 14:13:41 -04:00
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 ) ;
}
// 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 ) )
{
2014-09-08 14:46:46 -04:00
CompilerContext . MessageLog . Error ( * LOCTEXT ( " InvalidDynamicCastClass_CompilerError " , " Node @@ has an invalid target class. (Inner compiler error?) " ) . ToString ( ) , Node ) ;
2014-04-02 18:09:23 -04:00
return ;
}
2014-03-14 14:13:41 -04:00
// Create a literal term from the class specified in the node
2014-09-26 11:32:41 -04:00
FBPTerminal * ClassTerm = Context . CreateLocalTerminal ( ETerminalSpecification : : TS_Literal ) ;
2014-03-14 14:13:41 -04:00
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 ;
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 ) ) ;
2014-10-23 12:15:59 -04:00
const bool bIsInputInterface = ( ( InputObjClass ! = NULL ) & & InputObjClass - > HasAnyClassFlags ( CLASS_Interface ) ) ;
2014-04-02 18:09:23 -04:00
EKismetCompiledStatementType CastOpType = KCST_DynamicCast ;
if ( bIsInputInterface )
{
2014-10-23 12:15:59 -04:00
if ( bIsOutputInterface )
{
CastOpType = KCST_CrossInterfaceCast ;
}
else
{
CastOpType = KCST_CastInterfaceToObj ;
}
2014-04-02 18:09:23 -04:00
}
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 ) ;
2015-04-08 18:03:05 -04:00
FBPTerminal * * BoolSuccessTerm = nullptr ;
if ( UEdGraphPin * BoolSuccessPin = DynamicCastNode - > GetBoolSuccessPin ( ) )
{
BoolSuccessTerm = Context . NetMap . Find ( BoolSuccessPin ) ;
}
else
{
BoolSuccessTerm = BoolTermMap . Find ( DynamicCastNode ) ;
}
2014-11-21 14:51:28 -05:00
check ( BoolSuccessTerm ! = nullptr ) ;
2015-04-08 18:03:05 -04:00
2014-11-21 14:51:28 -05:00
// Check result of cast statement
FBlueprintCompiledStatement & CheckResultStatement = Context . AppendStatementForNode ( Node ) ;
CheckResultStatement . Type = KCST_ObjectToBool ;
CheckResultStatement . LHS = * BoolSuccessTerm ;
CheckResultStatement . RHS . Add ( * CastResultTerm ) ;
2014-03-14 14:13:41 -04:00
2014-11-21 14:51:28 -05:00
UEdGraphPin * SuccessExecPin = DynamicCastNode - > GetValidCastPin ( ) ;
bool const bIsPureCast = ( SuccessExecPin = = nullptr ) ;
2014-10-27 13:10:00 -04:00
if ( ! bIsPureCast )
{
UEdGraphPin * FailurePin = DynamicCastNode - > GetInvalidCastPin ( ) ;
check ( FailurePin ! = nullptr ) ;
// Failure condition...skip to the failed output
FBlueprintCompiledStatement & FailCastGoto = Context . AppendStatementForNode ( Node ) ;
FailCastGoto . Type = KCST_GotoIfNot ;
2014-11-21 14:51:28 -05:00
FailCastGoto . LHS = * BoolSuccessTerm ;
2014-10-27 13:10:00 -04:00
Context . GotoFixupRequestMap . Add ( & FailCastGoto , FailurePin ) ;
2014-03-14 14:13:41 -04:00
2014-10-27 13:10:00 -04:00
// Successful cast...hit the success output node
FBlueprintCompiledStatement & SuccessCastGoto = Context . AppendStatementForNode ( Node ) ;
SuccessCastGoto . Type = KCST_UnconditionalGoto ;
2014-11-21 14:51:28 -05:00
SuccessCastGoto . LHS = * BoolSuccessTerm ;
Context . GotoFixupRequestMap . Add ( & SuccessCastGoto , SuccessExecPin ) ;
2014-10-27 13:10:00 -04:00
}
2014-03-14 14:13:41 -04:00
}
# undef LOCTEXT_NAMESPACE