![]() |
VOOZH | about |
dotnet add package Chickensoft.LogicBlocks --version 6.1.0
NuGet\Install-Package Chickensoft.LogicBlocks -Version 6.1.0
<PackageReference Include="Chickensoft.LogicBlocks" Version="6.1.0" />
<PackageVersion Include="Chickensoft.LogicBlocks" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Chickensoft.LogicBlocks" />Project file
paket add Chickensoft.LogicBlocks --version 6.1.0
#r "nuget: Chickensoft.LogicBlocks, 6.1.0"
#:package Chickensoft.LogicBlocks@6.1.0
#addin nuget:?package=Chickensoft.LogicBlocks&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Chickensoft.LogicBlocks&version=6.1.0Install as a Cake Tool
LogicBlocks is a serializable, hierarchical state machine package for C# that works well when targeting ahead-of-time (AOT) environments. LogicBlocks draws inspiration from statecharts, state machines, and blocs.
<p align="center"> <img alt="Chickensoft.LogicBlocks" src="Chickensoft.LogicBlocks/icon.png" width="200"> </p>
Instead of elaborate transition tables, states are simply defined as self-contained class records that read like ordinary code using the state pattern. Logic blocks are designed with performance, adaptability, and error tolerance in mind, making them refactor-friendly and suitable for high performance scenarios (such as games).
Logic blocks grow with your code: you can start with a simple state machine and easily scale it into a nested, hierarchical statechart that represents a more complex system โ even while you're working out what the system should be.
Logic blocks are based on statecharts. You may also know them as hierarchical state machines (HSM's).
๐จ The Official โจ LogicBlocks Docs โจ
Read this as soon as you're up to speed on statecharts.
๐ข Introduction to State Machines and Statecharts
Beginner: overview for those who are new to statecharts.
๐ก Statecharts.dev
Intermediate: all the statechart concepts in one place.
๐ด UML State Machine (Wikipedia)
Expert: all the juicy technical details are here.
๐ต Logic Blocks Timer Tutorial
In a hurry? Learn about hierarchical states and logic blocks all at once!
A logic block is a class that receives inputs, maintains a single state instance, and produces outputs.
Logic blocks enable you to efficiently model complex behaviors[^1].
In v6, the logic block has no generic type parameter, states live outside the logic block class, and input handlers return Type instead of a Transition struct.
// LightSwitchLogic.cs
public partial class LightSwitchLogic : LogicBlock
{
public LightSwitchLogic()
{
// Preallocate states
Set(new LightSwitchState.PoweredOn());
Set(new LightSwitchState.PoweredOff());
}
}
public abstract partial record LightSwitchState : LogicBlockState
{
public static class Input
{
public readonly record struct Toggle;
}
public static class Output
{
public readonly record struct StatusChanged(bool IsOn);
}
}
// LightSwitchStates.cs
public partial record LightSwitchState
{
public record PoweredOn : LightSwitchState, IGet<Input.Toggle>
{
public PoweredOn()
{
this.OnEnter(() => Output(new Output.StatusChanged(IsOn: true)));
}
public Type On(in Input.Toggle input) => To<PoweredOff>();
}
public record PoweredOff : LightSwitchState, IGet<Input.Toggle>
{
public PoweredOff()
{
this.OnEnter(() => Output(new Output.StatusChanged(IsOn: false)));
}
public Type On(in Input.Toggle input) => To<PoweredOn>();
}
}
// Usage
using var logic = new LightSwitchLogic();
logic.Start<LightSwitchState.PoweredOff>();
logic.Input(new LightSwitchState.Input.Toggle());
// logic.State is now LightSwitchState.PoweredOn
Observe a logic block by creating a binding. Bindings are IDisposable โ dispose them when done.
using var binding = logic.Bind();
binding
.OnState<LightSwitchState.PoweredOn>(_ => Console.WriteLine("Light is on"))
.OnState<LightSwitchState.PoweredOff>(_ => Console.WriteLine("Light is off"))
.OnOutput<LightSwitchState.Output.StatusChanged>(
output => Console.WriteLine($"Status changed: {output.IsOn}")
)
.OnStart(() => Console.WriteLine("Started"))
.OnStop(() => Console.WriteLine("Stopped"));
LogicBlocks provides a source generator that can generate UML state diagrams of your code.
stateDiagram-v2
state "LightSwitch State" as Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State {
state "PoweredOn" as Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOn
state "PoweredOff" as Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOff
}
Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOff --> Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOn : Toggle
Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOn --> Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOff : Toggle
Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOff : OnEnter โ StatusChanged
Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOn : OnEnter โ StatusChanged
[*] --> Chickensoft_LogicBlocks_DiagramGenerator_Tests_TestCases_LightSwitch_State_PoweredOff
Add [StateDiagram] to your base state class to enable diagram generation. Generated *.g.puml files are placed alongside your code. You can use PlantUML (and/or the PlantUML VSCode Extension) to visualize them.
[StateDiagram]
public abstract partial record LightSwitchState : LogicBlockState { ... }
A diagram explains all of the high-level behavior of a state machine in a single picture. Without a diagram, you would have to read through every relevant code file to understand the machine.
Logic blocks support a state history stack, enabling pushdown automaton behavior โ push the current state type and pop it later to return to a previous state.
public Type On(in Input.Pause input)
{
Push(); // save current state type on the history stack
return To<Paused>();
}
public Type On(in Input.Resume input)
{
return Pop() ?? To<Playing>(); // restore previous state, or fall back
}
The history stack has a configurable maximum capacity (default: 8).
Bridge async tasks safely back into the synchronous input pipeline using Async():
public Type On(in Input.Load input)
{
Async(FetchDataAsync())
.Input(data => new Input.Loaded(data))
.ErrorInput(ex => new Input.LoadFailed(ex.Message))
.CanceledInput(() => new Input.LoadCanceled());
return ToSelf();
}
For logic blocks that need serialization, extend AutoBlock instead of LogicBlock. AutoBlock integrates with [Chickensoft.Introspection] and [Chickensoft.Serialization] to automatically discover and preallocate all concrete states, and to save/load state.
[Meta, Id("my_logic")]
public partial class MyLogic : AutoBlock
{
public MyLogic()
{
Preallocate<MyState>(); // discover and preallocate all concrete states
}
public override ILogicBlockSaveData GetSaveData(LogicBlockData data) =>
new MySaveData { Data = data };
}
// Save
var saveData = myLogic.Save();
// Load (resume from saved state)
myLogic.Start(saveData.Data);
Test individual states in isolation using state.Test():
var state = new LightSwitchState.PoweredOff();
var tester = state.Test();
tester.Set(new SomeDependency());
state.Enter();
tester.Outputs.ShouldContain(new LightSwitchState.Output.StatusChanged(IsOn: false));
Use LogicBlock.CreateFakeBinding() to test binding callbacks without a real logic block:
using var binding = LogicBlock.CreateFakeBinding();
binding.OnState<LightSwitchState.PoweredOn>(_ => ranCallback = true);
binding.SetState(new LightSwitchState.PoweredOn());
ranCallback.ShouldBeTrue();
In the interest of convenience, logic blocks have a few subtle differences from statecharts:
๐โโ๏ธ No explicit guards
Use conditional logic in an input handler
๐ชข Attach/Detach callbacks
These are an implementation specific detail that are called whenever the state instance changes, as opposed to only being called when the state type hierarchy (i.e., state configuration) changes.
๐ฐ๏ธ No event deferral
Non-handled inputs are simply discarded. There's nothing to stop you from implementing input buffering on your own, though: you may even use the boxless queue collection that LogicBlocks uses internally.
LogicBlocks also uses different terms for some of the statechart concepts to make them more intuitive or disambiguate them from other C# terminology.
| statecharts | logic blocks |
|---|---|
| internal transition | self transition |
| event | input |
| action | output |
[^1]: Simple behaviors, like the light switch example, are considerably more verbose than they need to be. Logic blocks shine brightest when they're used for things that actually require hierarchical state machines.
Looking for more? Read the โจ docs! โจ
๐ฃ Package generated from a ๐ค Chickensoft Template โ https://chickensoft.games
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 netstandard2.1 is compatible. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 1 NuGet packages that depend on Chickensoft.LogicBlocks:
| Package | Downloads |
|---|---|
|
Chickensoft.LogicBlocks.Auto
Automatic serialization and introspection support for LogicBlocks hierarchical state machines. |
Showing the top 1 popular GitHub repositories that depend on Chickensoft.LogicBlocks:
| Repository | Stars |
|---|---|
|
chickensoft-games/GameDemo
The Chickensoft Game Demo โ a fully tested, third-person 3D game built with Godot and C#. Now with saving and loading!
|
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.0 | 175 | 6/13/2026 |
| 6.0.0 | 311 | 6/2/2026 |
| 5.20.0 | 7,042 | 9/7/2025 |
| 5.19.1 | 1,234 | 6/30/2025 |
| 5.19.0 | 1,147 | 5/22/2025 |
| 5.18.0 | 663 | 4/12/2025 |
| 5.17.1 | 438 | 4/7/2025 |
| 5.17.0 | 354 | 3/31/2025 |
| 5.16.0 | 1,981 | 1/23/2025 |
| 5.15.0 | 476 | 1/10/2025 |
| 5.14.0 | 416 | 12/17/2024 |
| 5.13.0 | 566 | 11/26/2024 |
| 5.12.0 | 711 | 10/23/2024 |
| 5.11.1 | 268 | 10/23/2024 |
| 5.11.0 | 389 | 10/9/2024 |
| 5.10.0 | 297 | 10/4/2024 |
| 5.9.0 | 340 | 9/27/2024 |
| 5.8.0 | 337 | 9/17/2024 |
| 5.7.0 | 200 | 9/17/2024 |
| 5.6.0 | 435 | 9/4/2024 |
LogicBlocks release.