We've been discussing Orchestrator internally for several weeks now and after our successful release of Orchestrator v1, we wanted to give an update on what we believe lies ahead and how we intend to reach that goal. As a commitment to the Godot user community, we also intend to do monthly DevTalk announcements, discussing and illustrating not only the overall progress on Orchestrator throughout development but also sharing insight into our vision.
In this post, we're going to discuss the road to the next major release of Orchestrator, what that means in terms of the breadth of features, and when you can likely expect this release to be generally available. But before we get started, keep in mind that the information we share is entirely subject to change based on technical needs and any feedback we gain from the community regarding this post.
What prompted a major version jump?
This is certainly a valid question to raise and the answer is quite simple. Throughout our discussion both internally and based on the community feedback we received about Orchestrator v1, we began to evaluate how we could achieve some of the goals and requested features. Our initial release of Orchestrator was based entirely on GDScript, and this allowed us to quickly prototype concepts and changes; however, we began to see several limitations with this decision as we evaluated features such as signals or even the ability to attach an Orchestration to a scene node.
We want the user experience with Orchestrator to be seamless with Godot. The need to create a GDScript wrapper or to drop a specialized node in your scene to run an Orchestration, while functional, felt like too much glue was required to truly be as seamless of a feature much like GDScript or CSharp. This prompted us to begin looking at alternatives, to evaluate whether CSharp made more sense or if we should consider GDNative or GDExtension. If you're unfamiliar with those, that's okay. In essence, CSharp allows you to attach a script to a scene node much in the same way you attach a GDScript file. Both GDNative and GDExtension are quite a bit different where the former is compiled into the final engine's binary and the latter acts more like a native plug-in to the engine, where it can be compiled separately and installed in much the same way as any standard Godot plug-in.
After consideration, we eventually decided that GDExtension was the best alternative and path forward. It enables us to write code that very closely integrates with the Godot engine without the abstraction layers that GDScript is based on, those same layers that make it extremely useful for rapid prototyping and simplicity. This means that the entire source for Orchestrator must be rewritten from the ground up within C++ rather than GDScript, and with such a large overhaul, it made sense to consider this a major release.
Scene Node Integration
For Orchestrator v2, there is no need for any wrapper or OrchestratorPlayer node. Orchestrations are now referred to as simply OrchestratorScript files with an .os extension. You edit an OrchestratorScript much in the same way as you did with Orchestrations in v1; however, these can now be directly attached to any scene node in your scene tree. These scripts act identically to GDScript files, they can react to node-level events such as _ready, _process, and others. You can also define and emit signals while other scene components can connect and listen to those signals just like GDScript.
In addition, OrchestratorScript files can also define and optionally export variables to the owning scene node, much in the same way that GDScript provides. This allows you to write reusable visual-like scripts, attach those to any node, and then tailor the script's behavior based on those exported variables. Finally, OrchestratorScript files also can declare functions, making those functions callable by any other scene component with a reference to the owning node, again just like GDScript.
By allowing OrchestratorScripts to natively interface with Godot scene nodes much in the same way as both GDScript and CSharp, we believe this is pivotal to improving the overall seamless integration and usage of Orchestrator in any Godot project, no matter how big or small.
OrchestratorScript Node Changes
Overall, we wanted to maintain the feel and use of Orchestrator v1 with nodes; however, we wanted to take a step back and reimagine what a node fundamentally represents and how data flows into and out of a node.
In Orchestrator v1, a script node was primarily a black box. In essence, control flow triggered the node's behavior, it performed some actions and eventually passed control flow onto the next node in the chain. This meant that those nodes only accepted control-flow connections. This works well for simple designs, but we realize that games are very often complex and require complex but simple means to write gameplay and logic.
We took a step back and evaluated other similar frameworks such as Unreal Engine's Blueprint system and we began to consider what would nodes look like if we shifted the ideology that nodes were less of a black box but rather building blocks that can be combined to build larger, more complex elements in the same way that a developer might create a series of classes for specific behaviors and the integration of those classes create more complex systems. So let's take a sneak peek at a new node that will ship with Orchestrator v2 and how this differs from v1.
The following illustrates a new node type ForEach, which provides the designer with the ability to take an array or collection and iterate over the elements to perform some action on each element. The designer will be able to link any number of nodes to the "Loop Body" port and perform per-element work. The node also emits the element and its index as the iteration step occurs. Finally, when the iteration is complete, the control flow exits the "Completed" connection, allowing the program flow to continue forward.
One major difference from Orchestrator v1 is there is a clear distinction between control and data. Control or Program flow is managed by the white arrow ports on the left and right sides of the node. These control ports on the left are considered inputs while those on the right are considered outputs. Data flow is provided via the circular ports on both the left and right sides of the node and also act as input and output ports for data, allowing the node to accept and pass data onto any node thereafter.
You might also be wondering, what if I want to break out of that loop early, Orchestrator v2 has you covered. Many nodes directly interact with the Godot Editor's Inspector dock, shown below:
When selecting the ForEach node in the graph editor, the Inspector will show any eligible properties that can be simply toggled. By toggling the "with break" option on the ForEach node, a new input control port will appear on the left side of the node.
This allows you to easily control when the ForEach node breaks the loop performing any evaluation during the "Loop Body" and connecting back to the "break" port.
We have also reworked the node creation workflow. Rather than dragging a node from the node list view onto the graph editor as you did with Orchestrator v1, you can now use the right mouse button anywhere in the graph editor or by dragging from an input or output port to open an actions dialog to select any number of nodes.
In the example above, simply by typing "Vis", the dialog automatically updates the search results with all possible options that match the criteria. Additionally, when dragging from a port that either accepts a specific data type, such as bool or emits a value of a given data type, the dialog window will be restricted to those functions, signals, or properties that accept or return that data type. By unclicking the "context-sensitive" option in the top right, the dialog will show all options. We hope this eases and improves the efficiency of creating orchestrations.
Editor Changes
We've also decided to innovate how we directly integrate with the editor workspace. If you recall with Orchestrator v1, the graph mostly acted like a single function call with Start and End terminal nodes with your logic in between. In Orchestrator v2, those terminal node concepts are gone, and how graphs are constructed has been redesigned from the ground up.
One of the concepts we most liked about Unreal's Blueprint system was the ability to logically group nodes together by their purpose, whether you were creating a callback to handle a specific event flow or whether you were writing a function call. Their blueprint system allows you to group those nodes into units and the editor presents those units to you in a clean way using a tab-structure.
Orchestrator v2 builds on this concept with a tab bar across the top of the graph workspace. You can logically group calls to event callbacks like _ready, _process, _physics_process, and so on in one more many event graphs. The idea is that anything that is an inherited Godot callback function/event will be organized separately from your own custom functions for cleanliness and organization. You can choose to place each Godot callback function/event within its own graph or maintain these in a single graph as you desire.
User-defined functions are managed differently. These will always be rendered in a separate view from the event-based callbacks/functions. A single function is meant to be a piece of code that can stand on its own, you can freely call into that function using a FunctionCall node within your event graph or from any other function.
Additionally, there is a new component widget on the right side of the graph workspace. This component widget provides direct access to each event graph, the events defined within the graph, and the functions defined within the OrchestratorScript.
By selecting a specific function in the function's category, it will be loaded into a new tab if it isn't already and will become the current active tab in the editor's main view. Additionally, this is also the place where variables and custom signals are managed; however, we are evaluating whether this may simply be for informational purposes and those items act like hyperlinks, jumping the view to that specific node in its corresponding graph window where you can manage details about that element within the editor's Inspector dock.
Upgrading
OrchestratorScripts are not necessarily directly the same as Orchestrations from Orchestrator v1. As such, we certainly have thought about how might an existing user upgrade and what we believe that process might look like. We first thought about whether we could do that on the fly at project load, but given how the integration between Orchestrations and scenes worked in v1, we don't believe that's really viable.
With Orchestrator v2, there will be a converter scene that is shipped with the plug-in that will convert an Orchestration text-based resource file to the new OrchestratorScript binary file format. We don't have many details to share on this at this junction, but we do intend to make the upgrade process as painless as possible.
Wrapping up
So as you can see, Orchestrator v2 is shaping up to be a massive improvement over its predecessor. We are hoping to have a first alpha preview build in the coming weeks to start gaining some immediate feedback from the community. Until then, we have a number of "todos" we want to check off before doing so to guarantee that the user experience is clear and clean so that the feedback we get is very actionable.