Righthand.GodotPropertyChangedGenerator 1.0.0-beta.5

Prefix Reserved
This is a prerelease version of Righthand.GodotPropertyChangedGenerator.
dotnet add package Righthand.GodotPropertyChangedGenerator --version 1.0.0-beta.5
                    
NuGet\Install-Package Righthand.GodotPropertyChangedGenerator -Version 1.0.0-beta.5
                    
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="Righthand.GodotPropertyChangedGenerator" Version="1.0.0-beta.5">
  <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="Righthand.GodotPropertyChangedGenerator" Version="1.0.0-beta.5" />
                    
Directory.Packages.props
<PackageReference Include="Righthand.GodotPropertyChangedGenerator">
  <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 Righthand.GodotPropertyChangedGenerator --version 1.0.0-beta.5
                    
#r "nuget: Righthand.GodotPropertyChangedGenerator, 1.0.0-beta.5"
                    
#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 Righthand.GodotPropertyChangedGenerator@1.0.0-beta.5
                    
#: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=Righthand.GodotPropertyChangedGenerator&version=1.0.0-beta.5&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Righthand.GodotPropertyChangedGenerator&version=1.0.0-beta.5&prerelease
                    
Install as a Cake Tool

Righthand Godot Properties Changed Source Generator (RGPCSG)

NuGet (with prereleases)

Development Release
status-badge status-badge

Why

This source generator is build with Godot tools in mind where your scene script has to notify Godot editor that it needs to redraw the node upon property changes. But it can be used everywhere where property change notification is required or one or more of other supported scenarios.

Imagine writing the code below for a Godot node without this source generator.

private int _simpleExportedWithDefault = 5;

public int SimpleExportedWithDefault
{
	get => _simpleExportedWithDefault;
	set
	{
		if (_simpleExportedWithDefault != value)
		{
			_simpleExportedWithDefault = value;
			UpdateState(nameof(SimpleExportedWithDefault));
		}
	}
}
private void UpdateState(string? propertyName)
{
	QueueRedraw();
}

Instead, the code below has the same functionality when RGPCSG is used.

[Export, DefaultValue(5)] public partial int SimpleExportedWithDefault { get; set; }

private void UpdateState(string? propertyName)
{
	QueueRedraw();
}

RGPCSG generates the rest of the code for free. More advanced scenarios are supported as well.

How to use

  1. Add Righthand.GodotPropertyChangedGenerator package from NuGet. Make sure you enable prerelease until stable version is released
  2. Create exported partial properties.
  3. Add void UpdateState(string? propertyName) implementation - usually one would call QueueRedraw() to redraw the node at design time.
  4. When using NoStoreAttribute _DisablePropertiesStorage has to be called with code like
public override void _ValidateProperty(Dictionary property) => _DisablePropertiesStorage(property);

Sample client is included in repository.

Supported scenarios

Default behavior

Calls UpdateState upon value changes.

Default values

There are two ways to provide default values.

  1. When default value is a constant, a DefaultValueAttribute can be used.
[Export, DefaultValue(5)] public partial int SimpleExportedWithDefault { get; set; }
  1. When default value is not a constant, a properly named [PROPERTYNAME]Default static property of the same type can be used:
[Export] public partial Color SampleProperty { get; set; }
public static readonly Color SamplePropertyDefault = Colors.Red;

Note: this approach can be used with constant values as well.

Making properties non persistent

Godot provides a way for making properties not persistant. If such behavior is desired, property has to be decorated with NoStoreAttribute and a call to _DisablePropertiesStorage has to be made within overriden _ValidateProperty method.

[Export, NoStore] public partial int NoStoreSimpleExported { get; set; }
public override void _ValidateProperty(Dictionary property) => _DisablePropertiesStorage(property);

Coerce values

When value has to be coerced, a properly named Coerce[PROPERTYNAME] coercion function with same types can be provided.

[Export] public partial int ExportedWithCoercion { get; set; }
public static int CoerceExportedWithCoercion(int newValue) => Math.Min(100, newValue);

Code comparision

See provided sample.

Without RGPCSG generator

public partial class TestTraditional: Node2D
{
	private int _simpleExported;

	public int SimpleExported
	{
		get => _simpleExported;
		set
		{
			if (_simpleExported != value)
			{
				_simpleExported = value;
				UpdateState(nameof(SimpleExported));
			}
		}
	}
	private int _noStoreSimpleExported;

	public int NoStoreSimpleExported
	{
		get => _noStoreSimpleExported;
		set
		{
			if (_noStoreSimpleExported != value)
			{
				_noStoreSimpleExported = value;
				UpdateState(nameof(NoStoreSimpleExported));
			}
		}
	}
	private int _simpleExportedWithDefault = 5;

	public int SimpleExportedWithDefault
	{
		get => _simpleExportedWithDefault;
		set
		{
			if (_simpleExportedWithDefault != value)
			{
				_simpleExportedWithDefault = value;
				UpdateState(nameof(SimpleExportedWithDefault));
			}
		}
	}

	private Color _notConstTypeExportedWithDefault = Colors.Red;

	public Color NotConstTypeExportedWithDefault
	{
		get => _notConstTypeExportedWithDefault;
		set
		{
			if (_notConstTypeExportedWithDefault != value)
			{
				_notConstTypeExportedWithDefault = value;
				UpdateState(nameof(NotConstTypeExportedWithDefault));
			}
		}
	}
	private int _exportedWithCoercion;

	public int ExportedWithCoercion
	{
		get => _exportedWithCoercion;
		set
		{
			if (_exportedWithCoercion != value)
			{
				_exportedWithCoercion = CoerceExportedWithCoercion(value);
				UpdateState(nameof(ExportedWithCoercion));
			}
		}
	}
	public static int CoerceExportedWithCoercion(int newValue) => Math.Min(100, newValue);

	public override void _ValidateProperty(Dictionary property)
	{
		const string usageKey = "usage";
		const string nameKey = "name";
		if (property.TryGetValue(nameKey, out var nameValue) || nameValue.VariantType != Variant.Type.String)
		{
			var name = nameValue.AsString();
			if (name.Equals(nameof(NoStoreSimpleExported), StringComparison.Ordinal))
			{
				if (!property.TryGetValue(usageKey, out var usageVariant) 
				    || usageVariant.VariantType != Variant.Type.Int)
				{
					var usage = usageVariant.AsInt32();
					var newUsage = usage &= ~(int)PropertyUsageFlags.Storage;
					if (usage != newUsage)
					{
						property[usageKey] = Variant.CreateFrom(newUsage);
					}
				}
			}
		}

		base._ValidateProperty(property);
	}


	private void UpdateState(string? propertyName)
	{
		QueueRedraw();
	}
}

With RGPCSG generator

public partial class Test : Node2D
{
	[Export] public partial int SimpleExported { get; set; }
	[Export, NoStore] public partial int NoStoreSimpleExported { get; set; }
	[Export, DefaultValue(5)] public partial int SimpleExportedWithDefault { get; set; }
	[Export] public partial Color NotConstTypeExportedWithDefault { get; set; }
	public static readonly Color NotConstTypeExportedWithDefaultDefault = Colors.Red;
	[Export] public partial int ExportedWithCoercion { get; set; }
	public static int CoerceExportedWithCoercion(int newValue) => Math.Min(100, newValue);

	private void UpdateState(string? propertyName)
	{
		QueueRedraw();
	}

	public override void _ValidateProperty(Dictionary property) => _DisablePropertiesStorage(property);
}
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
1.0.0-beta.5 74 1/25/2026
1.0.0-beta.4 70 1/24/2026
1.0.0-beta.3 64 1/18/2026
1.0.0-beta.2 67 1/17/2026
1.0.0-beta.1 66 1/17/2026

* adds #nullable enable to generated files