GodotNodeGenerator 0.0.8-alpha

This is a prerelease version of GodotNodeGenerator.
dotnet add package GodotNodeGenerator --version 0.0.8-alpha
                    
NuGet\Install-Package GodotNodeGenerator -Version 0.0.8-alpha
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GodotNodeGenerator" Version="0.0.8-alpha">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GodotNodeGenerator" Version="0.0.8-alpha" />
                    
Directory.Packages.props
<PackageReference Include="GodotNodeGenerator">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GodotNodeGenerator --version 0.0.8-alpha
                    
#r "nuget: GodotNodeGenerator, 0.0.8-alpha"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GodotNodeGenerator@0.0.8-alpha
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GodotNodeGenerator&version=0.0.8-alpha&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=GodotNodeGenerator&version=0.0.8-alpha&prerelease
                    
Install as a Cake Tool

Godot Node Generator

A C# source generator for Godot 4.x that creates strongly-typed accessors for nodes in your scenes.

Features

  • Automatically generates strongly-typed accessors for nodes in your Godot scenes
  • Hierarchical node navigation with nested classes (e.g., this.PanelContainer.Button)
  • Enhanced type safety with proper error handling and null checks
  • TryGet methods for safe access without exceptions
  • Script and property detection for better code generation
  • Works with Godot 4.x C# projects
  • No runtime cost - all happens at compile time
  • Makes code more readable and maintainable
  • Prevents errors from typos in node paths or wrong type casts

Installation

  1. Install the NuGet package:
dotnet add package GodotNodeGenerator
  1. Add your scene files as AdditionalFiles in your project:
<ItemGroup>
    
    <AdditionalFiles Include="**/*.tscn" />
</ItemGroup>

Manual Installation

If you prefer to add the project directly:

  1. Add this project to your solution or include the compiled DLL as a reference
  2. Add the following to your .csproj file:
<ItemGroup>
    <ProjectReference Include="..\path\to\GodotNodeGenerator\GodotNodeGenerator.csproj"
                      OutputItemType="Analyzer"
                      ReferenceOutputAssembly="false" />
</ItemGroup>


<ItemGroup>
    
    <AdditionalFiles Include="**/*.tscn" />
    
    
    
</ItemGroup>

Usage

Project Setup Example

YourProject/
  ├── .godot/
  ├── project.godot
  ├── YourProject.csproj
  ├── scenes/
  │   └── Player.tscn
  └── scripts/
      └── Player.cs

Configure AdditionalFiles

Modify your .csproj file to include your .tscn files as AdditionalFiles:

<Project Sdk="Godot.NET.Sdk/4.2.0">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <EnableDynamicLoading>true</EnableDynamicLoading>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="GodotNodeGenerator" Version="1.0.0" PrivateAssets="all" />
  </ItemGroup>
  
  
  <ItemGroup>
    <AdditionalFiles Include="**/*.tscn" />
  </ItemGroup>
</Project>

Add the NodeGenerator Attribute

In your script, add the NodeGenerator attribute and make the class partial:

using Godot;
using GodotNodeGenerator;

namespace YourProject.Scripts
{
    [NodeGenerator("res://scenes/Player.tscn")]
    public partial class Player : CharacterBody2D
    {
        public override void _Ready()
        {
            // Using the direct node accessors
            Sprite.Modulate = Colors.Red;
            
            // Using null-safe TryGet methods
            if (TryGetCamera(out var camera))
            {
                camera.Current = true;
            }
            
            // Using nested class navigation for hierarchical nodes
            UI.MainPanel.Button.Text = "Click Me!";
        }
    }
}

Example Scene Structure

For the above example, your Player.tscn might look like:

[gd_scene format=3]

[node name="Player" type="CharacterBody2D"]
script = ExtResource("player_script")

[node name="Sprite" type="Sprite2D" parent="."]
texture = ExtResource("player_texture")

[node name="Camera" type="Camera2D" parent="."]

How It Works

  1. Add your scene files as AdditionalFiles in your project file (.csproj)
  2. Apply the [NodeGenerator] attribute to your Godot node classes
  3. Specify the scene file path in the attribute constructor (or let it infer from class name)
  4. Use the generated properties to access nodes directly or via nested classes

Generated Code Example

// <auto-generated/>
using Godot;
using System;
using System.Diagnostics.CodeAnalysis;

namespace MyGame
{
    // Generated node accessors for Player
    public partial class Player
    {
        private Sprite2D? _Sprite;
        
        /// <summary>
        /// Gets the Sprite node (path: "Sprite")
        /// </summary>
        /// <exception cref="InvalidCastException">Thrown when the node is not of type Sprite2D.</exception>
        /// <exception cref="NullReferenceException">Thrown when the node is not found.</exception>
        [return: NotNull]
        public Sprite2D Sprite 
        {
            get
            {
                if (_Sprite == null)
                {
                    var node = GetNodeOrNull("Sprite");
                    if (node == null)
                    {
                        throw new NullReferenceException("Node not found: Sprite");
                    }
                    
                    _Sprite = node as Sprite2D;
                    if (_Sprite == null)
                    {
                        throw new InvalidCastException($"Node is of type {node.GetType()}, not Sprite2D");
                    }
                }
                
                return _Sprite;
            }
        }
        
        /// <summary>
        /// Tries to get the Sprite node without throwing exceptions.
        /// </summary>
        /// <returns>True if the node was found and is of the correct type.</returns>
        public bool TryGetSprite([NotNullWhen(true)] out Sprite2D? node)
        {
            node = null;
            if (_Sprite != null)
            {
                node = _Sprite;
                return true;
            }
            
            var tempNode = GetNodeOrNull("Sprite");
            if (tempNode is Sprite2D typedNode)
            {
                _Sprite = typedNode;
                node = typedNode;
                return true;
            }
            
            return false;
        }

        // Additional properties and TryGet methods for other nodes...
    }
}

Type Safety Features

Safe Node Access

Each node property includes proper null checking and type validation:

public Camera2D Camera
{
    get
    {
        if (_Camera == null)
        {
            var node = GetNodeOrNull("Camera");
            if (node == null)
            {
                throw new NullReferenceException("Node not found: Camera");
            }
            
            _Camera = node as Camera2D;
            if (_Camera == null)
            {
                throw new InvalidCastException($"Node is of type {node.GetType()}, not Camera2D");
            }
        }
        
        return _Camera;
    }
}

Exception-free Access with TryGet Methods

For situations where you want to avoid exceptions, use the generated TryGet methods:

if (TryGetCamera(out var camera))
{
    // Camera exists and is of the correct type
    camera.Current = true;
}
else
{
    // Handle the case where the camera doesn't exist or is the wrong type
    GD.Print("Camera not available");
}

Script Detection

The generator detects scripts attached to nodes and includes this information in the property documentation:

/// <summary>
/// Gets the Player node (path: "Root/Player") (script: "res://scripts/Player.cs")
/// </summary>

This makes it easier to understand the relationship between scene nodes and script files.


Nested Class Navigation

One of the most powerful features is the nested class navigation for hierarchical node structures. Instead of accessing nodes with long paths like GetNode<Button>("UI/PanelContainer/VBoxContainer/Button"), you can use a more intuitive object-oriented approach:

// Access nested nodes through property chains
UI.PanelContainer.VBoxContainer.Button.Text = "Click Me!";

// Access the underlying node directly if needed
var panel = UI.PanelContainer.Node;

This approach gives you several benefits:

  • Better type safety at compile time
  • Code completion for available child nodes
  • More readable and maintainable code
  • Natural object-oriented navigation
  • Access to both the wrapper and the underlying node

Example Scene Structure

[node name="UI" type="Control"]

[node name="PanelContainer" type="PanelContainer" parent="UI"]

[node name="VBoxContainer" type="VBoxContainer" parent="UI/PanelContainer"]

[node name="Button" type="Button" parent="UI/PanelContainer/VBoxContainer"]

[node name="Label" type="Label" parent="UI/PanelContainer/VBoxContainer"]

Generated Wrapper Classes

For the above scene, the generator creates wrapper classes for nodes with children:

public class UIWrapper
{
    // Access to the underlying node
    public Control Node => _node;
    
    // Access to the child wrapper
    public PanelContainerWrapper PanelContainer { get; }
}

public class PanelContainerWrapper
{
    // Access to the underlying node
    public PanelContainer Node => _node;
    
    // Access to the child wrapper
    public VBoxContainerWrapper VBoxContainer { get; }
}

public class VBoxContainerWrapper
{
    // Access to the underlying node
    public VBoxContainer Node => _node;
    
    // Direct access to leaf nodes
    public Button Button => _owner.Button;
    public Label Label => _owner.Label;
}

These wrapper classes are accessed via properties in your main class:

// In your MonoBehaviour class:
public override void _Ready()
{
    // Access via nested wrappers
    UI.PanelContainer.VBoxContainer.Button.Pressed += OnButtonPressed;
    
    // You can still access nodes directly (flat accessors)
    Button.Disabled = true;
    
    // Access the underlying Godot node when needed
    var vbox = UI.PanelContainer.VBoxContainer.Node;
    vbox.AddThemeConstantOverride("separation", 10);
}

Scene File Resolution

The generator looks for scene files that have been included as AdditionalFiles in your project. The AdditionalFiles mechanism is a standard Roslyn feature that allows source generators to access files without direct file I/O, which is important for incremental compilation and better IDE integration.

By default, it will look for a scene file with the same name as the class. For example, if your class is named Player, it will look for Player.tscn among your AdditionalFiles.

The source generator follows this process to find the scene file:

  1. Try to find a file that exactly matches the path specified in the attribute
  2. If not found, try to find a file with the same filename
  3. If the path doesn't have a .tscn extension, try adding it
  4. If still not found, use a dummy scene for testing purposes or report a diagnostic

You can override this by specifying the path in the attribute:

[NodeGenerator("res://scenes/custom_player.tscn")]
public partial class Player : CharacterBody2D
{
}

Testing

The project includes a comprehensive test suite targeting various components:

  • SceneParserTests: Tests the TSCN file parser with various scene structures
  • NodeGeneratorTests: Tests the source generator's code generation capabilities
  • SourceGenerationHelperTests: Tests the helper methods for code generation
  • OutputVerificationTests: Verifies that the generated code matches expected output
  • NestedClassAccessorTests: Tests the nested class accessors functionality
  • NestedClassUsageTests: Tests real-world usage patterns of nested class navigation

To run tests, use the following command:

dotnet test

License

MIT License

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.8-alpha 117 6/30/2025
0.0.7-alpha 112 6/30/2025
0.0.5-alpha 107 6/20/2025
0.0.4-alpha 106 6/20/2025
0.0.3-alpha 115 6/19/2025
0.0.2-alpha 115 6/19/2025
0.0.1-alpha 200 6/19/2025