LokiCat.GodotNodeInterfaces.Observables
1.0.17
See the version list below for details.
dotnet add package LokiCat.GodotNodeInterfaces.Observables --version 1.0.17
NuGet\Install-Package LokiCat.GodotNodeInterfaces.Observables -Version 1.0.17
<PackageReference Include="LokiCat.GodotNodeInterfaces.Observables" Version="1.0.17" />
<PackageVersion Include="LokiCat.GodotNodeInterfaces.Observables" Version="1.0.17" />
<PackageReference Include="LokiCat.GodotNodeInterfaces.Observables" />
paket add LokiCat.GodotNodeInterfaces.Observables --version 1.0.17
#r "nuget: LokiCat.GodotNodeInterfaces.Observables, 1.0.17"
#:package LokiCat.GodotNodeInterfaces.Observables@1.0.17
#addin nuget:?package=LokiCat.GodotNodeInterfaces.Observables&version=1.0.17
#tool nuget:?package=LokiCat.GodotNodeInterfaces.Observables&version=1.0.17
LokiCat.GodotNodeInterfaces.Observables
Generate R3 Observables from Chickensoft.GodotNodeInterfaces signals
Overview
This project provides a Roslyn source generator that automatically creates R3 observable extensions for each signal exposed by the Chickensoft.GodotNodeInterfaces
interfaces.
You get strongly typed, composable observables that make it easy to work with Godot signals in a reactive way using R3.
Why bother?
- We want to program to Interfaces (see: Chickensoft.GodotNodeInterfaces)
- We want to use Reactive X style Observables for signal management (see: R3 )
- R3 provides a limited set of preconfigured Observable wrappers
- LokiCat.GodotNodeInterfaces.Observables: Now we can have Rx & program to interfaces without having to write wrappers every time!
Lets look at an example:
Lets say you have a menu that uses a button IBaseButton
, and you want to use an Observable for the Toggled
signal of that button.
Pure C# Events w/ GodotNodeInterface
- ✅ We get the behavior we want.
- ❌ We have to manage the subscription and unsubscription ourselves.
- ❌ We want ReactiveX
public partial class MyMenu : Control, IControl {
private IBaseButton doSomethingButton;
public void OnReady() {
doSomethingButton.Pressed += DoSomething;
}
public void OnExitTree() {
// We have to remember to unsubscribe.
// Not difficult, but easy to forget when managing behavior in multiple places.
doSomething.Pressed -= DoSomething;
}
private void DoSomething(bool isToggledOn) { /* Do stuff */ }
}
Using an R3 Observable
Here, we're using R3 to manually wrap our events into Observables
- ✅ We get the behavior we want.
- ✅ Only manage it in one place
- ✅ We have ReactiveX
- ❌ Observable takes quite a few lines to setup
- ❌ Some of the Godot EventHandler types involve more casting than this example.
public partial class MyMenu : Control, IControl {
private IBaseButton doSomethingButton;
public void OnReady() {
Observable.FromEvent<ToggledEventHandler, bool>(
h => (toggledOn) => h(toggledOn), // We could use a lambda here, if we wanted.
h => doSomethingButton.Toggled += h,
h => doSomethingButton.Toggled -= h,
cancellationToken // Optional
).Subscribe(DoSomething)
.AddTo(this); // Cleanup happens here now. Yay!
}
private void DoSomething(bool isToggledOn) { /* Do stuff */ }
}
Using LokiCat.GodotNodeInterfaces.Observables
- ✅ We get the behavior we want.
- ✅ Only manage it in one place
- ✅ We have ReactiveX
- ✅ Observables ready-to-use
- ✅ No explicit casting to fiddle with or extra code to write
- ✅ We can use lambdas too!
public partial class MyMenu : Control, IControl {
private IBaseButton doSomethingButton;
public void OnReady() {
doSomethingButton.OnPressedAsObservable()
.Subscribe(DoSomething)
.AddTo(this);
}
private void DoSomething(bool isToggledOn) { /* Do stuff */ }
}
✨ Features
- 🔧 Zero config: Just install the package and observe away.
- ⚡ Automatic discovery of all signals defined in
Chickensoft.GodotNodeInterfaces
. - 🧪 Fully tested generator logic.
- 🧵 Handles custom delegate signal types (like
ButtonPressedEventHandler
). - 📦 Designed for
.NET 7+
, compatible with Godot 4.x C# projects.
📦 Installation
Install via NuGet:
dotnet add package LokiCat.GodotNodeInterfaces.Observables
🔌 Usage
No setup is required. Once the package is installed, the source generator will run during build and add extension methods for each interface's signals.
You can observe any Godot signal (from the Chickensoft interfaces) like so:
public partial class MyNode : Node2D {
public override void _Ready() {
this.OnPressedAsObservable()
.Subscribe(_ => GD.Print("Pressed!"));
}
}
The method name pattern is:
On[SignalName]AsObservable()
These methods are automatically added to the interface types like IButton
, IArea2D
, etc.
Each observable uses the signal's native delegate (including custom Godot signal delegate types), and returns Observable<T>
where T
is:
- The signal parameter type (if 1 parameter)
- A tuple
(T1, T2, ...)
(if multiple parameters) Unit
(if no parameters)
🧪 Examples
Observing Pressed
from IButton
button.OnPressedAsObservable()
.Subscribe(_ => GD.Print("Button was pressed"));
Observing MouseEntered
from IArea2D
area.OnMouseEnteredAsObservable()
.Subscribe(_ => ShowTooltip());
Observing complex signal with parameters
For a signal like:
event InputEventEventHandler(Godot.Node viewport, Godot.InputEvent @event, long shapeIdx);
Generated observable extension:
collision.OnInputEventAsObservable()
.Subscribe(tuple => {
var (viewport, evt, shapeIdx) = tuple;
GD.Print($"Input received on shape {shapeIdx}");
});
Composing observables with R3
button.OnPressedAsObservable()
.ThrottleFirst(TimeSpan.FromMilliseconds(500))
.Subscribe(_ => GD.Print("Throttled click!"));
⚙️ Dependencies
🧱 How It Works
- Uses Roslyn source generation to discover every
event
declared inChickensoft.GodotNodeInterfaces
interfaces. - Ignores inherited events (to avoid duplicate generation).
- Generates extension methods per event with exact types.
- Handles custom Godot signal delegates with correct constructor/parameter logic.
All source is generated at compile time and added to your build transparently.
🧪 Tests
Tests cover:
- Events with 0, 1, or many parameters
- Delegates with and without constructors
- Namespace resolution
- Method name and return type formatting
You can run tests locally:
dotnet test
🛠 Development
To build from source:
dotnet build -c Release
To pack for NuGet:
dotnet pack -c Release
🙏 Credits
- Chickensoft for the base interfaces
- R3 for a clean observable abstraction
- Godot C# community for enabling signal-first development
📄 License
MIT
Learn more about Target Frameworks and .NET Standard.
-
net7.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.