The simplest form of plugin is just a plain C# class. Use a static class if you just wish to expose simple functions:
public static class MyPlugin
{
public static int GetValue() => 15;
}
The host exposes a set of capabilities through the PluginFeature
flags. Before attempting to use a particular subsystem, a plugin should call GetFeatureSet()
and check for the relevant flag. The available features are:
A plugin should combine these flags with bitwise operations (e.g., if ((features & PluginFeature.Menus) != 0) { … }
) to determine what to register or enable at runtime.
Once the plugin has verified that PluginFeature.Menus
is available, it can add items to Divooka’s main menu bar and register nested submenus. Each menu entry invokes a callback when clicked.
// Add or remove a top‑level menu item:
void RegisterMenu(
string menu, // unique identifier (e.g. "MyPlugin/Tools")
string title, // user‑facing text
string? tooltip, // optional hover text
Action<IDivookaEngineHostEnvironment> clickCallback,
bool autoUnregister // if true, host will remove it on plugin unload
);
void UnregisterMenu(string menu, string title);
// Add or remove a submenu under an existing menu:
void RegisterSubmenu(
string menu, // same “menu” key as above
string submenu, // unique identifier for the submenu entry
string title,
string? tooltip,
Action<IDivookaEngineHostEnvironment> clickCallback,
bool autoUnregister
);
void UnregisterSubMenu(string menu, string submenu, string title);
menu
and submenu
are identifiers (not necessarily the displayed text).title
is what the end user sees.autoUnregister
allows the host to clean up when the plugin is unloaded.If ConnectorVisualCustomizations
is supported, a plugin can customize how pins (input/output ports) and connector lines look for any given data type.
void RegisterTypeConnectionAppearance(
Type type, // the .NET type to style (e.g., typeof(MyCustomData))
BuiltinConnectorShape shape, // one of: HollowCircle, SolidSquare, etc.
Color color // base color for the connector (e.g., System.Drawing.Color.Red)
);
BuiltinConnectorShape
Divooka allows nodes to provide a small preview of their data (e.g., showing an image, a text snippet, or a graph). Two different extension points exist:
Preview Processor (requires the PreviewProcessor
flag)
void RegisterPreviewProcessor(
Type type, // the data type your plugin wants to handle
Func<object, object> processor // a function that converts “type” into a built‑in previewable type (e.g., Bitmap, string, List<float>, etc.)
);
MyImageData
instance into a System.Drawing.Bitmap
.Custom Preview Handler (requires the CustomPreviewHandler
flag)
void RegisterCustomPreviewHandler(
Type instanceType, // the .NET type for which you supply full control
Action<ProcessorNode, object> previewHandler
);
previewHandler
whenever the user requests a preview; it passes you the node instance plus the raw data object. Your code is responsible for showing a window or control, rendering content, wiring up close events, etc. Note: this only works as a separate popup, not inline on the canvas.If DynamicPackages
is enabled, the plugin can tell Divooka about new node types—both in terms of back‑end functionality (what the node does) and front‑end toolbox entries (where it appears in the UI). The RegisterPackages
call unifies several collections of definitions:
void RegisterPackages(
IEnumerable<ToolboxIndexer.AssemblyToolboxDefinition>? assemblyToolboxes,
IEnumerable<ToolboxIndexer.FrontendToolboxDefinition>? frontendToolboxes,
IEnumerable<ToolboxIndexer.TypeToolboxDefinition>? typedToolboxes,
IEnumerable<ToolboxIndexer.SpecificToolboxEndPointDefinition>? specificEndpoints,
IEnumerable<ToolboxIndexer.ProceduralContextBaseTypeDefinition>? proceduralContextTypes,
bool autoUnregister = true
);
AssemblyToolboxDefinition
FrontendToolboxDefinition
TypeToolboxDefinition
SpecificToolboxEndPointDefinition
ProceduralContextBaseTypeDefinition
Once registered, Divooka’s UI will show these new node types in the toolbox; users can drag and drop them onto the canvas just like built‑in nodes.
For plugins that introduce a custom procedural execution context, use:
void RegisterProceduralContextExecutionRunner(
Type baseType, // the abstract base for all of your procedural contexts
Type instantiatorType // a factory/runner class that knows how to execute that context
);
baseType
needs execution, use this instantiatorType
to run it.”GetFeatureSet()
.RegisterMenu
/RegisterSubmenu
if menus are supported.RegisterTypeConnectionAppearance
to give them distinct pin shapes/colors.RegisterPackages
.RegisterPreviewProcessor
.RegisterCustomPreviewHandler
.autoUnregister = true
, most registrations (menus, packages, preview handlers) will be cleaned up automatically when Divooka unloads the plugin. Otherwise, explicitly call UnregisterMenu
, UnregisterSubMenu
, and any custom cleanup needed.Feature Detection
var features = host.GetFeatureSet();
if ((features & PluginFeature.Menus) != 0)
RegisterMenus();
if ((features & PluginFeature.DynamicPackages) != 0)
RegisterPackages(...);
// etc.
Menus
RegisterMenu
/RegisterSubmenu
to add single-click actions."MyPlugin/Tools/DoSomething"
).Node Appearance
RegisterTypeConnectionAppearance(typeof(MyType), BuiltinConnectorShape.SolidCircle, Color.Blue)
to give nodes for MyType
a blue circular pin.Preview Support
Func<object, object>
to convert it into an existing previewable object (string, Bitmap, array, etc.).Dynamic Types (Toolbox)
RegisterPackages
.AssemblyToolboxDefinition
. If you want tight control over individual node metadata, use TypeToolboxDefinition
.Execution
ProceduralContextExecutionRunner
mapping your graph’s base type to a runner/factory.Once the above pieces are in place, Divooka will automatically show your menus, render your node pins, let users drag your custom node types into graphs, and—when a user clicks “Run” or requests a preview—invoke your converters or custom preview code under the hood.
By grouping functionality under these six areas (feature flags, menus, node appearance, previews, dynamic type registration, and execution runners), you ensure that your plugin integrates smoothly with Divooka’s host environment and follows the intended extension points.
Additional C# tricks.