Skip to content

Instantly share code, notes, and snippets.

@fanhexin
Last active May 31, 2020 12:26
Show Gist options
  • Save fanhexin/e25244781de09daa51e6104e00186081 to your computer and use it in GitHub Desktop.
Save fanhexin/e25244781de09daa51e6104e00186081 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
namespace Game.Util
{
public class FluentFsm<TState, TEvent>
where TState : Enum
where TEvent : Enum
{
readonly Dictionary<TState, State> _states = new Dictionary<TState, State>();
readonly Dictionary<TEvent, TState> _anyStateTransitions = new Dictionary<TEvent, TState>();
public TState CurState { get; private set; }
public FluentFsm(TState defaultState)
{
CurState = defaultState;
}
public TransitionBuilder<FluentFsm<TState, TEvent>> When(TEvent ev)
{
return new TransitionBuilder<FluentFsm<TState, TEvent>>(this, ev, _anyStateTransitions);
}
public StateBuilder Define(TState state)
{
var s = new State();
_states[state] = s;
return new StateBuilder(s);
}
public void Fire(TEvent ev)
{
if (_anyStateTransitions.TryGetValue(ev, out TState state))
{
ToState(state);
return;
}
State curState = _states[CurState];
if (curState.Transitions == null)
{
return;
}
if (!curState.Transitions.TryGetValue(ev, out state))
{
return;
}
ToState(state);
}
public void Update()
{
_states[CurState].OnUpdate?.Invoke();
}
void ToState(TState state)
{
State curState = _states[CurState];
curState.OnExit?.Invoke();
CurState = state;
curState = _states[CurState];
curState.OnEnter?.Invoke();
}
public struct StateBuilder
{
private readonly State _state;
public StateBuilder(State state)
{
_state = state;
}
public StateBuilder OnEnter(Action onEnter)
{
_state.OnEnter = onEnter;
return this;
}
public StateBuilder OnExit(Action onExit)
{
_state.OnExit = onExit;
return this;
}
public StateBuilder OnUpdate(Action onUpdate)
{
_state.OnUpdate = onUpdate;
return this;
}
public TransitionBuilder<StateBuilder> When(TEvent ev)
{
if (_state.Transitions == null)
{
_state.Transitions = new Dictionary<TEvent, TState>();
}
return new TransitionBuilder<StateBuilder>(this, ev, _state.Transitions);
}
}
public struct TransitionBuilder <T>
{
private readonly TEvent _ev;
private readonly Dictionary<TEvent, TState> _transitions;
private readonly T _returnInstance;
public TransitionBuilder(T returnInstance, TEvent ev, Dictionary<TEvent, TState> transitions)
{
_ev = ev;
_transitions = transitions;
_returnInstance = returnInstance;
}
public T To(TState state)
{
_transitions[_ev] = state;
return _returnInstance;
}
}
public class State
{
public Action OnEnter;
public Action OnExit;
public Action OnUpdate;
public Dictionary<TEvent, TState> Transitions;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment