One of my blog posts went up here (Unreal Property System (Reflection) - Unreal Engine) yesterday, it goes into a lot of detail on the property system, including the class hierarchy. Have a look at that first, as I’ll be using terms from there without defining them here.
I’ve got an old presentation that talks about more of the compiler internals and how to extend it in more advanced ways than simply exposing functions or variables. I’ll try to update it and hammer it out into a blog post in the next few weeks but here is a quick and dirty summary.
Graphs
The ‘editor graph’ system is system agnostic; we use the same setup for sound cues, Blueprints, animation graphs and state machines, behavior trees, and materials. The basic unit is a UEdGraph which references a UEdGraphSchema that defines what it can contain, as well as zero or more UEdGraphNode instances. The UEdGraphSchema (never instanced, stateless) is responsible for determining what kinds of nodes can be placed in a graph, and it drives things like the context sensitive menus, palette, etc… in the various editors. We’re working over time to devolve much of the control the schema had over the graph to the individual nodes, which makes extension a lot easier and avoids a single giant file of doom, but it’s still the ‘first stop’ for the editor and compiler in a lot of cases, then turning to the nodes from there.
Compilation
Conceptually, none of the graphs or nodes are ever needed at runtime (and are in editor/developer modules as a result). They’re ‘source code’ that gets compiled down into a regular class. Compiling a blueprint creates a new UClass (specifically a UBlueprintGeneratedClass) that works just like a regular UClass generated from a reflected C++ class, containing information about the properties and functions of the blueprint (every entry point into the blueprint such as functions and events turns into an individual UFunction, as well as one additional special UFunction for the entire event graph state machine).
There are actually two classes associated with any given blueprint: the skeleton and the generated class. The skeleton class is more like a ‘header’ for the blueprint, defining the surface area, but without any details. We regenerate this any time you make a ‘structural’ modification to the blueprint graph, such as adding/removing an event, variable, or function parameter, and it lets the BP editor work with the latest information. This avoids the need to do a full compilation for every little change, making the editor workflow smoother.
Compilation phases
&d=1396039968
The compilation process goes in several phases; the two red sections only happen during the full generated class compile, the rest are common across both.
The ‘create function list’ phase is actually a bit complicated, as it also handles node expansion. Many of the nodes in a graph are composite; they’re either explicitly so (macros and collapsed graphs) or implicitly so (things like UK2Node_InputKey actually turn into several simpler nodes during expansion). Many of the different compilation steps are exposed to nodes to override, either directly via UK2Node virtuals or via subclasses of FNodeHandlingFunctor, especially on the ‘core nodes’ such as function calls and variable reads/writes.
Module responsibilities
- Blueprint nodes (subclasses of UK2Node) are mostly declared in the BlueprintGraph module (though some are declared in-situ in other modules with associated code they deal with).
- The compiler is in the KismetCompiler module.
- Various editor helpers are in UnrealEd (most of this code should eventually be moved out of there)
- Runtime classes are in Engine (UBlueprintGeneratedClass, UBlueprint (this will eventually be editor-only too, with runtime classes being almost indistinguishable to any C++ class), etc…
- Core contains a bit of blueprint-related code as well, but without actual knowledge of Blueprints (mostly related to compile-on-load; it calls delegates to the compiler where necessary, and doesn’t happen in a standalone cooked game)
You’re a bit off on Blutilities. They’re not part of making detail panels work for regular blueprints (that’s handled by the property system just like a C++ class), they’re a prototype of how editor scripting using Blueprints would work. We’ve got a feature request pending to push the ‘event button’ aspect of Blutilities out to be available for any blueprint, then they’ll pretty much just be a library of editor-specific functionality like working with assets and the selection set.
Cheers,
Michael Noland