virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) { FNodeHandlingFunctor::RegisterNets(Context, Node); const FString BaseNetName = Context.NetNameMap->MakeValidName(Node); // Create a term to store a bool that determines if we're in the first execution of the node or not FBPTerminal* FirstRunTerm = Context.CreateLocalTerminal(); FirstRunTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Boolean; FirstRunTerm->Source = Node; FirstRunTerm->Name = BaseNetName + TEXT("_FirstRun"); FirstRunTermMap.Add(Node, FirstRunTerm); UK2Node_MultiGate* GateNode = Cast<UK2Node_MultiGate>(Node); // If there is already a data node from expansion phase if (!GateNode || !GateNode->DataNode) { FBPTerminal* DataTerm = Context.CreateLocalTerminal(); DataTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int; DataTerm->Source = Node; DataTerm->Name = BaseNetName + TEXT("_Data"); DataTermMap.Add(Node, DataTerm); } FFunctionScopedTerms& FuncLocals = FunctionTermMap.FindOrAdd(Context.Function); // Create a local scratch bool for run-time if there isn't already one if (!FuncLocals.GenericBoolTerm) { FuncLocals.GenericBoolTerm = Context.CreateLocalTerminal(); FuncLocals.GenericBoolTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Boolean; FuncLocals.GenericBoolTerm->Source = Node; FuncLocals.GenericBoolTerm->Name = BaseNetName + TEXT("_ScratchBool"); } // Create a local scratch int for run-time index tracking if there isn't already one if (!FuncLocals.IndexTerm) { FuncLocals.IndexTerm = Context.CreateLocalTerminal(); FuncLocals.IndexTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Int; FuncLocals.IndexTerm->Source = Node; FuncLocals.IndexTerm->Name = BaseNetName + TEXT("_ScratchIndex"); } }
virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override { UK2Node_Switch* SwitchNode = Cast<UK2Node_Switch>(Node); FNodeHandlingFunctor::RegisterNets(Context, Node); // Create a term to determine if the compare was successful or not //@TODO: Ideally we just create one ever, not one per switch FBPTerminal* BoolTerm = Context.CreateLocalTerminal(); BoolTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Boolean; BoolTerm->Source = Node; BoolTerm->Name = Context.NetNameMap->MakeValidName(Node) + TEXT("_CmpSuccess"); BoolTermMap.Add(Node, BoolTerm); }
virtual void RegisterNet(FKismetFunctionContext& Context, UEdGraphPin* Net) override { // This net is an anonymous temporary variable FBPTerminal* Term = Context.CreateLocalTerminal(Context.IsEventGraph() ? ETerminalSpecification::TS_ForcedShared : ETerminalSpecification::TS_Unspecified); FString NetName = Context.NetNameMap->MakeValidName(Net); Term->CopyFromPin(Net, NetName); UK2Node_TemporaryVariable* TempVarNode = CastChecked<UK2Node_TemporaryVariable>(Net->GetOwningNode()); Term->bIsSavePersistent = TempVarNode->bIsPersistent; Context.NetMap.Add(Net, Term); }
virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override { FNodeHandlingFunctor::RegisterNets(Context, Node); // Create the net for the return value manually as it's a special case Output Direction pin UK2Node_Select* SelectNode = Cast<UK2Node_Select>(Node); UEdGraphPin* ReturnPin = SelectNode->GetReturnValuePin(); FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(ReturnPin, Context.NetNameMap->MakeValidName(ReturnPin)); Context.NetMap.Add(SelectNode->GetReturnValuePin(), Term); // Create a term to determine if the compare 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("_CmpSuccess"); BoolTermMap.Add(Node, BoolTerm); }
virtual void RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) override { UK2Node_DelegateSet* DelegateNode = Cast<UK2Node_DelegateSet>(Node); if( DelegateNode ) { CompilerContext.MessageLog.Warning(*FString(*LOCTEXT("DeprecatedDelegateSet_Warning", "DelegateSet node @@ is Deprecated. It should be replaced by an EventCaller Bind node").ToString()), DelegateNode); // Create a term to store the locally created delegate that we'll use to add to the MC delegate FBPTerminal* DelegateTerm = Context.CreateLocalTerminal(); DelegateTerm->Type.PinCategory = CompilerContext.GetSchema()->PC_Delegate; FMemberReference::FillSimpleMemberReference<UFunction>(DelegateNode->GetDelegateSignature(), DelegateTerm->Type.PinSubCategoryMemberReference); DelegateTerm->Source = Node; DelegateTerm->Name = Context.NetNameMap->MakeValidName(Node) + TEXT("_TempBindingDelegate"); LocalDelegateMap.Add(Node, DelegateTerm); // The only net we need to register for this node is the delegate's target (self) pin, since the others are expanded to their own event node RegisterDelegateNet(Context, DelegateNode); } }
void FKCHandler_DynamicCast::RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) { FNodeHandlingFunctor::RegisterNets(Context, Node); 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); } } }
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 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); }
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; } } }
void FKCHandler_CreateDelegate::RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node) { UK2Node_CreateDelegate * DelegateNode = CastChecked<UK2Node_CreateDelegate>(Node); check(NULL != DelegateNode); const FName DelegateFunctionName = DelegateNode->GetFunctionName(); if(DelegateFunctionName == NAME_None) { CompilerContext.MessageLog.Error(*LOCTEXT("NoDelegateFunctionName", "No delegate function name @@").ToString(), DelegateNode); return; } if(!DelegateNode->GetDelegateSignature()) { const FString ErrorStr = FString::Printf( *LOCTEXT("NoDelegateFunction", "No delegate function '%' @@").ToString(), *DelegateFunctionName.ToString()); CompilerContext.MessageLog.Error(*ErrorStr, DelegateNode); return; } { UEdGraphPin* InputPin = DelegateNode->GetObjectInPin(); check(NULL != InputPin); UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(InputPin); FBPTerminal** FoundTerm = Context.NetMap.Find(Net); FBPTerminal* InputObjTerm = FoundTerm ? *FoundTerm : NULL; if(NULL == InputObjTerm) { if (InputPin->LinkedTo.Num() == 0) { InputObjTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal); InputObjTerm->Name = Context.NetNameMap->MakeValidName(Net); InputObjTerm->Type.PinSubCategory = CompilerContext.GetSchema()->PN_Self; } else { InputObjTerm = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net)); } Context.NetMap.Add(Net, InputObjTerm); } } { UEdGraphPin* OutPin = DelegateNode->GetDelegateOutPin(); check(NULL != OutPin); if(!OutPin->LinkedTo.Num()) { CompilerContext.MessageLog.Error(*LOCTEXT("NoDelegateSignature", "No delegate signature @@").ToString(), DelegateNode); return; } UEdGraphPin* Net = FEdGraphUtilities::GetNetFromPin(OutPin); FBPTerminal** FoundTerm = Context.NetMap.Find(Net); FBPTerminal* OutDelegateTerm = FoundTerm ? *FoundTerm : NULL; if(NULL == OutDelegateTerm) { OutDelegateTerm = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net)); if (NULL == FMemberReference::ResolveSimpleMemberReference<UFunction>(OutDelegateTerm->Type.PinSubCategoryMemberReference)) { FMemberReference::FillSimpleMemberReference<UFunction>(DelegateNode->GetDelegateSignature(), OutDelegateTerm->Type.PinSubCategoryMemberReference); } if (NULL == FMemberReference::ResolveSimpleMemberReference<UFunction>(OutDelegateTerm->Type.PinSubCategoryMemberReference)) { CompilerContext.MessageLog.Error(*LOCTEXT("UnconnectedDelegateSig", "Event Dispatcher has no signature @@").ToString(), OutPin); return; } Context.NetMap.Add(Net, OutDelegateTerm); } } }
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; }