LokiCat.Godot.R3.ObservableSignals 1.0.15

There is a newer version of this package available.
See the version list below for details.
dotnet add package LokiCat.Godot.R3.ObservableSignals --version 1.0.15
                    
NuGet\Install-Package LokiCat.Godot.R3.ObservableSignals -Version 1.0.15
                    
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="LokiCat.Godot.R3.ObservableSignals" Version="1.0.15" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LokiCat.Godot.R3.ObservableSignals" Version="1.0.15" />
                    
Directory.Packages.props
<PackageReference Include="LokiCat.Godot.R3.ObservableSignals" />
                    
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 LokiCat.Godot.R3.ObservableSignals --version 1.0.15
                    
#r "nuget: LokiCat.Godot.R3.ObservableSignals, 1.0.15"
                    
#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 LokiCat.Godot.R3.ObservableSignals@1.0.15
                    
#: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=LokiCat.Godot.R3.ObservableSignals&version=1.0.15
                    
Install as a Cake Addin
#tool nuget:?package=LokiCat.Godot.R3.ObservableSignals&version=1.0.15
                    
Install as a Cake Tool

LokiCat.Godot.R3.ObservableSignals

R3-compatible source generator for turning [RxSignal]-annotated observables in Godot C# into fully reactive Godot signals and cached Observable<T> properties.

This package eliminates boilerplate when exposing Godot signals through R3 observables.
It generates real [Signal] Godot events, connects them to your observable streams, and automatically emits signals when your code pushes data.


โœจ Features

  • Automatically detects [RxSignal]-annotated observable fields (e.g., Subject<T>) in Godot C# partial classes
  • Generates matching [Signal] Godot delegate declarations automatically
  • Generates a ConnectGodotSignals() method for wiring Observables to Godot signals
  • Supports 0 to 5 parameters in emitted signals
  • No runtime Connect needed for custom signals
  • Full R3 compatibility for reactive pipelines and disposal
  • Clean, manual control over when signals are fired via .OnNext()
  • Fully supports Godot Editor and visual signal connections
  • Supports Subject<T>, ReplaySubject<T>, BehaviorSubject<T>, ReactiveProperty<T>, and any other Observable<T>-derived types
  • Still includes dynamic .Signal(...) extension methods for wrapping built-in Godot signals (e.g., Button.Pressed, Area2D.BodyEntered)

๐Ÿ‘ Why This is Useful

Before, exposing Godot signals in a reactive way required manual wiring, manual Connect(...) calls, and custom observable creation:

Old Way (Manual)

[Signal]
public delegate void PressedEventHandler(BaseButton button);

private Observable<BaseButton> _onPressed;
public Observable<BaseButton> OnPressed => _onPressed ??= Observable.Create<BaseButton>(observer => {
    var callable = Callable.From((BaseButton button) => observer.OnNext(button));
    Connect(nameof(Pressed), callable);
    return Disposable.Empty;
});

New Way (With This Package)

[RxSignal]
private readonly Subject<BaseButton> _onButtonPressed = new();

public Observable<BaseButton> OnButtonPressed => _onButtonPressed;

public override void _Ready()
{
    ConnectGodotSignals();
}

public void PressButton(BaseButton button)
{
    _onButtonPressed.OnNext(button);
}

โœ… Much less code. โœ… No manual Connect() needed for custom signals. โœ… Full control when you fire signals with .OnNext(). โœ… Safer, reactive, and easier to test. โœ… Dynamic wrapping still available for built-in signals if needed.


๐Ÿ“ฆ Installation

  1. Add this NuGet package to your project:
dotnet add package LokiCat.Godot.R3.ObservableSignals
  1. Define your interfaces and classes:

Interface

public partial interface IPauseMenu
{
    Observable<Unit> OnMainMenuSelected { get; }
}

Class Implementation

public partial class PauseMenu : Control, IPauseMenu
{
    [RxSignal]
    private readonly Subject<Unit> _onMainMenuSelected = new();

    public Observable<Unit> OnMainMenuSelected => _onMainMenuSelected;

    public override void _Ready()
    {
        ConnectGodotSignals();
    }

    public void SelectMainMenu()
    {
        _onMainMenuSelected.OnNext(Unit.Default);
    }
}

โœ… That's it. No manual Connect, no manual EmitSignal needed for your own signals.


โœ… Supported Signal Forms

Observable Type Generated Signal and Emission
Observable<Unit> EmitSignal("SignalName")
Observable<T> EmitSignal("SignalName", T)
Observable<(T1, T2)> EmitSignal("SignalName", T1, T2)
... up to 5 arguments EmitSignal("SignalName", T1, T2, ..., T5)

Signals with more than 5 parameters are not supported and will trigger a generator warning.

Supported Field Types

You can annotate fields of type:

  • Subject<T>
  • ReplaySubject<T>
  • BehaviorSubject<T>
  • ReactiveProperty<T>
  • Any custom type inheriting Observable<T> that supports emitting values

๐Ÿ›  Using Both Systems Together

  • Use [RxSignal] and ConnectGodotSignals() for your own custom signals.
  • Use .Signal(this Node node, string signalName, ref cache) extension methods for wrapping built-in Godot signals you cannot modify (e.g., Button.Pressed, Area2D.BodyEntered).

โœ… Both systems can coexist cleanly. โœ… No conflicts.


๐Ÿง  How It Works

  • You define [RxSignal] observable fields (Subject<T>, ReplaySubject<T>, etc.)
  • You expose public Observable<T> properties
  • The generator emits:
    • A [Signal] Godot delegate for each signal
    • A ConnectGodotSignals() method that wires the Observables to EmitSignal calls
  • When you call .OnNext(), it automatically fires the Godot signal and notifies any R3 subscribers.

๐Ÿ›  Example: Full Class

public partial class ButtonGroup : Control
{
    [RxSignal]
    private readonly Subject<BaseButton> _onButtonPressed = new();

    public Observable<BaseButton> OnButtonPressed => _onButtonPressed;

    public override void _Ready()
    {
        ConnectGodotSignals();
    }

    public void PressButton(BaseButton button)
    {
        _onButtonPressed.OnNext(button);
    }
}

โฌ‡๏ธ The generator automatically emits:

[Signal]
public delegate void ButtonPressedEventHandler();

private void ConnectGodotSignals()
{
    OnButtonPressed.Subscribe(button => EmitSignal(nameof(ButtonPressed), button)).AddTo(this);
}

๐Ÿงช Troubleshooting

  • Make sure your classes are marked partial
  • Annotate observable fields with [RxSignal]
  • Expose observables with public Observable<T> properties
  • Call ConnectGodotSignals() in _Ready()
  • Use #nullable enable if you are using nullable types in your fields or properties

๐Ÿ“„ License

MIT License


๐Ÿ’ก Bonus Tip

Pair this generator with Chickensoft, R3, Godot, and other LokiCat Godot/.NET packages to create fully reactive, signal-driven gameplay systems that are easy to extend, test, and maintain.

There are no supported framework assets in this package.

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.

Version Downloads Last Updated
1.0.70 236 7/2/2025
1.0.69 118 6/21/2025
1.0.68 105 6/21/2025
1.0.65 141 6/19/2025
1.0.64 140 6/19/2025
1.0.63 139 6/19/2025
1.0.62 137 6/19/2025
1.0.61 140 6/19/2025
1.0.60 141 6/19/2025
1.0.59 139 6/19/2025
1.0.58 142 6/19/2025
1.0.57 139 6/19/2025
1.0.56 144 6/19/2025
1.0.55 139 6/19/2025
1.0.54 139 6/18/2025
1.0.53 140 6/18/2025
1.0.52 137 6/18/2025
1.0.51 145 6/18/2025
1.0.47 153 6/14/2025
1.0.40 154 6/14/2025
1.0.38 163 6/14/2025
1.0.37 138 5/9/2025
1.0.36 81 5/9/2025
1.0.35 81 5/9/2025
1.0.34 82 5/9/2025
1.0.33 146 5/8/2025
1.0.32 146 5/8/2025
1.0.31 146 5/1/2025
1.0.30 152 5/1/2025
1.0.29 151 5/1/2025
1.0.28 150 4/30/2025
1.0.26 147 4/30/2025
1.0.25 146 4/30/2025
1.0.24 144 4/30/2025
1.0.23 152 4/30/2025
1.0.22 150 4/30/2025
1.0.21 142 4/30/2025
1.0.20 146 4/30/2025
1.0.19 142 4/29/2025
1.0.18 159 4/29/2025
1.0.17 156 4/28/2025
1.0.16 159 4/27/2025
1.0.15 166 4/27/2025
1.0.14 159 4/27/2025
1.0.13 157 4/27/2025
1.0.12 155 4/27/2025
1.0.11 152 4/27/2025
1.0.9 160 4/27/2025
1.0.7 161 4/27/2025
1.0.1 152 4/27/2025
1.0.0 159 4/27/2025
0.0.6 247 4/19/2025
0.0.5 169 4/19/2025