Announce: MarymoorStudios.Core.Fsm


MarymoorStudios.Core.Fsm is a new MSC library for defining finite state machines:

New C#-based language for defining FSMs

  • Declarative FSM definitions using a C# fluent builder pattern.
  • Input events are defined by methods signatures. Supports ad-hoc or interface-based input event definitions.
  • Simple [attribute] code-gen triggers. Generates state machine logic as nested classes within the user-defined class.
  • Roslyn integrated incremental code-gen works in Visual Studio, VS Code, or any msbuild toolchain.
  • Also generates Mermaid State Diagrams for visualization.

Support Hierarchical State Machines (HSM)

  • Like Statecharts or the State Pattern.
  • Nested states inherit event handling from their parent (composite) states which significantly reduces clutter and improves maintainability.
  • Nest states to any degree.
  • Support nested and global error handling to control transitions in the presence of errors.

Advanced State Machine Features

  • State transition validation.
  • OnEnter and OnExit events.
  • OnStart support for determining the starting state (of both the root machine and nested composites).
  • Deferred input event dispatching prevents event handler reentrancy. Post input signals from within an event handler without reentering or corrupting state transition validation.

Async Input Events

  • Define async Promise-based input events.
  • Automatically produces input signals when async inputs complete (success or error).
  • Automatic pending async input signal lifetime tracking with the ability to await on pending.
  • Support for IPromiseDisposable for HSMs with async inputs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  [HsmInput]
  public override void Process(double delta)
  {
    m_state.Process(this, delta);
  }
  
  [HsmInput]
  public void See(Character target)
  {
    m_state.See(this, target);
  }
  
  [HsmInput]
  public override void TakeDamage(int damage)
  {
    m_state.TakeDamage(this, damage);
  }
  
  [HsmStates]
  private static void StateMachine(HsmMeta<Enemy, Hsm,   State, Inputs> m, Inputs i, Enemy x)
  {
    m.Composite(State.Init,
      [
        m.Composite(State.Alive,
          [
            m.State(State.Stunned)
             .OnEnter(x.StunnedOnEnter)
             .OnExit(x.StunnedOnExit)
             .Edge(i.Process, x.StunnedProcess, State. Self,  State.History),
            m.State(State.Idle)
             .OnEnter(x.IdleOnEnter)
             .Edge(i.Process, x.IdleProcess, State.Self,   State.Patrol),
            m.State(State.Patrol)
             .OnEnter(x.PatrolOnEnter)
             .Edge(i.Process, x.PatrolProcess, State.Self,   State.Idle),
            m.State(State.Attack)
             .OnEnter(x.AttackOnEnter)
             .Edge(i.Process, x.AttackProcess, State.Self,   State.Idle),
          ])
         .OnStart(State.Idle)
         .Edge(i.See, x.AliveSee, State.Self, State.Attack)
         .Edge(i.TakeDamage, x.AliveTakeDamage, State. Dead,  State.Stunned),
        m.State(State.Dead)
         .OnEnter(x.DeadOnEnter)
         .Edge(i.Process, x.DeadProcess),
      ])
     .OnStart(State.Alive);
  }

Previous

Read the previous post in this series.

Next

Read the next post in this series.

Feedback

Write us with feedback.

See Also