Developer Guide: Extending Dynamic Dungeon
This guide is for developers who want to extend the toolset by creating custom nodes, constraints, or integrating with the procedural pipeline via code.
1. Creating a Custom Node
All nodes in the World Generator graph must implement the IGenNode interface. For performance, it is highly recommended to use Unity's Job System and Burst Compiler.
Basic Node Structure
using DynamicDungeon.Runtime.Core;
using DynamicDungeon.Runtime.Graph;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
[NodeCategory("MyCategory")]
[NodeDisplayName("My Custom Node")]
public class MyCustomNode : IGenNode
{
private string _nodeId;
private string _nodeName;
// Define your ports here
public IReadOnlyList<NodePortDefinition> Ports => _ports;
private NodePortDefinition[] _ports;
public JobHandle Schedule(NodeExecutionContext context)
{
// 1. Get input channels
NativeArray<float> input = context.GetFloatChannel("Input");
// 2. Get/Create output channels
NativeArray<float> output = context.GetFloatChannel("Output");
// 3. Schedule a Job
MyCustomJob job = new MyCustomJob {
Input = input,
Output = output
};
return job.Schedule(output.Length, 64, context.InputDependency);
}
}
Key Attributes
[NodeCategory("Name")]: categorises the node in the searcher.[NodeDisplayName("Name")]: The name displayed on the node header.[Description("Text")]: Tooltip shown when hovering over the node.
2. Port Definitions & Data Types
The system supports five primary data types for ports:
| Type | Port Definition | C# Underlying Type |
|---|---|---|
Float | ChannelType.Float | NativeArray<float> |
Int | ChannelType.Int | NativeArray<int> |
Bool Mask | ChannelType.BoolMask | NativeArray<byte> (0 or 1) |
Point List | ChannelType.PointList | NativeList<float2> |
Placements | ChannelType.Placements | NativeList<PlacementRecord> |
3. The Execution Pipeline
The Schedule method is called once per generation attempt. You are responsible for:
- Retrieving the
NativeArrayorNativeListfrom theNodeExecutionContext. - Configuring your Job.
- Returning a
JobHandleto ensure the graph execution stays parallel and non-blocking.
Always use [BurstCompile] on your Jobs to ensure maximum performance during the generation phase.
4. Customising the Solver (Constraint Generator)
The Constraint Generator can be extended by implementing custom room selection logic or connectivity rules.
Scripting the Generation
You can trigger generation from your own scripts using the DungeonGenerationService:
DungeonGenerationService service = new DungeonGenerationService();
DungeonGenerationResult result = await service.GenerateLayoutAsync(myRequest);
if (result.Success)
{
// Do something with the layout
Debug.Log($"Dungeon generated with {result.Layout.Rooms.Count} rooms.");
}
5. Map Diagnostics API
You can run diagnostics programmatically to automate unit tests for your procedural levels.
GeneratedMapDiagnosticRules rules = new GeneratedMapDiagnosticRules();
GeneratedMapDiagnosticGrid grid = GeneratedMapDiagnostics.BuildGrid(myTargets, rules, myRegistry);
GeneratedMapDiagnosticResult result = GeneratedMapDiagnostics.RunAStar(grid, startKey, endKey, rules);
if (result.Success)
{
// Path exists!
}
Float
Int
Bool Mask
Point List
Placements