C# Source Generators for use with the Godot Game Engine (supports Godot 4 and .NET 8!)
SceneTree
class attribute:
_
operator)GodotOverride
method attribute:
Notify
property attribute:
InputMap
class attribute:
LayerNames
class attribute:
CodeComments
class attribute:
OnInstantiate
method attribute:
OnImport
method attribute (GD4 only):
Includes base classes/helpers to create project specific source generators
Version 2.x supports Godot 4
Version 1.x supports Godot 3
(See GodotSharp.BuildingBlocks or local tests for example usage patterns)
Install via NuGet
SceneTree
_
operator)Advanced options available as attribute arguments
traverseInstancedScenes: (default false) Include instanced scenes in the generated hierarchy
// Attach a C# script on the root node of the scene with the same name.
// [SceneTree] will generate the members as the scene hierarchy.
[SceneTree]
public partial class MyScene : Node2D
{
public override void _Ready()
{
// You can access the node via '_' object.
GD.Print(_.Node1.Node11.Node12.Node121);
GD.Print(_.Node4.Node41.Node412);
// You can also directly access nodes marked as having a unique name in the editor
GD.Print(MyNodeWithUniqueName);
GD.Print(_.Path.To.MyNodeWithUniqueName); // Long equivalent
}
}
GodotOverride
Advanced options available as attribute arguments
public partial class MyNode : Node2D
{
[GodotOverride]
protected virtual void OnReady()
=> GD.Print("Ready");
[GodotOverride(replace: true)] private void OnProcess(double delta) => GD.Print("Processing");
// Requires partial method declaration for use with Godot 4.0 public override partial void _Ready(); public override partial void _Process(double delta); }
Generates:
```cs
public override void _Ready()
{
base._Ready();
OnReady();
}
public override _Process(double delta)
=> OnProcess(delta);
Notify
[NEW] Initial value can be set without triggering update (useful when using a non-nullable reference type)
public partial class NotifyTest : Node
{
[Notify]
public float Value1
{
get => _value1.Get();
set => _value1.Set(value); // You can also pass onchanged event handler here
}
public override void _Ready()
{
Value1Changing += () => GD.Print("Value1Changing raised before value is changed");
Value1Changed += () => GD.Print("Value1Changed raised after value is changed");
// You can also subscribe to private events if needed
// _value1.Changing += OnValue1Changing;
// _value1.Changed += OnValue1Changed;
// This might be useful... erm... if you need to clear the public listeners for some reason...?
Value1 = 1; // Raise Value1Changing and Value1Changed
Value1 = 2; // Raise Value1Changing and Value1Changed
Value1 = 2; // No event is raised since value is the same
}
public NotifyTest()
=> InitValue1(7); // [NEW] Set initial value without triggering events (optional)
}
InputMap
[InputMap]
public static partial class MyInput { }
Equivalent (for defined input actions) to:
// (static optional)
// (string rather than StringName for Godot 3)
// (does not provide access to built-in actions)
partial static class MyInput
{
public static readonly StringName MoveLeft = "move_left";
public static readonly StringName MoveRight = "move_right";
public static readonly StringName MoveUp = "move_up";
public static readonly StringName MoveDown = "move_down";
}
LayerNames
Provides strongly typed access to layer names defined in godot.project (set via editor)
[LayerNames]
public static partial class MyLayers { }
Equivalent (for defined layers) to:
// (static optional)
partial static partial class MyLayers
{
public static class Render2D
{
public const int MyLayer1 = 0; // Yes, layers start at 1 in editor, but 0 in code
public const int MyLayer2 = 1;
public const int MyLayer7 = 6;
public const int _11reyaLyM = 10; // Yes, we will append an underscore if required...
public static class Mask
{
public const uint MyLayer1 = 1 << 0;
public const uint MyLayer2 = 1 << 1;
public const uint MyLayer7 = 1 << 6;
public const uint _11reyaLyM = 1 << 10;
}
}
public static class Render3D
{
public const int MyLayer1 = 0;
public static class Mask
{
public const uint MyLayer1 = 1 << 0;
}
}
// Also for Physics2D, Physics3D, Navigation2D, Navigation3D, Avoidance, etc...
}
CodeComments
Advanced options available as attribute arguments
[CodeComments]
public partial class CodeCommentsTest : Node
{
// This a comment for Value1
// [CodeComments] only works with Property
[Export] public float Value1 { get; set; }
// Value 2 is a field so no comment [Export] public float value2;
public override void _Ready() { GD.Print(GetComment(nameof(Value1))); // output: "This a comment for Value1\n[CodeComments] only works with Property" GD.Print(GetComment(nameof(value2))); // output: "" (No output for fields, but could be added if needed) } }
### `OnInstantiate`
Advanced options available as attribute arguments
// Initialise can be public or protected if required; args also optional
// Currently assumes tscn is in same folder with same name
// Obviously only valid for root nodes
public partial class MyScene : Node
{
[OnInstantiate]
private void Initialise(string myArg1, int myArg2)
=> GD.PrintS("Init", myArg1, myArg2);
}
Generates (simplified):
private static PackedScene __scene__;
private static PackedScene __Scene__ => __scene__ ??= GD.Load<PackedScene>("res://Path/To/MyScene.tscn");
public static MyScene Instantiate(string myArg1, int myArg2)
{
var scene = Scene.Instantiate
private Test3Arg() {}
Usage:
```cs
// ... in some class
private void AddSceneToWorld()
{
var myScene = MyScene.Instantiate("str", 3);
MyWorld.AddChild(myScene);
}
OnImport