GodotNodeGenerator 0.0.8-alpha
dotnet add package GodotNodeGenerator --version 0.0.8-alpha
NuGet\Install-Package GodotNodeGenerator -Version 0.0.8-alpha
<PackageReference Include="GodotNodeGenerator" Version="0.0.8-alpha"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="GodotNodeGenerator" Version="0.0.8-alpha" />
<PackageReference Include="GodotNodeGenerator"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add GodotNodeGenerator --version 0.0.8-alpha
#r "nuget: GodotNodeGenerator, 0.0.8-alpha"
#:package GodotNodeGenerator@0.0.8-alpha
#addin nuget:?package=GodotNodeGenerator&version=0.0.8-alpha&prerelease
#tool nuget:?package=GodotNodeGenerator&version=0.0.8-alpha&prerelease
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
Via NuGet (Recommended)
- Install the NuGet package:
dotnet add package GodotNodeGenerator
- Add your scene files as AdditionalFiles in your project:
<ItemGroup>
<AdditionalFiles Include="**/*.tscn" />
</ItemGroup>
Manual Installation
If you prefer to add the project directly:
- Add this project to your solution or include the compiled DLL as a reference
- 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
- Add your scene files as
AdditionalFiles
in your project file (.csproj) - Apply the
[NodeGenerator]
attribute to your Godot node classes - Specify the scene file path in the attribute constructor (or let it infer from class name)
- 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:
- Try to find a file that exactly matches the path specified in the attribute
- If not found, try to find a file with the same filename
- If the path doesn't have a .tscn extension, try adding it
- 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 | Versions 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. |
-
.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 |