StateMachineBuddy 5.0.5
dotnet add package StateMachineBuddy --version 5.0.5
NuGet\Install-Package StateMachineBuddy -Version 5.0.5
<PackageReference Include="StateMachineBuddy" Version="5.0.5" />
<PackageVersion Include="StateMachineBuddy" Version="5.0.5" />
<PackageReference Include="StateMachineBuddy" />
paket add StateMachineBuddy --version 5.0.5
#r "nuget: StateMachineBuddy, 5.0.5"
#:package StateMachineBuddy@5.0.5
#addin nuget:?package=StateMachineBuddy&version=5.0.5
#tool nuget:?package=StateMachineBuddy&version=5.0.5
StateMachineBuddy
A finite state machine library for .NET and MonoGame projects. Define states and messages, configure transitions between states, send messages to trigger transitions, and subscribe to events when state changes occur.
Installation
Install via NuGet:
dotnet add package StateMachineBuddy
NuGet Package: StateMachineBuddy
Version: 5.0.2
Target Framework: .NET 8.0
License: MIT
Dependencies
MonoGame.Framework.DesktopGL(3.8.*)FilenameBuddy(5.*)XmlBuddy(5.*)
Overview
StateMachineBuddy provides three state machine implementations:
| Class | State Type | Message Type | Use Case |
|---|---|---|---|
IntStateMachine |
int |
int |
High-performance scenarios with integer indices |
StringStateMachine |
string |
string |
Flexibility with string-based states |
EnumStateMachine<TState, TMessage> |
Enum | Enum | Type-safe enum-based state machines |
Core Concepts
- State: A discrete condition the machine can be in
- Message: An input that may trigger a state transition
- Transition: A rule defining: when in state X and receiving message Y, move to state Z
- Initial State: The starting state of the machine
Quick Start
Using EnumStateMachine (Recommended)
using StateMachineBuddy;
// Define your states and messages as enums
public enum PlayerState { Idle, Walking, Running, Jumping }
public enum PlayerMessage { Walk, Run, Jump, Stop, Land }
// Create the state machine
var fsm = new EnumStateMachine<PlayerState, PlayerMessage>(PlayerState.Idle);
// Define transitions
fsm.Set(PlayerState.Idle, PlayerMessage.Walk, PlayerState.Walking);
fsm.Set(PlayerState.Idle, PlayerMessage.Run, PlayerState.Running);
fsm.Set(PlayerState.Idle, PlayerMessage.Jump, PlayerState.Jumping);
fsm.Set(PlayerState.Walking, PlayerMessage.Stop, PlayerState.Idle);
fsm.Set(PlayerState.Walking, PlayerMessage.Run, PlayerState.Running);
fsm.Set(PlayerState.Running, PlayerMessage.Stop, PlayerState.Idle);
fsm.Set(PlayerState.Jumping, PlayerMessage.Land, PlayerState.Idle);
// Subscribe to state changes
fsm.StateChangedEvent += (sender, args) =>
{
Console.WriteLine($"State changed from {args.OldState} to {args.NewState}");
};
// Send messages to trigger transitions
fsm.SendStateMessage("Walk"); // Transitions from Idle to Walking
fsm.SendStateMessage("Run"); // Transitions from Walking to Running
fsm.SendStateMessage("Stop"); // Transitions from Running to Idle
Using IntStateMachine (Performance-Optimized)
using StateMachineBuddy;
public enum GameState { Menu, Playing, Paused, GameOver }
public enum GameMessage { Start, Pause, Resume, Die, Restart }
var fsm = new IntStateMachine();
// Initialize with enum types
fsm.Set(typeof(GameState), typeof(GameMessage), (int)GameState.Menu);
// Define transitions using integer indices
fsm.SetEntry((int)GameState.Menu, (int)GameMessage.Start, (int)GameState.Playing);
fsm.SetEntry((int)GameState.Playing, (int)GameMessage.Pause, (int)GameState.Paused);
fsm.SetEntry((int)GameState.Playing, (int)GameMessage.Die, (int)GameState.GameOver);
fsm.SetEntry((int)GameState.Paused, (int)GameMessage.Resume, (int)GameState.Playing);
fsm.SetEntry((int)GameState.GameOver, (int)GameMessage.Restart, (int)GameState.Menu);
// Subscribe to state changes
fsm.StateChangedEvent += (sender, args) =>
{
Console.WriteLine($"Changed from {fsm.GetStateName(args.OldState)} to {fsm.GetStateName(args.NewState)}");
};
// Send messages
fsm.SendStateMessage((int)GameMessage.Start); // Menu -> Playing
Using StringStateMachine
using StateMachineBuddy;
var fsm = new StringStateMachine();
// Add states and messages
fsm.AddStates(new[] { "idle", "active", "complete" });
fsm.AddMessages(new[] { "activate", "finish", "reset" });
fsm.SetInitialState("idle");
// Define transitions
fsm.Set("idle", "activate", "active");
fsm.Set("active", "finish", "complete");
fsm.Set("complete", "reset", "idle");
// Subscribe to state changes
fsm.StateChangedEvent += (sender, args) =>
{
Console.WriteLine($"Changed from {args.OldState} to {args.NewState}");
};
// Send messages
fsm.SendStateMessage("activate"); // idle -> active
API Reference
IntStateMachine
High-performance state machine using integer indices internally stored in a 2D array.
Properties
| Property | Type | Description |
|---|---|---|
InitialState |
int |
The starting state index |
InitialStateName |
string |
Name of the initial state |
CurrentState |
int |
Current state index |
CurrentStateName |
string |
Name of current state |
PrevState |
int |
Previous state index |
NumStates |
int |
Total number of states |
NumMessages |
int |
Total number of messages |
StateNames |
string[] |
Array of state names |
MessageNames |
string[] |
Array of message names |
Events
| Event | Args Type | Description |
|---|---|---|
StateChangedEvent |
StateChangeEventArgs<int> |
Fired when state changes via message or force |
ResetEvent |
StateChangeEventArgs<int> |
Fired when ResetToInitialState() is called |
Initialization Methods
| Method | Description |
|---|---|
Set(int numStates, int numMessages, int initialState = 0) |
Initialize with counts and initial state |
Set(Type statesEnum, Type messagesEnum, int initialState = 0) |
Initialize from enum types |
SetEntry(int state, int message, int nextState) |
Define a transition |
SetEntry(int state, string messageName, string nextStateName) |
Define transition using names |
SetStateName(int state, string name) |
Set name for a state index |
SetMessageName(int message, string name) |
Set name for a message index |
SetNames(Type enumType, bool isStates) |
Set names from enum |
Resize(int numStates, int numMessages) |
Resize the state machine |
RemoveState(int state) |
Remove a state |
RemoveMessage(int message) |
Remove a message |
Runtime Methods
| Method | Returns | Description |
|---|---|---|
SendStateMessage(int message) |
bool |
Send message; returns true if state changed |
ForceState(int state) |
void |
Force transition to state |
ResetToInitialState() |
void |
Reset to initial state |
Lookup Methods
| Method | Returns | Description |
|---|---|---|
GetStateFromName(string name) |
int |
Get state index from name (-1 if not found) |
GetMessageFromName(string name) |
int |
Get message index from name (-1 if not found) |
GetStateName(int state) |
string |
Get state name from index |
GetMessageName(int message) |
string |
Get message name from index |
GetEntry(int state, int message) |
int |
Get target state for a transition |
Compare(IntStateMachine other) |
bool |
Check equality with another machine |
File I/O
| Method | Description |
|---|---|
LoadXml(Filename file, ContentManager content) |
Load from XML via MonoGame content pipeline |
StringStateMachine
Flexible state machine using string-based states and messages.
Properties
| Property | Type | Description |
|---|---|---|
InitialState |
string |
The starting state |
CurrentState |
string |
Current state |
PrevState |
string |
Previous state |
StateTable |
Dictionary<string, State> |
All states and their transitions |
Messages |
HashSet<string> |
All valid message names |
States |
HashSet<string> |
All valid state names |
Events
| Event | Args Type | Description |
|---|---|---|
StateChangedEvent |
StateChangeEventArgs<string> |
Fired when state changes |
ResetEvent |
StateChangeEventArgs<string> |
Fired on reset |
Initialization Methods
| Method | Description |
|---|---|
StringStateMachine() |
Default constructor |
StringStateMachine(StringStateMachine source) |
Copy constructor |
SetInitialState(string state) |
Set the initial state |
AddStates(IEnumerable<string> states) |
Add multiple states |
AddStates(Type statesEnum) |
Add states from enum |
AddMessages(IEnumerable<string> messages) |
Add multiple messages |
AddMessages(Type messagesEnum) |
Add messages from enum |
AddStateMachine(Type statesEnum, Type messagesEnum, string initialState) |
Full initialization from enums |
Set(string state, string message, string nextState) |
Define a transition |
Runtime Methods
| Method | Returns | Description |
|---|---|---|
SendStateMessage(string message) |
bool |
Send message; returns true if state changed |
ForceState(string state) |
void |
Force transition to state |
ResetToInitialState() |
void |
Reset to initial state |
File I/O
| Method | Description |
|---|---|
LoadXml(Filename file, ContentManager content) |
Load from XML |
LoadStateMachine(StateMachineModel model) |
Load from model object |
EnumStateMachine<TState, TMessage>
Type-safe wrapper around StringStateMachine for enum-based states and messages. Inherits from StringStateMachine.
Constructor
EnumStateMachine(TState initialState)
Methods
| Method | Description |
|---|---|
Set(TState state, TMessage message, TState nextState) |
Define a transition using enum values |
Inherits all properties, events, and methods from StringStateMachine. Use string versions of enum names when calling inherited methods like SendStateMessage("EnumValueName").
StateChangeEventArgs<T>
Event arguments passed to state change events.
| Property | Type | Description |
|---|---|---|
OldState |
T |
The previous state |
NewState |
T |
The new current state |
State
Internal class representing a state and its transitions.
| Property | Type | Description |
|---|---|---|
StateChanges |
Dictionary<string, string> |
Map of message → target state |
XML Configuration
State machines can be loaded from XML files using the MonoGame content pipeline.
XML Schema
<StateMachine initial="InitialStateName">
<states>
<state name="State1" />
<state name="State2" />
<state name="State3" />
</states>
<messages>
<message name="Message1" />
<message name="Message2" />
</messages>
<stateChanges>
<state name="State1">
<transitions>
<transition message="Message1" state="State2" />
<transition message="Message2" state="State3" />
</transitions>
</state>
<state name="State2">
<transitions>
<transition message="Message1" state="State3" />
</transitions>
</state>
</stateChanges>
</StateMachine>
Loading XML
var fsm = new StringStateMachine();
fsm.LoadXml(new Filename("path/to/statemachine.xml"), contentManager);
Model Classes
For programmatic construction or serialization:
StateMachineModel
| Property | Type | Description |
|---|---|---|
Initial |
string |
Initial state name |
StateNames |
List<string> |
All state names |
MessageNames |
List<string> |
All message names |
States |
List<StateModel> |
State transition definitions |
StateModel
| Property | Type | Description |
|---|---|---|
Name |
string |
State name |
Transitions |
List<StateChangeModel> |
Transitions from this state |
StateChangeModel
| Property | Type | Description |
|---|---|---|
Message |
string |
Message that triggers this transition |
TargetState |
string |
State to transition to |
Behavior Notes
No transition defined: If no transition exists for the current state + message combination,
SendStateMessagereturnsfalseand the state remains unchanged.Self-transitions ignored: If a transition would result in the same state, no state change occurs and
SendStateMessagereturnsfalse.ForceState: Bypasses the transition table and directly sets the state. Fires
StateChangedEventif the state actually changes.Invalid states/messages:
Set()throws exceptions if states or messages haven't been added first.Reset behavior:
ResetToInitialState()firesResetEventinstead ofStateChangedEvent.
Project Structure
StateMachineBuddy/
├── IntStateMachine.cs # Performance-optimized integer-based FSM
├── StringStateMachine.cs # Flexible string-based FSM
├── EnumStateMachine.cs # Type-safe enum wrapper
├── State.cs # State with transitions dictionary
├── StateChangeEventArgs.cs # Event args for state changes
└── Models/
├── StateMachineModel.cs # XML serialization model
├── StateModel.cs # State definition model
└── StateChangeModel.cs # Transition definition model
Repository
GitHub: https://github.com/dmanning23/StateMachine
License
MIT License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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. |
-
net8.0
- FilenameBuddy (>= 5.0.5)
- XmlBuddy (>= 5.0.0)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on StateMachineBuddy:
| Package | Downloads |
|---|---|
|
MenuBuddy
A complete MonoGame library for building menu systems and managing game state transitions |
|
|
FlashCards
MonoGame library for making little flashcard games |
|
|
MouseBuddy
A MonoGame component for doing simple mouse interaction |
|
|
GameDonkey
A simple MonoGame game engine for character-based games |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.0.5 | 28 | 1/27/2026 |
| 5.0.4 | 33 | 1/27/2026 |
| 5.0.3 | 34 | 1/26/2026 |
| 5.0.2 | 155 | 1/4/2026 |
| 5.0.1 | 103 | 1/4/2026 |
| 5.0.0 | 450 | 10/10/2025 |
| 4.0.0 | 1,180 | 10/24/2023 |
| 2.0.21 | 1,893 | 5/22/2020 |
| 2.0.20 | 1,833 | 3/6/2020 |
| 2.0.19 | 1,841 | 6/28/2019 |
| 2.0.18 | 1,800 | 5/14/2019 |
| 2.0.17 | 1,882 | 2/20/2019 |
| 2.0.16 | 1,841 | 2/19/2019 |
| 2.0.15 | 1,900 | 2/19/2019 |
| 2.0.14 | 1,806 | 2/19/2019 |
| 2.0.13 | 1,933 | 2/8/2019 |
| 2.0.12 | 1,841 | 2/5/2019 |
| 2.0.11 | 1,908 | 2/5/2019 |
| 2.0.10 | 1,856 | 2/5/2019 |
| 2.0.7 | 1,916 | 2/5/2019 |
| 2.0.6 | 1,874 | 2/2/2019 |
| 2.0.5 | 1,908 | 2/1/2019 |
| 2.0.4 | 1,827 | 2/1/2019 |
| 2.0.3 | 1,881 | 2/1/2019 |
| 2.0.1 | 1,911 | 2/1/2019 |
| 2.0.0 | 2,650 | 10/23/2018 |
| 1.0.12 | 2,570 | 3/1/2018 |
| 1.0.11 | 2,516 | 2/21/2018 |
| 1.0.10 | 2,523 | 1/24/2018 |
| 1.0.9 | 2,608 | 1/15/2018 |
| 1.0.8 | 2,532 | 1/15/2018 |
| 1.0.7 | 2,276 | 11/26/2017 |
| 1.0.6 | 2,323 | 11/26/2017 |
| 1.0.5 | 2,276 | 11/26/2017 |
| 1.0.4 | 2,345 | 11/23/2017 |
| 1.0.3 | 2,303 | 10/8/2017 |
| 1.0.2 | 2,265 | 10/3/2017 |
| 1.0.1 | 2,464 | 12/31/2016 |
| 1.0.0 | 2,784 | 4/25/2016 |