virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		static const FBoolConfigValueHelper ExecutionAfterReturn(TEXT("Kismet"), TEXT("bExecutionAfterReturn"), GEngineIni);

		if (ExecutionAfterReturn)
		{
			// for backward compatibility only
			FKCHandler_VariableSet::Compile(Context, Node);
		}
		else
		{
			GenerateAssigments(Context, Node);

			if (Context.bCreateDebugData && Node)
			{
				FBlueprintCompiledStatement& TraceStatement = Context.AppendStatementForNode(Node);
				TraceStatement.Type = KCST_WireTraceSite;
				TraceStatement.Comment = Node->NodeComment.IsEmpty() ? Node->GetName() : Node->NodeComment;
			}

			// always go to return
			FBlueprintCompiledStatement& GotoStatement = Context.AppendStatementForNode(Node);
			GotoStatement.Type = KCST_GotoReturn;
		}
	}
Example #2
0
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		// For imperative nodes, make sure the exec function was actually triggered and not just included due to an output data dependency
		FEdGraphPinType ExpectedExecPinType;
		ExpectedExecPinType.PinCategory = UEdGraphSchema_K2::PC_Exec;

		FEdGraphPinType ExpectedBoolPinType;
		ExpectedBoolPinType.PinCategory = UEdGraphSchema_K2::PC_Boolean;


		UEdGraphPin* ExecTriggeringPin = Context.FindRequiredPinByName(Node, UEdGraphSchema_K2::PN_Execute, EGPD_Input);
		if ((ExecTriggeringPin == NULL) || !Context.ValidatePinType(ExecTriggeringPin, ExpectedExecPinType))
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("NoValidExecutionPinForBranch_Error", "@@ must have a valid execution pin @@").ToString()), Node, ExecTriggeringPin);
			return;
		}
		else if (ExecTriggeringPin->LinkedTo.Num() == 0)
		{
			CompilerContext.MessageLog.Warning(*FString::Printf(*LOCTEXT("NodeNeverExecuted_Warning", "@@ will never be executed").ToString()), Node);
			return;
		}

		// Generate the output impulse from this node
		UEdGraphPin* CondPin = Context.FindRequiredPinByName(Node, CompilerContext.GetSchema()->PN_Condition, EGPD_Input);
		UEdGraphPin* ThenPin = Context.FindRequiredPinByName(Node, CompilerContext.GetSchema()->PN_Then, EGPD_Output);
		UEdGraphPin* ElsePin = Context.FindRequiredPinByName(Node, CompilerContext.GetSchema()->PN_Else, EGPD_Output);
		if (Context.ValidatePinType(ThenPin, ExpectedExecPinType) &&
			Context.ValidatePinType(ElsePin, ExpectedExecPinType) &&
			Context.ValidatePinType(CondPin, ExpectedBoolPinType))
		{
			UEdGraphPin* PinToTry = FEdGraphUtilities::GetNetFromPin(CondPin);
			FBPTerminal** CondTerm = Context.NetMap.Find(PinToTry);

			if (CondTerm != NULL) //
			{
				// First skip the if, if the term is false
				{
					FBlueprintCompiledStatement& SkipIfGoto = Context.AppendStatementForNode(Node);
					SkipIfGoto.Type = KCST_GotoIfNot;
					SkipIfGoto.LHS = *CondTerm;
					Context.GotoFixupRequestMap.Add(&SkipIfGoto, ElsePin);
				}

				// Now go to the If branch
				{
					FBlueprintCompiledStatement& GotoThen = Context.AppendStatementForNode(Node);
					GotoThen.Type = KCST_UnconditionalGoto;
					GotoThen.LHS = *CondTerm;
					Context.GotoFixupRequestMap.Add(&GotoThen, ThenPin);
				}
			}
			else
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("ResolveTermPassed_Error", "Failed to resolve term passed into @@").ToString(), CondPin);
			}
		}
	}
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		UK2Node_FunctionEntry* EntryNode = CastChecked<UK2Node_FunctionEntry>(Node);
		//check(EntryNode->SignatureName != NAME_None);
		if (EntryNode->SignatureName == CompilerContext.GetSchema()->FN_ExecuteUbergraphBase)
		{
			UEdGraphPin* EntryPointPin = Node->FindPin(CompilerContext.GetSchema()->PN_EntryPoint);
			FBPTerminal** pTerm = Context.NetMap.Find(EntryPointPin);
			if ((EntryPointPin != NULL) && (pTerm != NULL))
			{
				FBlueprintCompiledStatement& ComputedGotoStatement = Context.AppendStatementForNode(Node);
				ComputedGotoStatement.Type = KCST_ComputedGoto;
				ComputedGotoStatement.LHS = *pTerm;
			}
			else
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("NoEntryPointPin_Error", "Expected a pin named EntryPoint on @@").ToString(), Node);
			}
		}
		else
		{
			// Generate the output impulse from this node
			GenerateSimpleThenGoto(Context, *Node);
		}
	}
void FKCHandler_ClearDelegate::Compile(FKismetFunctionContext& Context, UEdGraphNode* Node)
{
	UK2Node_BaseMCDelegate* DelegateNode = CastChecked<UK2Node_BaseMCDelegate>(Node);

	UEdGraphPin* SelfPin = CompilerContext.GetSchema()->FindSelfPin(*DelegateNode, EEdGraphPinDirection::EGPD_Input);
	check(SelfPin);

	TArray<UEdGraphPin*> Links = SelfPin->LinkedTo;
	if(!Links.Num())
	{
		Links.Add(SelfPin);
	}

	for (auto NetIt = Links.CreateIterator(); NetIt; ++NetIt)
	{
		UEdGraphPin* NetPin = *NetIt;
		check(NetPin);

		FBlueprintCompiledStatement& AddStatement = Context.AppendStatementForNode(DelegateNode);
		AddStatement.Type = KCST_ClearMulticastDelegate;

		FBPTerminal** VarDelegate = InnerTermMap.Find(FDelegateOwnerId(NetPin, DelegateNode));
		check(VarDelegate && *VarDelegate);
		AddStatement.LHS = *VarDelegate;
	}

	GenerateSimpleThenGoto(Context, *DelegateNode, DelegateNode->FindPin(CompilerContext.GetSchema()->PN_Then));
	FNodeHandlingFunctor::Compile(Context, DelegateNode);
}
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		UK2Node_MakeArray* ArrayNode = CastChecked<UK2Node_MakeArray>(Node);
		UEdGraphPin* OutputPin = ArrayNode->GetOutputPin();

		FBPTerminal** ArrayTerm = Context.NetMap.Find(OutputPin);
		check(ArrayTerm);

		FBlueprintCompiledStatement& CreateArrayStatement = Context.AppendStatementForNode(Node);
		CreateArrayStatement.Type = KCST_CreateArray;
		CreateArrayStatement.LHS = *ArrayTerm;

		for(auto PinIt = Node->Pins.CreateIterator(); PinIt; ++PinIt)
		{
			UEdGraphPin* Pin = *PinIt;
			if(Pin && Pin->Direction == EGPD_Input)
			{
				FBPTerminal** InputTerm = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(Pin));
				if( InputTerm )
				{
					CreateArrayStatement.RHS.Add(*InputTerm);
				}
			}
		}
	}
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		const UK2Node_DelegateSet* DelegateNode = Cast<UK2Node_DelegateSet>(Node);
		check(DelegateNode);

		// Verify that the event has a darget to be bound to
		UEdGraphPin* DelegateOwnerPin = DelegateNode->GetDelegateOwner();

		if (DelegateOwnerPin == nullptr || DelegateOwnerPin->LinkedTo.Num() == 0)
		{
			CompilerContext.MessageLog.Error(*FString(*LOCTEXT("FindDynamicallyBoundDelegate_Error", "Couldn't find target for dynamically bound delegate node @@").ToString()), DelegateNode);
			return;
		}

		FBPTerminal** pDelegateOwnerTerm = Context.NetMap.Find(DelegateOwnerPin);

		// Create a delegate name term
		FBPTerminal* DelegateNameTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
		DelegateNameTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Name;
		DelegateNameTerm->Name = DelegateNode->GetDelegateTargetEntryPointName().ToString();
		DelegateNameTerm->bIsLiteral = true;

		// Create a local delegate, which we can then add to the multicast delegate
		FBPTerminal* LocalDelegate = *LocalDelegateMap.Find(Node);
		FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
		Statement.Type = KCST_Assignment;
		Statement.LHS = LocalDelegate;
		Statement.RHS.Add(DelegateNameTerm);

		// Add the local delegate to the MC delegate
		FBlueprintCompiledStatement& AddStatement = Context.AppendStatementForNode(Node);
		AddStatement.Type = KCST_AddMulticastDelegate;
		AddStatement.LHS = *pDelegateOwnerTerm;
		AddStatement.RHS.Add(LocalDelegate);

		GenerateSimpleThenGoto(Context, *Node, DelegateNode->FindPin(CompilerContext.GetSchema()->PN_Then));

		FNodeHandlingFunctor::Compile(Context, Node);
	}
	void InnerAssignment(FKismetFunctionContext& Context, UEdGraphNode* Node, UEdGraphPin* VariablePin, UEdGraphPin* ValuePin)
	{
		FBPTerminal** VariableTerm = Context.NetMap.Find(VariablePin);
		if (VariableTerm == NULL)
		{
			VariableTerm = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(VariablePin));
		}

		FBPTerminal** ValueTerm = Context.LiteralHackMap.Find(ValuePin);
		if (ValueTerm == NULL)
		{
			ValueTerm = Context.NetMap.Find(FEdGraphUtilities::GetNetFromPin(ValuePin));
		}

		if ((VariableTerm != NULL) && (ValueTerm != NULL))
		{
			FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);

			Statement.Type = KCST_Assignment;
			Statement.LHS = *VariableTerm;
			Statement.RHS.Add(*ValueTerm);

			if (!(*VariableTerm)->IsTermWritable())
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("WriteConst_Error", "Cannot write to const @@").ToString(), VariablePin);
			}
		}
		else
		{
			if (VariablePin != ValuePin)
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("ResolveValueIntoVariablePin_Error", "Failed to resolve term @@ passed into @@").ToString(), ValuePin, VariablePin);
			}
			else
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("ResolveTermPassed_Error", "Failed to resolve term passed into @@").ToString(), VariablePin);
			}
		}
	}
void FKCHandler_CreateDelegate::Compile(FKismetFunctionContext& Context, UEdGraphNode* Node)
{
	UK2Node_CreateDelegate * DelegateNode = CastChecked<UK2Node_CreateDelegate>(Node);
	check(NULL != DelegateNode);

	FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
	Statement.Type = KCST_BindDelegate;

	{
		UEdGraphPin* OutPin = DelegateNode->GetDelegateOutPin();
		check(NULL != OutPin);
		UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(OutPin);
		check(NULL != Net);
		FBPTerminal** FoundTerm = Context.NetMap.Find(Net);
		check(FoundTerm && *FoundTerm);
		Statement.LHS = *FoundTerm;
	}

	{
		FBPTerminal* DelegateNameTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
		DelegateNameTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Name;
		DelegateNameTerm->Name = DelegateNode->GetFunctionName().ToString();
		DelegateNameTerm->bIsLiteral = true;
		Statement.RHS.Add(DelegateNameTerm);
	}

	{
		UEdGraphPin* InputPin = DelegateNode->GetObjectInPin();
		check(NULL != InputPin);
		UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(InputPin);
		FBPTerminal** FoundTerm = Context.NetMap.Find(Net);
		check(FoundTerm && *FoundTerm);
		Statement.RHS.Add(*FoundTerm);
	}

	FNodeHandlingFunctor::Compile(Context, Node);
}
Example #9
0
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		// Cast the node and get all the input pins
		UK2Node_Select* SelectNode = Cast<UK2Node_Select>(Node);
		TArray<UEdGraphPin*> OptionPins;
		SelectNode->GetOptionPins(OptionPins);
		UEdGraphPin* IndexPin = SelectNode->GetIndexPin();

		// Get the kismet term for the (Condition or Index) that will determine which option to use
		UEdGraphPin* PinToTry = FEdGraphUtilities::GetNetFromPin(IndexPin);
		FBPTerminal** ConditionTerm = Context.NetMap.Find(PinToTry);

		// Get the kismet term for the return value
		UEdGraphPin* ReturnPin = SelectNode->GetReturnValuePin();
		FBPTerminal** ReturnTerm = Context.NetMap.Find(ReturnPin);

		// Don't proceed if there is no return value or there is no selection
		if (ConditionTerm != NULL && ReturnTerm != NULL)
		{
			FName ConditionalFunctionName = "";
			UClass* ConditionalFunctionClass = NULL;
			SelectNode->GetConditionalFunction(ConditionalFunctionName, &ConditionalFunctionClass);
			UFunction* ConditionFunction = FindField<UFunction>(ConditionalFunctionClass, ConditionalFunctionName);

			// Find the local boolean for use in the equality call function below (BoolTerm = result of EqualEqual_IntInt or NotEqual_BoolBool)
			FBPTerminal* BoolTerm = BoolTermMap.FindRef(SelectNode);

			// We need to keep a pointer to the previous IfNot statement so it can be linked to the next conditional statement
			FBlueprintCompiledStatement* PrevIfNotStatement = NULL;

			// Keep an array of all the unconditional goto statements so we can clean up their jumps after the noop statement is created
			TArray<FBlueprintCompiledStatement*> GotoStatementList;

			// Loop through all the options
			for (int32 OptionIdx = 0; OptionIdx < OptionPins.Num(); OptionIdx++)
			{
				// Create a CallFunction statement with the condition function from the Select class
				FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
				Statement.Type = KCST_CallFunction;
				Statement.FunctionToCall = ConditionFunction;
				Statement.FunctionContext = NULL;
				Statement.bIsParentContext = false;
				// BoolTerm will be the return value of the condition statement
				Statement.LHS = BoolTerm;
				// The condition passed into the Select node
				Statement.RHS.Add(*ConditionTerm);
				// Create a local int for use in the equality call function below (LiteralTerm = the right hand side of the EqualEqual_IntInt or NotEqual_BoolBool statement)
				FBPTerminal* LiteralTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
				LiteralTerm->bIsLiteral = true;
				LiteralTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int;
				LiteralTerm->Name = FString::Printf(TEXT("%d"), OptionIdx);
				Statement.RHS.Add(LiteralTerm);
				// If there is a previous IfNot statement, hook this one to that one for jumping
				if (PrevIfNotStatement)
				{
					Statement.bIsJumpTarget = true;
					PrevIfNotStatement->TargetLabel = &Statement;
				}

				// Create a GotoIfNot statement using the BoolTerm from above as the condition
				FBlueprintCompiledStatement* IfNotStatement = &Context.AppendStatementForNode(Node);
				IfNotStatement->Type = KCST_GotoIfNot;
				IfNotStatement->LHS = BoolTerm;

				// Create an assignment statement
				FBlueprintCompiledStatement& AssignStatement = Context.AppendStatementForNode(Node);
				AssignStatement.Type = KCST_Assignment;
				AssignStatement.LHS = *ReturnTerm;
				// Get the kismet term from the option pin
				UEdGraphPin* OptionPinToTry = FEdGraphUtilities::GetNetFromPin(OptionPins[OptionIdx]);
				FBPTerminal** OptionTerm = Context.NetMap.Find(OptionPinToTry);
				if (!OptionTerm)
				{
					Context.MessageLog.Error(*LOCTEXT("Error_UnregisterOptionPin", "Unregister option pin @@").ToString(), OptionPins[OptionIdx]);
					return;
				}
				AssignStatement.RHS.Add(*OptionTerm);

				// Create an unconditional goto to exit the node
				FBlueprintCompiledStatement& GotoStatement = Context.AppendStatementForNode(Node);
				GotoStatement.Type = KCST_UnconditionalGoto;
				GotoStatementList.Add(&GotoStatement);

				// If this is the last IfNot statement, hook the jump to an error message
				if (OptionIdx == OptionPins.Num() - 1)
				{
					// Create a CallFunction statement for doing a print string of our error message
					FBlueprintCompiledStatement& PrintStatement = Context.AppendStatementForNode(Node);
					PrintStatement.Type = KCST_CallFunction;
					PrintStatement.bIsJumpTarget = true;
					FName PrintStringFunctionName = "";
					UClass* PrintStringFunctionClass = NULL;
					SelectNode->GetPrintStringFunction(PrintStringFunctionName, &PrintStringFunctionClass);
					UFunction* PrintFunction = FindField<UFunction>(PrintStringFunctionClass, PrintStringFunctionName);
					PrintStatement.FunctionToCall = PrintFunction;
					PrintStatement.FunctionContext = NULL;
					PrintStatement.bIsParentContext = false;

					// Create a local int for use in the equality call function below (LiteralTerm = the right hand side of the EqualEqual_IntInt or NotEqual_BoolBool statement)
					FBPTerminal* LiteralStringTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
					LiteralStringTerm->bIsLiteral = true;
					LiteralStringTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String;

					FString SelectionNodeType(TEXT("NONE"));
					if (IndexPin)
					{
						UEnum* EnumObject = Cast<UEnum>(IndexPin->PinType.PinSubCategoryObject.Get());
						if (EnumObject != NULL)
						{
							SelectionNodeType = EnumObject->GetName();
						}
						else
						{
							// Not an enum, so just use the basic type
							SelectionNodeType = IndexPin->PinType.PinCategory;
						}
					}

					const UEdGraph* OwningGraph = Context.MessageLog.FindSourceObjectTypeChecked<UEdGraph>( SelectNode->GetGraph() );
					LiteralStringTerm->Name =
						FString::Printf(*LOCTEXT("SelectNodeIndexWarning", "Graph %s: Selection Node of type %s failed! Out of bounds indexing of the options. There are only %d options available.").ToString(),
						(OwningGraph) ? *OwningGraph->GetFullName() : TEXT("NONE"),
						*SelectionNodeType,
						OptionPins.Num());
					PrintStatement.RHS.Add(LiteralStringTerm);

					// Hook the IfNot statement's jump target to this statement
					IfNotStatement->TargetLabel = &PrintStatement;
				}

				PrevIfNotStatement = IfNotStatement;
			}

			// Create a noop to jump to so the unconditional goto statements can exit the node after successful assignment
			FBlueprintCompiledStatement& NopStatement = Context.AppendStatementForNode(Node);
			NopStatement.Type = KCST_Nop;
			NopStatement.bIsJumpTarget = true;
			// Loop through the unconditional goto statements and fix their jump targets
			for (auto It = GotoStatementList.CreateConstIterator(); It; It++)
			{
				(*It)->TargetLabel = &NopStatement;
			}
		}
	}
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		UK2Node_Switch* SwitchNode = CastChecked<UK2Node_Switch>(Node);

		FEdGraphPinType ExpectedExecPinType;
		ExpectedExecPinType.PinCategory = UEdGraphSchema_K2::PC_Exec;

		// Make sure that the input pin is connected and valid for this block
		UEdGraphPin* ExecTriggeringPin = Context.FindRequiredPinByName(SwitchNode, UEdGraphSchema_K2::PN_Execute, EGPD_Input);
		if ((ExecTriggeringPin == NULL) || !Context.ValidatePinType(ExecTriggeringPin, ExpectedExecPinType))
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("NoValidExecutionPinForSwitch_Error", "@@ must have a valid execution pin @@").ToString()), SwitchNode, ExecTriggeringPin);
			return;
		}

		// Make sure that the selection pin is connected and valid for this block
		UEdGraphPin* SelectionPin = SwitchNode->GetSelectionPin();
		if ((SelectionPin == NULL) || !Context.ValidatePinType(SelectionPin, SwitchNode->GetPinType()))
		{
			CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("NoValidSelectionPinForSwitch_Error", "@@ must have a valid execution pin @@").ToString()), SwitchNode, SelectionPin);
			return;
		}

		// Find the boolean intermediate result term, so we can track whether the compare was successful
		FBPTerminal* BoolTerm = BoolTermMap.FindRef(SwitchNode);

		// Generate the output impulse from this node
		UEdGraphPin* SwitchSelectionNet = FEdGraphUtilities::GetNetFromPin(SelectionPin);
		FBPTerminal* SwitchSelectionTerm = Context.NetMap.FindRef(SwitchSelectionNet);

		if ((BoolTerm != NULL) && (SwitchSelectionTerm != NULL))
		{
			UEdGraphNode* TargetNode = NULL;
			UEdGraphPin* FuncPin = SwitchNode->GetFunctionPin();
			FBPTerminal* FuncContext = Context.NetMap.FindRef(FuncPin);
			UEdGraphPin* DefaultPin = SwitchNode->GetDefaultPin();

			// Pull out function to use
			UClass* FuncClass = Cast<UClass>(FuncPin->PinType.PinSubCategoryObject.Get());
			UFunction* FunctionPtr = FindField<UFunction>(FuncClass, *FuncPin->PinName);
			check(FunctionPtr);

			// Run thru all the output pins except for the default label
			for (auto PinIt = SwitchNode->Pins.CreateIterator(); PinIt; ++PinIt)
			{
				UEdGraphPin* Pin = *PinIt;

				if ((Pin->Direction == EGPD_Output) && (Pin != DefaultPin))
				{
					// Create a term for the switch case value
					FBPTerminal* CaseValueTerm = new (Context.Literals) FBPTerminal();
					CaseValueTerm->Name = Pin->PinName;
					CaseValueTerm->Type = SelectionPin->PinType;
					CaseValueTerm->SourcePin = Pin;
					CaseValueTerm->bIsLiteral = true;

					// Call the comparison function associated with this switch node
					FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(SwitchNode);
					Statement.Type = KCST_CallFunction;
					Statement.FunctionToCall = FunctionPtr;
					Statement.FunctionContext = FuncContext;
					Statement.bIsParentContext = false;

					Statement.LHS = BoolTerm;
					Statement.RHS.Add(SwitchSelectionTerm);
					Statement.RHS.Add(CaseValueTerm);

					// Jump to output if strings are actually equal
					FBlueprintCompiledStatement& IfFailTest_SucceedAtBeingEqualGoto = Context.AppendStatementForNode(SwitchNode);
					IfFailTest_SucceedAtBeingEqualGoto.Type = KCST_GotoIfNot;
					IfFailTest_SucceedAtBeingEqualGoto.LHS = BoolTerm;

					Context.GotoFixupRequestMap.Add(&IfFailTest_SucceedAtBeingEqualGoto, Pin);
				}
			}

			// Finally output default pin
			GenerateSimpleThenGoto(Context, *SwitchNode, DefaultPin);
		}
		else
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("ResolveTermPassed_Error", "Failed to resolve term passed into @@").ToString(), SelectionPin);
		}
	}
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);

		if (!ObjectToCast || !(*ObjectToCast))
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("InvalidConnectionOnNode_Error", "Node @@ has an invalid connection on @@").ToString(), Node, SourceObjectPin);
			return;
		}
	}

	// Output pin
	const UEdGraphPin* CastOutputPin = DynamicCastNode->GetCastResultPin();
	if( !CastOutputPin )
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("InvalidDynamicCastClass_Error", "Node @@ has an invalid target class").ToString(), Node);
		return;
	}

	FBPTerminal** CastResultTerm = Context.NetMap.Find(CastOutputPin);
	if (!CastResultTerm || !(*CastResultTerm))
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("InvalidDynamicCastClass_CompilerError", "Node @@ has an invalid target class. (Inner compiler error?)").ToString(), Node);
		return;
	}

	// Create a literal term from the class specified in the node
	FBPTerminal* ClassTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
	ClassTerm->Name = DynamicCastNode->TargetType->GetName();
	ClassTerm->bIsLiteral = true;
	ClassTerm->Source = Node;
	ClassTerm->ObjectLiteral = DynamicCastNode->TargetType;
	ClassTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Class;

	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)
	{
		if (bIsOutputInterface)
		{
			CastOpType = KCST_CrossInterfaceCast;
		}
		else
		{
			CastOpType = KCST_CastInterfaceToObj;
		}
	}
	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;
	}

	// Cast Statement
	FBlueprintCompiledStatement& CastStatement = Context.AppendStatementForNode(Node);
	CastStatement.Type = CastOpType;
	CastStatement.LHS = *CastResultTerm;
	CastStatement.RHS.Add(ClassTerm);
	CastStatement.RHS.Add(*ObjectToCast);

	FBPTerminal** BoolSuccessTerm = nullptr;
	if (UEdGraphPin* BoolSuccessPin = DynamicCastNode->GetBoolSuccessPin())
	{
		BoolSuccessTerm = Context.NetMap.Find(BoolSuccessPin);
	}
	else
	{
		BoolSuccessTerm = BoolTermMap.Find(DynamicCastNode);
	}	
	check(BoolSuccessTerm != nullptr);

	// Check result of cast statement
	FBlueprintCompiledStatement& CheckResultStatement = Context.AppendStatementForNode(Node);
	CheckResultStatement.Type = KCST_ObjectToBool;
	CheckResultStatement.LHS  = *BoolSuccessTerm;
	CheckResultStatement.RHS.Add(*CastResultTerm);

	UEdGraphPin* SuccessExecPin = DynamicCastNode->GetValidCastPin();
	bool const bIsPureCast = (SuccessExecPin == nullptr);
	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;
		FailCastGoto.LHS  = *BoolSuccessTerm;
		Context.GotoFixupRequestMap.Add(&FailCastGoto, FailurePin);

		// Successful cast...hit the success output node
		FBlueprintCompiledStatement& SuccessCastGoto = Context.AppendStatementForNode(Node);
		SuccessCastGoto.Type = KCST_UnconditionalGoto;
		SuccessCastGoto.LHS  = *BoolSuccessTerm;
		Context.GotoFixupRequestMap.Add(&SuccessCastGoto, SuccessExecPin);
	}
}
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		UEdGraphPin* InputPin = NULL;
		for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
		{
			UEdGraphPin* Pin = Node->Pins[PinIndex];
			if (Pin && (EGPD_Input == Pin->Direction))
			{
				InputPin = Pin;
				break;
			}
		}
		UEdGraphPin *InNet = FEdGraphUtilities::GetNetFromPin(InputPin);
		UClass *Class = Cast<UClass>(StaticLoadObject(UClass::StaticClass(), NULL, TEXT("class'VaRestPlugin.VaRestJsonObject'")));
		FBPTerminal **SourceTerm = Context.NetMap.Find(InNet);
		if (SourceTerm == nullptr)
		{
			return;
		}
		for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex)
		{
			UEdGraphPin* Pin = Node->Pins[PinIndex];
			if (Pin && (EGPD_Output == Pin->Direction))
			{
				if (Pin->LinkedTo.Num() < 1)
				{
					continue;
				}
				FBPTerminal **Target = Context.NetMap.Find(Pin);
				const FString &FieldName = Pin->PinName;
				const FString &FieldType = Pin->PinType.PinCategory;
				FBPTerminal* FieldNameTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
				FieldNameTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String;
				FieldNameTerm->Source = Pin;
				FieldNameTerm->Name = FieldName;
				FieldNameTerm->TextLiteral = FText::FromString(FieldName);
 				FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
				FName FunctionName;
				bool bIsArray = Pin->PinType.bIsArray;
				if (FieldType == CompilerContext.GetSchema()->PC_Boolean)
				{
					FunctionName = bIsArray ? TEXT("GetBoolArrayField") : TEXT("GetBoolField");
				}
				else if (FieldType == CompilerContext.GetSchema()->PC_Float)
				{
					FunctionName = bIsArray ? TEXT("GetNumberArrayField") : TEXT("GetNumberField");
				}
				else if (FieldType == CompilerContext.GetSchema()->PC_String)
				{
					FunctionName = bIsArray ? TEXT("GetStringArrayField") : TEXT("GetStringField");
				}
				else if (FieldType == CompilerContext.GetSchema()->PC_Object)
				{
					FunctionName = bIsArray ? TEXT("GetObjectArrayField") : TEXT("GetObjectField");
				}
				else
				{
					continue;
				}
			
				UFunction *FunctionPtr = Class->FindFunctionByName(FunctionName);
				Statement.Type = KCST_CallFunction;
				Statement.FunctionToCall = FunctionPtr;
				Statement.FunctionContext = *SourceTerm;
				Statement.bIsParentContext = false;
				Statement.LHS = *Target;
				Statement.RHS.Add(FieldNameTerm);
			}
		}
	}
	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node)
	{
		/////////////////////////////////////////////////////////////////////////////////////
		// Get the node, retrieve the helper functions, and create a local "Index" variable
		/////////////////////////////////////////////////////////////////////////////////////

		// Get the multi gate node and the helper functions
		UK2Node_MultiGate* GateNode = Cast<UK2Node_MultiGate>(Node);

		// Get function names and class pointers to helper nodes
		FName MarkBitFunctionName = "";
		UClass* MarkBitFunctionClass = NULL;
		GateNode->GetMarkBitFunction(MarkBitFunctionName, &MarkBitFunctionClass);
		UFunction* MarkBitFunction = FindField<UFunction>(MarkBitFunctionClass, MarkBitFunctionName);

		FName HasUnmarkedBitFunctionName = "";
		UClass* HasUnmarkedBitFunctionClass = NULL;
		GateNode->GetHasUnmarkedBitFunction(HasUnmarkedBitFunctionName, &HasUnmarkedBitFunctionClass);
		UFunction* HasUnmarkedBitFunction = FindField<UFunction>(HasUnmarkedBitFunctionClass, HasUnmarkedBitFunctionName);

		FName GetUnmarkedBitFunctionName = "";
		UClass* GetUnmarkedBitFunctionClass = NULL;
		GateNode->GetUnmarkedBitFunction(GetUnmarkedBitFunctionName, &GetUnmarkedBitFunctionClass);
		UFunction* GetUnmarkedBitFunction = FindField<UFunction>(GetUnmarkedBitFunctionClass, GetUnmarkedBitFunctionName);

		FName ConditionalFunctionName = "";
		UClass* ConditionalFunctionClass = NULL;
		GateNode->GetConditionalFunction(ConditionalFunctionName, &ConditionalFunctionClass);
		UFunction* ConditionFunction = FindField<UFunction>(ConditionalFunctionClass, ConditionalFunctionName);

		FName EqualityFunctionName = "";
		UClass* EqualityFunctionClass = NULL;
		GateNode->GetEqualityFunction(EqualityFunctionName, &EqualityFunctionClass);
		UFunction* EqualityFunction = FindField<UFunction>(EqualityFunctionClass, EqualityFunctionName);

		FName BoolNotEqualFunctionName = "";
		UClass* BoolNotEqualFunctionClass = NULL;
		GateNode->GetBoolNotEqualFunction(BoolNotEqualFunctionName, &BoolNotEqualFunctionClass);
		UFunction* BoolNotEqualFunction = FindField<UFunction>(BoolNotEqualFunctionClass, BoolNotEqualFunctionName);

		FName PrintStringFunctionName = "";
		UClass* PrintStringFunctionClass = NULL;
		GateNode->GetPrintStringFunction(PrintStringFunctionName, &PrintStringFunctionClass);
		UFunction* PrintFunction = FindField<UFunction>(PrintStringFunctionClass, PrintStringFunctionName);

		FName ClearBitsFunctionName = "";
		UClass* ClearBitsFunctionClass = NULL;
		GateNode->GetClearAllBitsFunction(ClearBitsFunctionName, &ClearBitsFunctionClass);
		UFunction* ClearBitsFunction = FindField<UFunction>(ClearBitsFunctionClass, ClearBitsFunctionName);

		// Find the data terms if there is already a data node from expansion phase
		FBPTerminal* DataTerm = NULL;
		if (GateNode->DataNode)
		{
			UEdGraphPin* PinToTry = FEdGraphUtilities::GetNetFromPin(GateNode->DataNode->GetVariablePin());
			FBPTerminal** DataTermPtr = Context.NetMap.Find(PinToTry);
			DataTerm = (DataTermPtr != NULL) ? *DataTermPtr : NULL;
		}
		// Else we built it in the net registration, so find it
		else
		{
			DataTerm = DataTermMap.FindRef(GateNode);
		}
		check(DataTerm);

		// Used for getting all the nets from pins
		UEdGraphPin* PinToTry = NULL;

		// The StartIndex passed into the multi gate node
		PinToTry = FEdGraphUtilities::GetNetFromPin(GateNode->GetStartIndexPin());
		FBPTerminal** StartIndexPinTerm = Context.NetMap.Find(PinToTry);

		// Get the bRandom pin as a kismet term from the multi gate node
		PinToTry = FEdGraphUtilities::GetNetFromPin(GateNode->GetIsRandomPin());
		FBPTerminal** RandomTerm = Context.NetMap.Find(PinToTry);

		// Get the Loop pin as a kismet term from the multi gate node
		PinToTry = FEdGraphUtilities::GetNetFromPin(GateNode->GetLoopPin());
		FBPTerminal** LoopTerm = Context.NetMap.Find(PinToTry);

		// Find the local boolean for use in determining if this is the first run of the node or not
		FBPTerminal* FirstRunBoolTerm = FirstRunTermMap.FindRef(GateNode);

		// Create a literal pin that represents a -1 value
		FBPTerminal* InvalidIndexTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
		InvalidIndexTerm->bIsLiteral = true;
		InvalidIndexTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int;
		InvalidIndexTerm->Name = TEXT("-1");

		// Create a literal pin that represents a true value
		FBPTerminal* TrueBoolTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
		TrueBoolTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Boolean;
		TrueBoolTerm->bIsLiteral = true;
		TrueBoolTerm->Name = TEXT("true");

		// Get the out pins and create a literal describing how many logical outs there are
		TArray<UEdGraphPin*> OutPins;
		GateNode->GetOutPins(OutPins);
		FBPTerminal* NumOutsTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
		NumOutsTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int;
		NumOutsTerm->bIsLiteral = true;
		NumOutsTerm->Name = FString::Printf(TEXT("%d"), OutPins.Num());

		///////////////////////////////////////////////////
		// See if this is the first time in
		///////////////////////////////////////////////////

		FFunctionScopedTerms& FuncLocals = FunctionTermMap.FindChecked(Context.Function);
		check(FuncLocals.GenericBoolTerm != nullptr);

		// (bIsNotFirstTime != true)
		FBlueprintCompiledStatement& BoolNotEqualStatement = Context.AppendStatementForNode(Node);
		BoolNotEqualStatement.Type = KCST_CallFunction;
		BoolNotEqualStatement.FunctionToCall = BoolNotEqualFunction;
		BoolNotEqualStatement.FunctionContext = NULL;
		BoolNotEqualStatement.bIsParentContext = false;
		// Set the params
		BoolNotEqualStatement.LHS = FuncLocals.GenericBoolTerm;
		BoolNotEqualStatement.RHS.Add(FirstRunBoolTerm);
		BoolNotEqualStatement.RHS.Add(TrueBoolTerm);

		// if (bIsNotFirstTime == false)
		// {
		FBlueprintCompiledStatement& IfFirstTimeStatement = Context.AppendStatementForNode(Node);
		IfFirstTimeStatement.Type = KCST_GotoIfNot;
		IfFirstTimeStatement.LHS = FuncLocals.GenericBoolTerm;

		///////////////////////////////////////////////////////////////////
		// This is the first time in... set the bool and the start index
		///////////////////////////////////////////////////////////////////

		// bIsNotFirstTime = true;
		FBlueprintCompiledStatement& AssignBoolStatement = Context.AppendStatementForNode(Node);
		AssignBoolStatement.Type = KCST_Assignment;
		AssignBoolStatement.LHS = FirstRunBoolTerm;
		AssignBoolStatement.RHS.Add(TrueBoolTerm);

		//////////////////////////////////////////////////////////////////////
		// See if the StartIndex is greater than -1 (they supplied an index)
		//////////////////////////////////////////////////////////////////////

		// (StartIndex > -1)
		FBlueprintCompiledStatement& Statement = Context.AppendStatementForNode(Node);
		Statement.Type = KCST_CallFunction;
		Statement.FunctionToCall = ConditionFunction;
		Statement.FunctionContext = NULL;
		Statement.bIsParentContext = false;
		Statement.LHS = FuncLocals.GenericBoolTerm;
		Statement.RHS.Add(*StartIndexPinTerm);
		Statement.RHS.Add(InvalidIndexTerm);

		// if (StartIndex > -1)
		// {
		FBlueprintCompiledStatement& IfHasIndexStatement = Context.AppendStatementForNode(Node);
		IfHasIndexStatement.Type = KCST_GotoIfNot;
		IfHasIndexStatement.LHS = FuncLocals.GenericBoolTerm;

		///////////////////////////////////////////////////////////////////
		// They supplied a start index so set the index to it
		///////////////////////////////////////////////////////////////////

		// Index = StartIndex; // (StartIndex is from multi gate pin for it)
		FBlueprintCompiledStatement& AssignSuppliedIndexStatement = Context.AppendStatementForNode(Node);
		AssignSuppliedIndexStatement.Type = KCST_Assignment;
		AssignSuppliedIndexStatement.LHS = FuncLocals.IndexTerm;
		AssignSuppliedIndexStatement.RHS.Add(*StartIndexPinTerm);

		// Jump to index usage
		FBlueprintCompiledStatement& ElseGotoIndexUsageStatement = Context.AppendStatementForNode(Node);
		ElseGotoIndexUsageStatement.Type = KCST_UnconditionalGoto;
		// }
		// else
		// {

		///////////////////////////////////////////////////////////////////
		// They did NOT supply a start index so figure one out
		///////////////////////////////////////////////////////////////////

		check(FuncLocals.IndexTerm != nullptr);

		// Index = GetUnmarkedBit(Data, -1, bRandom);
		FBlueprintCompiledStatement& GetStartIndexStatement = Context.AppendStatementForNode(Node);
		GetStartIndexStatement.Type = KCST_CallFunction;
		GetStartIndexStatement.FunctionToCall = GetUnmarkedBitFunction;
		GetStartIndexStatement.bIsParentContext = false;
		GetStartIndexStatement.LHS = FuncLocals.IndexTerm;
		GetStartIndexStatement.RHS.Add(DataTerm);
		GetStartIndexStatement.RHS.Add(*StartIndexPinTerm);
		GetStartIndexStatement.RHS.Add(NumOutsTerm);
		GetStartIndexStatement.RHS.Add(*RandomTerm);
		// Hook the IfHasIndexStatement jump to this node
		GetStartIndexStatement.bIsJumpTarget = true;
		IfHasIndexStatement.TargetLabel = &GetStartIndexStatement;

		// Jump to index usage
		FBlueprintCompiledStatement& StartIndexGotoIndexUsageStatement = Context.AppendStatementForNode(Node);
		StartIndexGotoIndexUsageStatement.Type = KCST_UnconditionalGoto;
		// }
		// }
		// else
		// {
		////////////////////////////////////////////////////////////////////////////
		// Else this is NOT the first time in, see if there is an available index
		////////////////////////////////////////////////////////////////////////////

		// (HasUnmarkedBit())
		FBlueprintCompiledStatement& IsAvailableStatement = Context.AppendStatementForNode(Node);
		IsAvailableStatement.Type = KCST_CallFunction;
		IsAvailableStatement.FunctionToCall = HasUnmarkedBitFunction;
		IsAvailableStatement.FunctionContext = NULL;
		IsAvailableStatement.bIsParentContext = false;
		IsAvailableStatement.LHS = FuncLocals.GenericBoolTerm;
		IsAvailableStatement.RHS.Add(DataTerm);
		IsAvailableStatement.RHS.Add(NumOutsTerm);
		// Hook the IfFirstTimeStatement jump to this node
		IsAvailableStatement.bIsJumpTarget = true;
		IfFirstTimeStatement.TargetLabel = &IsAvailableStatement;

		// if (HasUnmarkedBit())
		// {
		FBlueprintCompiledStatement& IfIsAvailableStatement = Context.AppendStatementForNode(Node);
		IfIsAvailableStatement.Type = KCST_GotoIfNot;
		IfIsAvailableStatement.LHS = FuncLocals.GenericBoolTerm;

		////////////////////////////////////////////////////////////////////////////
		// Has available index so figure it out and jump to its' usage
		////////////////////////////////////////////////////////////////////////////

		// Index = GetUnmarkedBit(Data, -1, bRandom)
		FBlueprintCompiledStatement& GetNextIndexStatement = Context.AppendStatementForNode(Node);
		GetNextIndexStatement.Type = KCST_CallFunction;
		GetNextIndexStatement.FunctionToCall = GetUnmarkedBitFunction;
		GetNextIndexStatement.bIsParentContext = false;
		GetNextIndexStatement.LHS = FuncLocals.IndexTerm;
		GetNextIndexStatement.RHS.Add(DataTerm);
		GetNextIndexStatement.RHS.Add(*StartIndexPinTerm);
		GetNextIndexStatement.RHS.Add(NumOutsTerm);
		GetNextIndexStatement.RHS.Add(*RandomTerm);

		// Goto Index usage
		FBlueprintCompiledStatement& GotoIndexUsageStatement = Context.AppendStatementForNode(Node);
		GotoIndexUsageStatement.Type = KCST_UnconditionalGoto;
		// }
		// else
		// {
		////////////////////////////////////////////////////////////////////////////
		// No available index, see if we can loop
		////////////////////////////////////////////////////////////////////////////

		// if (bLoop)
		FBlueprintCompiledStatement& IfLoopingStatement = Context.AppendStatementForNode(Node);
		IfLoopingStatement.Type = KCST_GotoIfNot;
		IfLoopingStatement.LHS = *LoopTerm;
		IfLoopingStatement.bIsJumpTarget = true;
		IfIsAvailableStatement.TargetLabel = &IfLoopingStatement;
		// {
		////////////////////////////////////////////////////////////////////////////
		// Reset the data and jump back up to "if (HasUnmarkedBit())"
		////////////////////////////////////////////////////////////////////////////

		// Clear the data
		// Data = 0;
		FBlueprintCompiledStatement& ClearDataStatement = Context.AppendStatementForNode(Node);
		ClearDataStatement.Type = KCST_CallFunction;
		ClearDataStatement.FunctionToCall = ClearBitsFunction;
		ClearDataStatement.bIsParentContext = false;
		ClearDataStatement.RHS.Add(DataTerm);

		// Goto back up to attempt an index again
		FBlueprintCompiledStatement& RetryStatement = Context.AppendStatementForNode(Node);
		RetryStatement.Type = KCST_UnconditionalGoto;
		IsAvailableStatement.bIsJumpTarget = true;
		RetryStatement.TargetLabel = &IsAvailableStatement;
		// }
		// else
		// {
		////////////////////////////////////////////////////////////////////////////
		// Dead... Jump to end of thread
		////////////////////////////////////////////////////////////////////////////
		FBlueprintCompiledStatement& NoLoopStatement = Context.AppendStatementForNode(Node);
		NoLoopStatement.Type = KCST_EndOfThread;
		NoLoopStatement.bIsJumpTarget = true;
		IfLoopingStatement.TargetLabel = &NoLoopStatement;
		// }
		// }
		// }

		//////////////////////////////////////
		// We have a valid index so mark it
		//////////////////////////////////////

		// MarkBit(Data, Index);
		FBlueprintCompiledStatement& MarkIndexStatement = Context.AppendStatementForNode(Node);
		MarkIndexStatement.Type = KCST_CallFunction;
		MarkIndexStatement.FunctionToCall = MarkBitFunction;
		MarkIndexStatement.bIsParentContext = false;
		MarkIndexStatement.LHS = FuncLocals.IndexTerm;
		MarkIndexStatement.RHS.Add(DataTerm);
		MarkIndexStatement.RHS.Add(FuncLocals.IndexTerm);

		// Setup jump label
		MarkIndexStatement.bIsJumpTarget = true;
		GotoIndexUsageStatement.TargetLabel = &MarkIndexStatement;
		ElseGotoIndexUsageStatement.TargetLabel = &MarkIndexStatement;
		StartIndexGotoIndexUsageStatement.TargetLabel = &MarkIndexStatement;

		/////////////////////////////////////////////////////////////////////////
		// We have a valid index so mark it, then find the correct exec out pin
		/////////////////////////////////////////////////////////////////////////

		// Call the correct exec pin out of the multi gate node
		FBlueprintCompiledStatement* PrevIndexEqualityStatement = NULL;
		FBlueprintCompiledStatement* PrevIfIndexMatchesStatement = NULL;
		for (int32 OutIdx = 0; OutIdx < OutPins.Num(); OutIdx++)
		{
			// (Index == OutIdx)
			FBlueprintCompiledStatement& IndexEqualityStatement = Context.AppendStatementForNode(Node);
			IndexEqualityStatement.Type = KCST_CallFunction;
			IndexEqualityStatement.FunctionToCall = EqualityFunction;
			IndexEqualityStatement.FunctionContext = NULL;
			IndexEqualityStatement.bIsParentContext = false;
			// LiteralIndexTerm will be the right side of the == statemnt
			FBPTerminal* LiteralIndexTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
			LiteralIndexTerm->bIsLiteral = true;
			LiteralIndexTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int;
			LiteralIndexTerm->Name = FString::Printf(TEXT("%d"), OutIdx);
			// Set the params
			IndexEqualityStatement.LHS = FuncLocals.GenericBoolTerm;
			IndexEqualityStatement.RHS.Add(FuncLocals.IndexTerm);
			IndexEqualityStatement.RHS.Add(LiteralIndexTerm);

			// if (Index == OutIdx)
			FBlueprintCompiledStatement& IfIndexMatchesStatement = Context.AppendStatementForNode(Node);
			IfIndexMatchesStatement.Type = KCST_GotoIfNot;
			IfIndexMatchesStatement.LHS = FuncLocals.GenericBoolTerm;
			// {
			//////////////////////////////////////
			// Found a match - Jump there
			//////////////////////////////////////

			GenerateSimpleThenGoto(Context, *GateNode, OutPins[OutIdx]);
			// }
			// else
			// {
			////////////////////////////////////////////////////
			// Not a match so loop will attempt the next index
			////////////////////////////////////////////////////

			if (PrevIndexEqualityStatement && PrevIfIndexMatchesStatement)
			{
				// Attempt next index
				IndexEqualityStatement.bIsJumpTarget = true;
				PrevIfIndexMatchesStatement->TargetLabel = &IndexEqualityStatement;
			}
			// }

			PrevIndexEqualityStatement = &IndexEqualityStatement;
			PrevIfIndexMatchesStatement = &IfIndexMatchesStatement;
		}

		check(PrevIfIndexMatchesStatement);

		// Should have jumped to proper index, print error (should never happen)
		// Create a CallFunction statement for doing a print string of our error message
		FBlueprintCompiledStatement& PrintStatement = Context.AppendStatementForNode(Node);
		PrintStatement.Type = KCST_CallFunction;
		PrintStatement.bIsJumpTarget = true;
		PrintStatement.FunctionToCall = PrintFunction;
		PrintStatement.FunctionContext = NULL;
		PrintStatement.bIsParentContext = false;
		// Create a local int for use in the equality call function below (LiteralTerm = the right hand side of the EqualEqual_IntInt or NotEqual_BoolBool statement)
		FBPTerminal* LiteralStringTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
		LiteralStringTerm->bIsLiteral = true;
		LiteralStringTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_String;
		LiteralStringTerm->Name = FString::Printf(*LOCTEXT("MultiGateNode IndexWarning", "MultiGate Node failed! Out of bounds indexing of the out pins. There are only %d outs available.").ToString(), OutPins.Num());
		PrintStatement.RHS.Add(LiteralStringTerm);
		// Hook the IfNot statement's jump target to this statement
		PrevIfIndexMatchesStatement->TargetLabel = &PrintStatement;
	}