AI DevLog 6: Creating the nodes.

For practical reasons, the definitions file will be loaded on start, and the nodes generated accordingly, stored as instances refrenced somewhere deep in the engine. (Nodes.gd)

So to start dealing with that, let's say I use the Tri-V decision node.

Here's the general layout of the code, as I recovered this from the post that disappeared after the power surge.

  • This function will recover the name of the given port (int) and will return an empty string if none is found.
func _get_port_name(data : Dictionary, port : int, input : bool = true) -> String:
    var ports : Array = []
    if input:
        ports = data.get("_input_ports")
    else:
        ports = data.get("_output_ports")
    if port < ports.size():
        print(data)
        return ports[port].get("_label_title")
    else:
        return ""


  • This one will  return the type, given the port. Both of these functions need a subdictionary passed, this is the dictionary stored under "function_name"

func _get_port_type(data : Dictionary, port : int, input : bool = true) -> int:
    var ports : Array = []
    if input:
        ports = data.get("_input_ports")
    else:
        ports = data.get("_output_ports") 
    if port < ports.size():
        return ports[port].get("_type")
    else:
        return TYPE_NIL

  • This function gets the names from the _function dictionary and gets their specifications, then creates a node with those types.


func _load_functions():
    var functions : Dictionary = Definitions.get("_functions")
    var function_names = functions.keys()
    for function in function_names:
        var data : Dictionary = functions.get(function)
        var current_node : GraphNode = GraphNode.new()
        current_node.title = function

        #The max function will return the higher count, meaning that we won't leave
        #ports out when creating them
        for ports in max(data.get("_input_ports").size(),data.get("_output_ports").size()):
            current_node.set_slot(
                ports,
                _get_port_type(data, ports, true), 
                _get_port_type(data, ports, true),
                Nodes.Color(_get_port_type(data, ports, true)),
                _get_port_type(data, ports, false),
                _get_port_type(data, ports, false),
                Nodes.Color(_get_port_type(data, ports, false)))
            current_node.add_child(DoubleLabel.new(
                _get_port_name(data, ports, true),
                _get_port_name(data, ports, false)
            ))
            #At this point we have created the node, let's store it
        match data.get("_category"):
            "inhibitors":
                Graphs.inhibitors[function]=current_node
            "actions":
                Graphs.actions[function]=current_node
            "misc":
                Graphs.misc[function]=current_node

  • To make this something easier I created the DoubleLabel node, which is not complex, you can see the code here:

extends HBoxContainer
class_name DoubleLabel

func _init(left_title : String = "", right_title : String = ""):
var Label1 = Label.new()
Label1.text = left_title
var Label2 = Label.new()
Label2.text = right_title
add_child(Label1)
add_child(Label2)


This may seem not very intuitive at first, but ends up working: