Navigation
API > API/Plugins > API/Plugins/ControlFlows
System/Tool to queue (asynchronous or synchronous) functions for modularity implemented via delegates. Allows code to be more easily read so there fewer 'Alt+G'-ing around to figure out what and where a class does it's thing
This system only supports non-const functions currently.
'QueueFunction': Queues a 'void (...)' function. The Flow will execute this function and continue on with the next function in queue.
'QueueWait': Queues a 'void (FControlFlowNodeRef FlowHandle, ...)' function. The flow will stop until 'FlowHandle->ContinueFlow()' is called. BE RESPONSIBLE and make sure all code paths call to continue xOR cancel, otherwise the flow will hang.
'QueueControlFlow': Queues a 'void (TSharedRef
'QueueControlFlowBranch': Queues a 'int32(TSharedRef
'QueueConcurrentFlows': Queues a 'void(TSharedRef
'QueueConditionalLoop': Queues a 'EConditionalLoopResult(TSharedRef
'QueueStep': Usable in #UObject's or classes that derive from #TSharedFromThis
Using the auto-deduction of 'QueueStep', you can change the queue from a synchronous function (QueueFunction) to an asynchronous one (QueueWait) or vice-versa by adding/removing the 'FControlFlowNodeRef FlowHandle' as your first parameter. And you can change it to (QueueControlFlow) if need be as well!
Syntax:
void MyFunction(...); void MyFunction(FControlFlowNodeRef FlowHandle, ...); void MyFunction(TSharedRef
ControlFlowInstance->QueueStep(this, &UserClass:MyFunction1, ...) .QueueStep(this, &UserClass:MyFunction2, ...) .QueueStep(this, &UserClass:MyFunction3, ...);
This allow ease of going from Synchronous Functionality to Asynchronously Functionality to Subflows as you build out your Flow.
Full Example Class
struct FMyFlowClass : public TSharedFromThis
void RunMyPurpose()
{
MyPurpose
.QueueStep(this, &ThisClass::Construct)
.Loop(this
{
Outerloop->RunLoopFirst()
.SetCancelledNodeAsComplete(true)
.QueueStep(this, &ThisClass::Foo)
.QueueStep(this, &ThisClass::Foo)
.Loop(this
{
InnerLoop->CheckConditionFirst()
.BranchFlow([this], TSharedRef
Branch->AddOrGetBranch(1)
.QueueStep(this, &ThisClass::Foo)
.ForkFlow([this], TSharedRef
ConcurrentFlows->AddOrGetFlow(1) .QueueStep(this, &ThisClass::Foo); });
return FMath::RandBool() ? EConditionalLoopResult::RunLoop : EConditionalLoopResult::LoopFinished; }) .QueueStep(this, &ThisClass::Foo);
return FMath::RandBool() ? EConditionalLoopResult::RunLoop : EConditionalLoopResult::LoopFinished; }) .QueueStep(this, &ThisClass::Foo);
return EConditionalLoopResult::RunLoop; // OuterLoop will never end in this example }) .QueueStep(this, &ThisClass::Destruct) .ExecuteFlow(); }
private: void Foo(); void Construct(); // Equivalent to Init void Destruct(); // Equivalent to Uninit
TSharedRef
The implementation details of a flow can be fully disjointed from the Flow logic itself!
| Name | FControlFlow |
| Type | class |
| Header File | /Engine/Plugins/Experimental/ControlFlows/Source/ControlFlows/Public/ControlFlow.h |
| Include Path | #include "ControlFlow.h" |
Syntax
class FControlFlow : public TSharedFromThis< FControlFlow >
Inheritance Hierarchy
- TSharedFromThis< FControlFlow > → FControlFlow
Constructors
| Name | Remarks | Include Path | Unreal Specifiers |
|---|---|---|---|
FControlFlow
(
const FString& FlowDebugName |
ControlFlow.h |
Constants
| Name | Type | Remarks | Include Path |
|---|---|---|---|
| UnnamedControlFlowCounter | int32 | ControlFlow.h |
Variables
Protected
| Name | Type | Remarks | Include Path | Unreal Specifiers |
|---|---|---|---|---|
| Activity | TSharedPtr< FTrackedActivity > | ControlFlow.h | ||
| bBroadcastingStepComplete | bool | ControlFlow.h | ||
| bInterpretCancelledNodeAsComplete | bool | ControlFlow.h | ||
| bProfilerEventStarted | bool | ControlFlow.h | ||
| CurrentlyRunningTask | TSharedPtr< FControlFlowNode_Task > | ControlFlow.h | ||
| CurrentNode | TSharedPtr< FControlFlowNode > | ControlFlow.h | ||
| DebugName | FString | ControlFlow.h | ||
| FlowQueue | TArray< TSharedRef< FControlFlowNode > > | ControlFlow.h | ||
| LastZeroSecondDelay | TPair< double, float > | ControlFlow.h | ||
| OnCancelledDelegate_Internal | FSimpleDelegate | ControlFlow.h | ||
| OnCompleteDelegate_Internal | FSimpleDelegate | ControlFlow.h | ||
| OnExecutedWithoutAnyNodesDelegate_Internal | FSimpleDelegate | ControlFlow.h | ||
| OnFlowCancelledDelegate | FSimpleMulticastDelegate | ControlFlow.h | ||
| OnFlowCompleteDelegate | FSimpleMulticastDelegate | ControlFlow.h | ||
| OnNodeWasNotBoundedOnExecution_Internal | FSimpleDelegate | ControlFlow.h | ||
| OnStepCompletedDelegate | FSimpleMulticastDelegate | ControlFlow.h | ||
| ParentFlow | TWeakPtr< FControlFlow > | ControlFlow.h | ||
| SubFlowStack_ForDebugging | TArray< TSharedRef< FControlFlow > > | TODO: Put behind some args, because this is expensive. | ControlFlow.h | |
| UnnamedBranchCounter | int32 | ControlFlow.h | ||
| UnnamedNodeCounter | int32 | ControlFlow.h |
Functions
Public
| Name | Remarks | Include Path | Unreal Specifiers |
|---|---|---|---|
FControlFlow & BranchFlow
(
FunctionT InBranchLambda, |
ControlFlow.h | ||
void CancelFlow () |
Will cancel ALL flows, both child ControlFlows and ControlFlows who owns this Flow. | ControlFlow.h | |
void ExecuteFlow () |
This needs to be called, otherwise nothing will happen!! Call after you finish adding functions to the queue. | ControlFlow.h | |
FControlFlow & ForkFlow
(
FunctionT InForkLambda, |
ControlFlow.h | ||
TOptional< FString > GetCurrentStepDebugName() |
ControlFlow.h | ||
const FString & GetDebugName() |
ControlFlow.h | ||
TSharedPtr< FTrackedActivity > GetTrackedActivity() |
ControlFlow.h | ||
bool IsRunning() |
ControlFlow.h | ||
FControlFlow & Loop
(
FunctionT InLoopLambda, |
ControlFlow.h | ||
size_t NumInQueue() |
ControlFlow.h | ||
FSimpleMulticastDelegate & OnFlowCancel() |
ControlFlow.h | ||
FSimpleMulticastDelegate & OnFlowComplete() |
ControlFlow.h | ||
FSimpleMulticastDelegate & OnNodeComplete() |
ControlFlow.h | ||
TSharedRef< FControlFlowTask_BranchLegacy > QueueBranch
(
FControlFlowBranchDecider_Legacy& BranchDecider, |
Both of these implementations are deprecated. | ControlFlow.h | |
FConcurrentFlowsDefiner & QueueConcurrentFlows
(
const FString& TaskName, |
ControlFlow.h | ||
FControlFlowConditionalLoopDefiner & QueueConditionalLoop
(
const FString& TaskName, |
ControlFlow.h | ||
FControlFlowPopulator & QueueControlFlow
(
const FString& TaskName, |
ControlFlow.h | ||
FControlFlowBranchDefiner & QueueControlFlowBranch
(
const FString& TaskName, |
ControlFlow.h | ||
FControlFlow & QueueDelay
(
const float InSeconds, |
ControlFlow.h | ||
FSimpleDelegate & QueueFunction
(
const FString& FlowNodeDebugName |
ControlFlow.h | ||
FControlFlowPopulator & QueueLoop
(
FControlFlowLoopComplete& LoopCompleteDelgate, |
ControlFlow.h | ||
FControlFlow & QueueSetCancelledNodeAsComplete
(
const bool bCancelledNodeIsComplete, |
ControlFlow.h | ||
FControlFlow & QueueStep
(
const char* NodeName, |
ControlFlow.h | ||
FControlFlow & QueueStep
(
const TCHAR* NodeName, |
ControlFlow.h | ||
FControlFlow & QueueStep
(
const FString& NodeName, |
ControlFlow.h | ||
FControlFlow & QueueStep
(
ArgsT... Params |
ControlFlow.h | ||
FControlFlowWaitDelegate & QueueWait
(
const FString& FlowNodeDebugName |
ControlFlow.h | ||
void Reset() |
ControlFlow.h | ||
FControlFlow & SetCancelledNodeAsComplete
(
bool bCancelledNodeIsComplete |
ControlFlow.h | ||
FControlFlow & SplitFlow
(
ArgsT... Args |
ControlFlow.h | ||
FControlFlow & SwitchFlow
(
ArgsT... Args |
ControlFlow.h | ||
FControlFlow & TrackActivities
(
TSharedPtr< FTrackedActivity > InActivity |
ControlFlow.h |