A slimmed fork of https://github.com/Cat-Lips/GodotSharp.SourceGenerators containing bug fixes and new features.
Contains C# Source Generators for use with the Godot Game Engine 4.x and up.
SceneTreeclass attribute:- Provides strongly typed access to the scene hierarchy (via
_operator) - Generates direct access to uniquely named nodes via class properties
- Provides strongly typed access to the scene hierarchy (via
Instantiableclass attribute:- Generates configurable static method(s) to instantiate scene
InputMapclass attribute:- Provides strongly typed access to input actions defined in godot.project
- Attribute option to replace StringName with your own custom object/handler
- Generates
SortInputActionshelper for sorted dropdowns in the Godot editor
TscnFilePathclass attribute:- Generates a static
TscnFilePathproperty without the fullSceneTreehierarchy
- Generates a static
TresFilePathclass attribute:- Generates a static
TresFilePathproperty pointing to the associated.tresresource file
- Generates a static
- Includes base classes/helpers to create project specific source generators
Install via NuGet
- Class attribute
- Provides strongly typed access to the scene hierarchy (via
_operator) - Generates direct access class properties for uniquely named nodes
- Generates an interface for static tscn retrieval (ISceneTree.TscnFilePath)
- Generates an interface for static instantiation (IInstantiable.Instantiate)
- Note that nodes are cached on first access to avoid interop overhead
- Advanced options available as attribute arguments:
- tscnRelativeToClassPath: (default null) Specify path to tscn relative to current class
- traverseInstancedScenes: (default false) Include instanced scenes in the generated hierarchy
- root: (default _) Provide alternative to
_operator (eg, to allow use of C# discard variable) - uqScope: (default Public) Default access scope for uniquely named node properties
// Attach a C# script on the root node of the scene with the same name
// [SceneTree] will generate the members as the scene hierarchy and TscnFilePath property
[SceneTree]
//[SceneTree(root: "ME")] // Use this for alternative to `_`
//[SceneTree("my_scene.tscn")] // Use this if tscn has different name
//[SceneTree("../Scenes/MyScene.tscn")] // Use relative path if tscn located elsewhere
//[SceneTree(traverseInstancedScenes: true)] // Use this to include instanced scenes in current hierarchy
//[SceneTree(uqScope: Scope.Protected)] // Use this to specify default scope of uniquely named nodes (default: 'Public')
public partial class MyScene : Node
{
// Default scope of uniquely named nodes can be overridden using partial properties
private partial MyNodeType MyNodeWithUniqueName { get; }
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
// Only leaf nodes are Godot types (call .Get() on branch nodes)
// Lets say you have _.Node1.Node2, observe the following code
GD.Print(_.Node1.Name); // invalid
GD.Print(_.Node1.Get().Name); // valid
Node node1 = _.Node1; // implicit conversion also possible!
GD.Print(node1.Name); // valid
GD.Print(_.Node1.Node2.Name); // valid
}
}
// TscnFilePath usage:
public void NextScene()
=> GetTree().ChangeSceneToFile(MyScene.TscnFilePath);- Generated for any class decorated with [SceneTree]
namespace Djentinga.Godot.SourceGenerators;
public partial interface ISceneTree
{
static abstract string TscnFilePath { get; }
}Usage:
public void NextScene<T>() where T : ISceneTree
=> GetTree().ChangeSceneToFile(T.TscnFilePath);- Provides a default Instantiate method that uses TscnFilePath
- Both non-generic and generic versions are available
- A default Instantiator class is also available
public partial interface IInstantiable
{
static T Instantiate<T>() where T : Node, ISceneTree
=> GD.Load<PackedScene>(T.TscnFilePath).Instantiate<T>();
}
public partial interface IInstantiable<T> where T : Node, IInstantiable<T>, ISceneTree
{
static T Instantiate() => GD.Load<PackedScene>(T.TscnFilePath).Instantiate<T>();
}
public static partial class Instantiator
{
public static T Instantiate<T>() where T : Node, ISceneTree
=> GD.Load<PackedScene>(T.TscnFilePath).Instantiate<T>();
}Usage:
[SceneTree]
public partial class Scene1 : Node;
[SceneTree]
public partial class Scene2 : Node, IInstantiable;
[SceneTree]
public partial class Scene3 : Node, IInstantiable<Scene3>;
*****
// Instantiator works for all ISceneTree types
var scene1 = Instantiator.Instantiate<Scene1>();
var scene2 = Instantiator.Instantiate<Scene2>();
var scene3 = Instantiator.Instantiate<Scene3>();
// The non-generic interface can also instantiate any ISceneTree type (but why would you want to)
var scene1 = IInstantiable.Instantiate<Scene1>();
var scene2 = IInstantiable.Instantiate<Scene2>();
var scene3 = IInstantiable.Instantiate<Scene3>();
// The generic interface can only instantiate it's own ISceneTree type (but why would you want to)
var scene3 = IInstantiable<Scene3>.Instantiate();
// Use generics to instantiate specific types
static T Instantiate<T>() where T : Node, ISceneTree, IInstantiable
=> IInstantiable.Instantiate<T>(); // or Instantiator.Instantiate<T>();
var scene2 = Instantiate<Scene2>();
OR
static T Instantiate<T>() where T : Node, ISceneTree, IInstantiable<T>
=> IInstantiable<T>.Instantiate(); // or Instantiator.Instantiate<T>();
var scene3 = Instantiate<Scene3>();- Class attribute
- Generates configurable static method(s) to instantiate scene
- Generates configurable constructor to ensure safe construction
- Advanced options available as attribute arguments:
- init: (default 'Init') Name of init function
- name: (default 'New') Name of instantiate function
[Instantiate]
public partial class Scene1 : Node
{
// No Init()
}
[Instantiate]
public partial class Scene2 : Node
{
private void Init()
private void Init(int arg)
}
[Instantiate(nameof(Initialise), "Instantiate")]
public partial class Scene3 : Node
{
private void Initialise(int arg1, string arg2, object arg3 = null)
}Generates:
partial class Scene1
{
[EditorBrowsable(EditorBrowsableState.Never)]
private static PackedScene _Scene1 => field ??= GD.Load<PackedScene>("res://Path/To/Scene1.tscn");
public static Scene1 New() => (Scene1)_Scene1.Instantiate();
}
partial class Scene2
{
[EditorBrowsable(EditorBrowsableState.Never)]
private static PackedScene _Scene2 => field ??= GD.Load<PackedScene>("res://Path/To/Scene2.tscn");
public static Scene2 New()
{
var scene = (Scene2)_Scene2.Instantiate();
scene.Init();
return scene;
}
public static Scene2 New(int arg)
{
var scene = (Scene2)_Scene2.Instantiate();
scene.Init(arg);
return scene;
}
}
partial class Scene3
{
[EditorBrowsable(EditorBrowsableState.Never)]
private static PackedScene _Scene3 => field ??= GD.Load<PackedScene>("res://Path/To/Scene3.tscn");
public static Scene3 Instantiate(int arg1, string arg2, object arg3 = null)
{
var scene = (Scene3)_Scene3.Instantiate();
scene.Initialise(arg1, arg2, arg3);
return scene;
}
}- Class attribute
- Provides strongly typed access to input actions defined in godot.project (set via editor)
- Actions are sorted alphabetically in the generated code
- Generates a
SortInputActionshelper method for sorted dropdowns in the Godot editor - If you want access to built-in actions, see BuiltinInputActions.cs
- Advanced options available as attribute arguments:
- dataType: (default StringName)
[InputMap]
public static partial class MyInput;
[InputMap(nameof(GameInput))]
public static partial class MyGameInput;
// Example custom input action class
public class GameInput(StringName action)
{
public StringName Action => action;
public bool IsPressed => Input.IsActionPressed(action);
public bool IsJustPressed => Input.IsActionJustPressed(action);
public bool IsJustReleased => Input.IsActionJustReleased(action);
public float Strength => Input.GetActionStrength(action);
public void Press() => Input.ActionPress(action);
public void Release() => Input.ActionRelease(action);
}Generates:
// (static optional)
// (does not provide access to built-in actions)
partial static class MyInput
{
/// <summary>
/// Replaces <c>PropertyHint.InputName</c> with a sorted <c>PropertyHint.Enum</c> dropdown in the Godot editor.
/// Call from <c>_ValidateProperty</c> to sort the input action dropdown.
/// </summary>
public static void SortInputActions(Godot.Collections.Dictionary property) { ... }
public static readonly StringName MoveDown = new("move_down");
public static readonly StringName MoveLeft = new("move_left");
public static readonly StringName MoveRight = new("move_right");
public static readonly StringName MoveUp = new("move_up");
}
partial static class MyGameInput
{
public static void SortInputActions(Godot.Collections.Dictionary property) { ... }
public static readonly GameInput MoveDown = new("move_down");
public static readonly GameInput MoveLeft = new("move_left");
public static readonly GameInput MoveRight = new("move_right");
public static readonly GameInput MoveUp = new("move_up");
}Use the generated SortInputActions method in _ValidateProperty to replace the default unsorted input action dropdown with a sorted enum dropdown:
public override void _ValidateProperty(Godot.Collections.Dictionary property)
{
MyInput.SortInputActions(property);
}- Class attribute
- Lightweight alternative to
[SceneTree]when you only need theTscnFilePathproperty - Generates a static
TscnFilePathproperty and implementsISceneTree - Advanced options available as attribute arguments:
- tscnRelativeToClassPath: (default null) Specify path to tscn relative to current class
// Generates TscnFilePath for the .tscn file with the same name as the class
[TscnFilePath]
public partial class MyScene : Node;
// Specify a custom path relative to the class file
[TscnFilePath("../Scenes/MyScene.tscn")]
public partial class MyScene : Node;Generates:
partial class MyScene : Godot.ISceneTree
{
public static string TscnFilePath { get; } = "res://Path/To/MyScene.tscn";
}- Class attribute
- Generates a static
TresFilePathproperty pointing to the associated.tresresource file - Advanced options available as attribute arguments:
- tresRelativeToClassPath: (default null) Specify path to tres relative to current class
// Generates TresFilePath for the .tres file with the same name as the class
[TresFilePath]
public partial class MyResource : Resource;
// Specify a custom path relative to the class file
[TresFilePath("../Resources/MyResource.tres")]
public partial class MyResource : Resource;Generates:
partial class MyResource
{
public static string TresFilePath { get; } = "res://Path/To/MyResource.tres";
}