Wednesday Wisdom: Custom FlowGraph node in C++
Wednesday Wisdom: Custom FlowGraph node in C++

Wednesday Wisdom: Custom FlowGraph node in C++

Introducing our new section dedicated to featuring community created tutorials, tips and tricks, and code! This week "ochounos" shows you how to create a custom FlowGraph node in C++!

Managing complex FlowGraph logic can sometimes be much easier if it is handled natively in C++ directly. This tutorial will give you an introduction on how to create a custom flowgraph node to simplify your workflow.

Let’s create a simple FlowGraph node and look at its core functionality. The node should be able to sum three integers and only perform the calculation when a specific operation triggers.


class CFlowSumNode : public CFlowBaseNode<eNCT_Instanced>

{

  public:

  enum EInputs

  {

IN_TRIGGER = 0,

IN_INTEGER_1,

IN_INTEGER_2,

IN_INTEGER_3

  };


  enum EOutputs

  {

      OUT_SUM

  };


  void CFlowSumNode::GetConfiguration(SFlowNodeConfig& config)
  {

static const SInputPortConfig in_config[] = {

    InputPortConfig<SFlowSystemVoid>( "Trigger", _HELP("Activate the node") ),

    InputPortConfig<int>( "A", _HELP("Operator A") ),

    InputPortConfig<int>( "B", _HELP("Operator B") ),

    InputPortConfig<int>( "C", _HELP("Operator C") )

            };

 

            static const SOutputPortConfig out_config[] = {

    OutputPortConfig<int>( "Sum", _HELP("Sum three integers when activated") )

            };

 

            config.sDescription = "Sum three integers when activated";

            config.pInputPorts  = in_config;

            config.pOutputPorts = out_config;

            config.SetCategory(EFLN_APPROVED); 

            …
      }


}

REGISTER_FLOW_NODE( "MyCategory:Sum", CFlowSumNode );


The first thing we notice is that our node inherits from CFlowBaseNode<>. The base for any FlowNode.

It defines the basic behavior of our node. It can be constructed with the flowing settings:


  • eNCT_Singleton:  A single instance of the node will be created and referenced by the FlowGraph every time it is used.
  • eNCT_Instanced: A new instance will be created every time this node is added to the FlowGraph.
  • eNCT_Cloned: A new instance, cloned from the existing instance, will be created every time this node is added to the FlowGraph. (deprecated)

In this example we use eNCT_Instanced as we do not intent to share the internal node data.


The InputPortConfig<> allows the user to feed data into the flow node.

By default it can be any of the types:


·  SflowSystemVoid

·  int

·  float

·  bool

·  string

·  Vec3

·  EntityId

 

In our example this controls when to sum up the three integers as well as the value of each individual integer. The first InputPortConfig<> is of type SFlowSystemVoid. Since it is only used for triggering the calculation it does not require a special data type. SFlowSystemVoid will accept any data type.


The other three InputPortConfig<> target the three integers.


Outputs are pretty much defined the same as inputs except the create OutputPortConfig<> instances.


In the last step of defining our flow node, we need to bind the SinputPortConfig in_config[] and SoutputPortConfig out_config[]  information to the SFlowNodeConfig& config, passed into the function by reference.


Ignore the following line for now.
config.SetCategory(EFLN_APPROVED);


We are only missing the code to run the sum of the inputs and put the result in the output.

Every time an input port is modified, our node will receive an event. We need to handle that event.


void CFlowSumNode::ProcessEvent(EFlowEventevent, SActivationInfo* pActInfo)

{

    // Every time that one input is modified the node receives an event

    if (event == eFE_Activate)

    { 

        // Check if Trigger port has been activated

        if (IsPortActive(pActInfo, IN_TRIGGER))

        {

            // Get the value of all operators   

            const int (pActInfo, IN_INTEGER_1);

            const int (pActInfo, IN_INTEGER_2);

            const int (pActInfo, IN_INTEGER_3);


            // Output the sum of the three operators

            ActivateOutput(pActInfo, OUT_SUM, a + b + c);

            }

      }

}


In this simplified example we check the event type first. As we only want to act when our “Trigger” input port is activated. We also need to specifically check if the “Trigger” input port is active specifically, as we do not want to act when any of the “Integer” input ports received and activation event.

It is advised to create a set of enums i.e. EInputs/EOutputs next to your input/output ports which map the order in which the ports slots are layout out in your in_config/out_config array. The first entry being assigned slot 0 counting upwards.

Finally you need to register your flow node, defining category and name:

REGISTER_FLOW_NODE( "MyCategory:Sum", CFlowSumNode );


Check the whole source code provided in the attached file. Play around with it to understand FlowGraph nodes even further.


For CRYENGINE V:

Create your file at \Code\Game\GameDll\flownodes


For CRYENGINE 3.8.6 and earlier:

Create your file at \Code\GameSDK\GameDll\Nodes


In both cases, you must add your file to your solution to be included in your generated dll.

Download the code sample here.

- ochounos