Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some fixes and new features #9

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/Base/IStateMachine.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

using System.Collections.Generic;

namespace FSM
{
public interface IStateMachine : IState
{
IReadOnlyList<IState> States { get; }
}

/// <summary>
/// A subset of features that every parent state machine has to provide.
/// It is useful, as it allows the parent state machine to be independent from the
Expand All @@ -9,7 +16,7 @@ namespace FSM
/// => An abstraction layer
/// </summary>
/// <typeparam name="TStateId">They type of the names / ids of the sub states</typeparam>
public interface IStateMachine<TStateId>
public interface IStateMachine<TStateId> : IStateMachine
{
/// <summary>
/// Tells the state machine that, if there is a state transition pending,
Expand All @@ -21,5 +28,6 @@ public interface IStateMachine<TStateId>

StateBase<TStateId> ActiveState { get; }
TStateId ActiveStateName { get; }
TStateId PrevStateName { get; }
}
}
50 changes: 49 additions & 1 deletion src/Base/StateBase.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
using System;
using System.Collections.Generic;
using UnityEngine;

namespace FSM
{
public interface IState
{

}

/// <summary>
/// The base class of all states
/// </summary>
public class StateBase<TStateId>
public class StateBase<TStateId> : IState
{
public bool needsExitTime;
public TStateId name;

public IStateMachine<TStateId> fsm;

private Dictionary<Type, Delegate> commandHandlers;

/// <summary>
/// Initialises a new instance of the BaseState class
/// </summary>
Expand Down Expand Up @@ -46,6 +55,45 @@ public virtual void OnLogic() {

}

/// <summary>
/// Set command handler
/// </summary>
/// <param name="handler">Handler delegate</param>
/// <typeparam name="TCommand">Type of command</typeparam>
protected void SetCommandHandler<TCommand>(Action<TCommand> handler)
{
if (commandHandlers == null)
{
commandHandlers = new Dictionary<Type, Delegate>();
}

commandHandlers[typeof(TCommand)] = handler;
}

protected bool CanProcessCommand<TCommand>()
{
if (commandHandlers != null)
{
commandHandlers.TryGetValue(typeof(TCommand), out var commandHandler);
return commandHandler is Action<TCommand>;
}
return false;
}

/// <summary>
/// Called when state is active and fsm was call OnCommand
/// </summary>
/// <param name="command"></param>
/// <typeparam name="TCommand"></typeparam>
public virtual void OnCommand<TCommand>(TCommand command = default)
{
if (commandHandlers != null)
{
commandHandlers.TryGetValue(typeof(TCommand), out var commandHandler);
(commandHandler as Action<TCommand>)?.Invoke(command);
}
}

/// <summary>
/// Called when the state machine transitions from this state to another state (exits this state)
/// </summary>
Expand Down
16 changes: 13 additions & 3 deletions src/HybridStateMachine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using UnityEngine;
using System;
using System.Collections.Generic;

namespace FSM
{
Expand Down Expand Up @@ -33,11 +34,17 @@ public class HybridStateMachine<TOwnId, TStateId, TEvent> : StateMachine<TOwnId,
/// Determins whether the state machine as a state of a parent state machine is allowed to instantly
/// exit on a transition (false), or if it should wait until the active state is ready for a
/// state change (true).</param>
/// <param name="stateIdComparer">Comparer which will be used for lookup by state id.
/// Recommended for struct typed TStateId or custom lookup logic.</param>
/// <param name="eventComparer">Comparer which will be used for lookup by event.
/// Recommended for struct typed TEvent or custom lookup logic.</param>
public HybridStateMachine(
Action<HybridStateMachine<TOwnId, TStateId, TEvent>> onEnter = null,
Action<HybridStateMachine<TOwnId, TStateId, TEvent>> onLogic = null,
Action<HybridStateMachine<TOwnId, TStateId, TEvent>> onExit = null,
bool needsExitTime = false) : base(needsExitTime)
bool needsExitTime = false,
IEqualityComparer<TStateId> stateIdComparer = null,
IEqualityComparer<TEvent> eventComparer = null) : base(needsExitTime, stateIdComparer, eventComparer)
{
this.onEnter = onEnter;
this.onLogic = onLogic;
Expand Down Expand Up @@ -76,7 +83,9 @@ public HybridStateMachine(
Action<HybridStateMachine<TStateId, TStateId, TEvent>> onEnter = null,
Action<HybridStateMachine<TStateId, TStateId, TEvent>> onLogic = null,
Action<HybridStateMachine<TStateId, TStateId, TEvent>> onExit = null,
bool needsExitTime = false) : base(onEnter, onLogic, onExit, needsExitTime)
bool needsExitTime = false,
IEqualityComparer<TStateId> stateIdComparer = null,
IEqualityComparer<TEvent> eventComparer = null) : base(onEnter, onLogic, onExit, needsExitTime, stateIdComparer, eventComparer)
{
}
}
Expand All @@ -87,7 +96,8 @@ public HybridStateMachine(
Action<HybridStateMachine<TStateId, TStateId, string>> onEnter = null,
Action<HybridStateMachine<TStateId, TStateId, string>> onLogic = null,
Action<HybridStateMachine<TStateId, TStateId, string>> onExit = null,
bool needsExitTime = false) : base(onEnter, onLogic, onExit, needsExitTime)
bool needsExitTime = false,
IEqualityComparer<TStateId> stateIdComparer = null) : base(onEnter, onLogic, onExit, needsExitTime, stateIdComparer)
{
}
}
Expand Down
20 changes: 18 additions & 2 deletions src/State.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,36 @@ public class State<TStateId> : StateBase<TStateId>
/// <param name="needsExitTime">Determins if the state is allowed to instantly
/// exit on a transition (false), or if the state machine should wait until the state is ready for a
/// state change (true)</param>
/// <param name="commands">Commands which will be registered for OnCommand calls</param>
public State(
Action<State<TStateId>> onEnter = null,
Action<State<TStateId>> onLogic = null,
Action<State<TStateId>> onExit = null,
Func<State<TStateId>, bool> canExit = null,
bool needsExitTime = false) : base(needsExitTime)
bool needsExitTime = false,
params CommandBase<TStateId>[] commands) : base(needsExitTime)
{
this.onEnter = onEnter;
this.onLogic = onLogic;
this.onExit = onExit;
this.canExit = canExit;

if (commands != null)
{
foreach (var command in commands)
{
command?.Register(this);
}
}

this.timer = new Timer();
}

internal void SetCommandHandlerInternal<TCommand>(Action<TCommand> handler)
{
SetCommandHandler(handler);
}

public override void OnEnter()
{
timer.Reset();
Expand Down Expand Up @@ -76,7 +91,8 @@ public State(
Action<State<string>> onLogic = null,
Action<State<string>> onExit = null,
Func<State<string>, bool> canExit = null,
bool needsExitTime = false) : base(onEnter, onLogic, onExit, canExit, needsExitTime)
bool needsExitTime = false,
params CommandBase<string>[] commands) : base(onEnter, onLogic, onExit, canExit, needsExitTime, commands)
{
}
}
Expand Down
Loading