Files
StrawberryBF/src/Components/Logic/StateMachine.bf

130 lines
2.3 KiB
Beef
Raw Normal View History

2020-05-26 21:23:46 -07:00
using System;
using System.Collections;
2020-05-30 16:19:46 -07:00
using System.Diagnostics;
2020-05-26 21:23:46 -07:00
namespace Strawberry
{
public class StateMachine<TIndex> : Component where TIndex : struct, IHashable
{
private Dictionary<TIndex, State> states = new Dictionary<TIndex, State>() ~ delete _;
private TIndex state;
private bool inStateCall;
public TIndex PreviousState { get; private set; }
public TIndex NextState { get; private set; }
public this(TIndex startState)
: base(true, false)
{
NextState = PreviousState = state = startState;
}
public ~this()
{
for (let s in states.Values)
delete s;
}
public override void Started()
{
CallEnter();
}
public override void Update()
{
CallUpdate();
}
public override void Draw()
{
}
public void Add(TIndex state, delegate void() enter = null, delegate TIndex() update = null, delegate void() exit = null)
2020-05-26 21:23:46 -07:00
{
let s = new State();
s.Enter = enter;
s.Update = update;
s.Exit = exit;
states[state] = s;
}
public TIndex State
{
get => state;
set => Set(value);
}
private Result<bool> Set(TIndex to)
{
2020-05-30 16:19:46 -07:00
Debug.Assert(states.ContainsKey(to), "State does not exist in this State Machine. Call Add() first!");
Runtime.Assert(!inStateCall, "Cannot set State directly from inside a State Enter/Exit/Update call. Return the desired State change instead.");
2020-05-26 21:23:46 -07:00
if (to != state)
{
NextState = to;
CallExit();
2020-05-26 21:23:46 -07:00
PreviousState = state;
state = to;
CallEnter();
return true;
}
else
return false;
}
private void CallEnter()
2020-05-26 21:23:46 -07:00
{
let s = states[state];
2020-05-26 22:23:02 -07:00
if (s != null && s.Enter != null)
2020-05-26 21:23:46 -07:00
{
inStateCall = true;
s.Enter();
2020-05-26 21:23:46 -07:00
inStateCall = false;
}
}
private bool CallUpdate()
{
let s = states[state];
2020-05-26 22:23:02 -07:00
if (s != null && s.Update != null)
2020-05-26 21:23:46 -07:00
{
inStateCall = true;
let set = s.Update();
inStateCall = false;
return Set(set);
}
else
return false;
}
private void CallExit()
2020-05-26 21:23:46 -07:00
{
let s = states[state];
2020-05-26 22:23:02 -07:00
if (s != null && s.Exit != null)
2020-05-26 21:23:46 -07:00
{
inStateCall = true;
s.Exit();
2020-05-26 21:23:46 -07:00
inStateCall = false;
}
}
public class State
{
public delegate void() Enter;
2020-05-26 21:23:46 -07:00
public delegate TIndex() Update;
public delegate void() Exit;
2020-05-26 21:23:46 -07:00
public ~this()
{
if (Enter != null)
delete Enter;
if (Update != null)
delete Update;
if (Exit != null)
delete Exit;
}
}
}
}