Preface

In blueprints, we often see some nodes with multiple output execution pins (Figure 1). We know that when a program is executed, according to the execution flow, execution branches can appear according to given conditions, which can be accomplished using the Branch node in blueprints. But when designing nodes (in C++), how should we complete the node encapsulation and have multiple output execution pins? This is the key to the problem.

Figure 1
Figure 1

First, let's get to know the nodes in Figure 1 below

  • A blueprint function node written in ordinary C++, with an output execution pin
  • Note that this is a macro, written in a blueprint, and the macro can add multiple input pins and multiple output pins when building. It can be directly produced in the blueprint
  • A function built in C++ with multiple output execution pins
  • A function built in C++ with multiple output execution pins

The descriptions of the third and fourth nodes are the same, so are they the same? Otherwise, the biggest difference between the fourth node and the third node is: ** There is an additional clock mark in the upper right corner of the node. In the blueprint, this mark indicates that the node is an asynchronous node**.

So the biggest difference between nodes three and four is whether asynchronous output occurs during execution

Writing a multi-output execution pin node in C++ (non-asynchronous)

It is relatively simple to build a multi-output execution pin node (synchronous)

  • Build enumeration items to describe output pin names
  • Write functions and mark them as exposed to blueprints
  • Add enumeration parameters as references
  • Add export enumerations to execute pin marking instructions

Build enumeration

c++
1
2
3
4
5
6
UENUM(BlueprintType)
enum class EBlueprintExecNodePin : uint8
{
    Success,
    Fail
};

Write function declaration

c++
1
2
UFUNCTION(BlueprintCallable, meta=(ExpandEnumAsExecs="Result"))
static void MultiExecNode(EBlueprintExecNodePin& Result);

Constructing function definitions

c++
1
2
3
4
5
void UMultiExecBPLibrary::MultiExecNode(EBlueprintExecNodePin& Result)
{
    //Output pin, if you want it to be Success, directly assign Result to Success, and vice versa
    Result = EBlueprintExecNodePin::Success;
}

Writing multi-output execution pin nodes in C++ (asynchronous)

The construction of asynchronous blueprint nodes is slightly more complicated than other blueprint nodes. First of all, in conventional coding, we need to solve several problems in asynchronous logic. The first is the writing of callback functions. The second is that the calling object cannot be released during asynchronous operation, otherwise the callback notification will fail. The third is to build an asynchronous thread, which is different from the current logic thread. However, in the blueprint, the Unreal Engine designer simplifies the asynchronous construction logic and hides the complexity in C++, making any asynchronous node we operate very simple. (Whether asynchronous nodes can be built in blueprints is not within the scope of discussion. From a certain perspective, it should not be recommended)

Building steps

  • Write C++ classes and inherit UBlueprintAsyncActionBase classes
  • Build dynamic multicast object types
  • Build multicast objects
  • Write blueprint function nodes
  • Execute asynchronous notification broadcasts

Write C++ classes

You can choose to inherit the BlueprintAsyncActionBase parent class when creating a class, or modify the inherited parent class in the created class

Figure 2
Figure 2

Build dynamic multicast types

**When building dynamic multicast proxy types, you can choose to have parameters or no parameters. You can design according to your actual design intent! **

c++
1
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintAsyncNodePinResult, int32, Result);

Constructing a multicast object

c++
1
2
3
4
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnSuccess;
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnFail;

Note that the macro must be marked, otherwise it will not be applied in the blueprint

Writing blueprint function nodes

c++
1
2
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UBlueprintAsyncNode* AsyncDelay(float Delay);

BlueprintInternalUseOnly tag directive hides the function from the blueprint and is only used for internal operations. Intent: The real blueprint asynchronous node is specially handled. We cannot directly expose this node to the blueprint (you can try to remove it and you will see two AsyncDelay nodes in the blueprint). The framework will redesign this function to provide it for use in the blueprint.

Now you can see the exposed nodes in the blueprint after compiling

Figure 3
Figure 3

Of course, writing asynchronous blueprint nodes is not that simple. We just explained the process separately. The next article (portal) will explain in detail how to write asynchronous blueprint nodes

Source code

Head file

c++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Fill out your copyright notice in the Description page of Project Settings.
 
#pragma once
 
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "BlueprintAsyncNode.generated.h"
 
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintAsyncNodePinResult, int32, Result);
/**
 * 
 */
UCLASS()
class UECPP_API UBlueprintAsyncNode : public UBlueprintAsyncActionBase
{
    GENERATED_BODY()
 
    UPROPERTY(BlueprintAssignable)
    FBlueprintAsyncNodePinResult OnSuccess;
    UPROPERTY(BlueprintAssignable)
    FBlueprintAsyncNodePinResult OnFail;
 
    UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
    static UBlueprintAsyncNode* AsyncDelay(float Delay);
};

Source code

c++
1
2
3
4
5
6
7
8
// Fill out your copyright notice in the Description page of Project Settings.
 
#include "BlueprintAsyncNode.h"
 
UBlueprintAsyncNode* UBlueprintAsyncNode::AsyncDelay(float Delay)
{
    return nullptr;
}

I wish you all a happy time playing Unreal

Unreal version V4.21.2