• Bob Cober

Creating Latent Functions for Blueprints in C++

Updated: Apr 22

While working on an AWS Blueprint library, I came across the need to expose some Latent Actions to blueprint.

A Latent Action is a node that can be called in a blueprint that will return at some point in the future. The best example is the Delay node.

In this example, LedgeGrabEnabled will not be set to true until 1 sec has passed.

All the network calls I was making would return at some point in the future, so it made sense to implement a latent action. Then the Blueprint user can take action with the result of the call. Latent functions are a perfect fit for async operations like network calls.

There are several parts of implementing a latent action:

.First, define the latent function in your blueprint library. e.g.

/** Send request using latent action */ UFUNCTION(BlueprintCallable, Category = "MyBPStuff", meta = (Latent, LatentInfo = "LatentInfo", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject")) virtual void GetRequest(UObject* WorldContextObject, ,struct FLatentActionInfo LatentInfo);

Next, implement the function, making sure to utilize FLatentActionManager.

// Prepare latent action

if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject)) { FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); if (LatentActionManager.FindExistingAction<FAWSDelayAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == NULL) { LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FAWSDelayAction(Duration, LatentInfo)); } }

As you can see, the primary purpose of this is to add your custom FPendingLatentAction(s) to LatentActionManager. (FAWSDelayAction is the custom latent action for my applciation).

The job of the LatentActionManager is to tick all these pending actions every frame. If the action has completed, then it should use the other information in the latent action to notify the user and call whatever ever they specified. This is typically don by calling FinishAndTriggerIf within the action's UpdateOperation.

Typically, you override your own custom action.

As an example, here is the Delay action from source:

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. #pragma once

#include "LatentActions.h"

// FDelayAction // A simple delay action; counts down and triggers it's output link when the time remaining falls to zero class FDelayAction : public FPendingLatentAction { public: float TimeRemaining; FName ExecutionFunction; int32 OutputLink; FWeakObjectPtr CallbackTarget;

FDelayAction(float Duration, const FLatentActionInfo& LatentInfo) : TimeRemaining(Duration) , ExecutionFunction(LatentInfo.ExecutionFunction) , OutputLink(LatentInfo.Linkage) , CallbackTarget(LatentInfo.CallbackTarget) { }

virtual void UpdateOperation(FLatentResponse& Response) override { TimeRemaining -= Response.ElapsedTime(); Response.FinishAndTriggerIf(TimeRemaining <= 0.0f, ExecutionFunction, OutputLink, CallbackTarget); }

#if WITH_EDITOR // Returns a human readable description of the latent operation's current state virtual FString GetDescription() const override { return FString::Printf( *NSLOCTEXT("DelayAction", "DelayActionTime", "Delay (%.3f seconds left)").ToString(), TimeRemaining); } #endif };

Using latent actions is a great way to let the blueprint user do something with the result of your async operation.

Happy Coding!


© 2016 by Casual Distraction Games, LLC