Trigger reentry into a superstate from within a substate

303 views
Skip to first unread message

Arun Mehta

unread,
Feb 17, 2015, 12:47:48 AM2/17/15
to dotnet-state-ma...@googlegroups.com
First, thanks for your great stateless framework, Nicholas!

I have a quick question: in my state-machine I have a superstate S ("battle phase") with three sub-states, A, B, and C.  I want to be able to reenter S from within C, but when I call the trigger T from within C, it seems to exit 'back' into S but does not call S.OnExit / S.OnEnter unless I fire T a second time (seems like I'm doing something wrong...) The configuration is below:

// configure "prebattle" state
BattleSM.Configure(FSM.Battle.PreBattle.Instance)
.OnEntry( () => FSM.Battle.PreBattle.Instance.Entering(BattleSM) )
.OnExit( () => FSM.Battle.PreBattle.Instance.Exiting(BattleSM) )
.Permit(BattleFSMTrigger.StartPhase, FSM.Battle.BattlePhase.Instance);

// configure "thinking" state (sub-state of BattlePhase)
BattleSM.Configure(FSM.Battle.Thinking.Instance)
.OnEntry( () => FSM.Battle.Thinking.Instance.Entering(BattleSM) )
.OnExit( () => FSM.Battle.Thinking.Instance.Exiting(BattleSM) )
.Permit(BattleFSMTrigger.StartMoving, FSM.Battle.Moving.Instance)
.SubstateOf(FSM.Battle.BattlePhase.Instance);

// configure "moving" state (sub-state of BattlePhase)
BattleSM.Configure(FSM.Battle.Moving.Instance)
.OnEntry( () => FSM.Battle.Moving.Instance.Entering(BattleSM) )
.OnExit( () => FSM.Battle.Moving.Instance.Exiting(BattleSM) )
.Permit(BattleFSMTrigger.StopMoving, FSM.Battle.DoAction.Instance)
.SubstateOf(FSM.Battle.BattlePhase.Instance);

// configure "do action" state (sub-state of BattlePhase)
BattleSM.Configure(FSM.Battle.DoAction.Instance)
.OnEntry( () => FSM.Battle.DoAction.Instance.Entering(BattleSM) )
.OnExit( () => FSM.Battle.DoAction.Instance.Exiting(BattleSM) )
.Permit(BattleFSMTrigger.NextTurn, FSM.Battle.Thinking.Instance )
.Permit(BattleFSMTrigger.EndBattle, FSM.Battle.BattleDone.Instance)
.SubstateOf(FSM.Battle.BattlePhase.Instance);

// configure "battle phase" super-state
BattleSM.Configure(FSM.Battle.BattlePhase.Instance)
.OnEntry( () => FSM.Battle.BattlePhase.Instance.Entering(BattleSM) )
.OnExit( () => FSM.Battle.BattlePhase.Instance.Exiting(BattleSM) )
.Permit(BattleFSMTrigger.NextTurn, FSM.Battle.Thinking.Instance )
.PermitReentry(BattleFSMTrigger.StartPhase);

// configure "battle done" state
BattleSM.Configure(FSM.Battle.BattleDone.Instance)
.OnEntry( () => FSM.Battle.BattleDone.Instance.Entering(BattleSM) )
.OnExit( () => FSM.Battle.BattleDone.Instance.Exiting(BattleSM) );

I'm trying to attach a diagram (.png format) of my state-machine as well.

Cheers,
-Arun
StateMachine_Arun.png

nblumhardt

unread,
Feb 17, 2015, 5:03:32 PM2/17/15
to dotnet-state-ma...@googlegroups.com
Hi Arun,

Thanks for the mail!

IIRC (it's been a long time) reentry won't occur when moving between substates of the same superstate. I'm not sure why hitting the trigger twice would have this behaviour, it's possible there's a bug or some form of regression at play.

Sorry to not have some more specific feedback - if you can nail it down to a failing test/patch, PRs on the github project are appreciated.

Cheers,
Nick

Grant BlahaErath

unread,
Feb 17, 2015, 5:15:32 PM2/17/15
to dotnet-state-ma...@googlegroups.com

If you are calling fire inside the transition handler its a recursive call. The onexit call never happens because the transition handler never exits.  Eventually you rub out of stack space.

In a similar situation I used a queue to store the triggers and looped Fire until the queue was empty.

--

---
You received this message because you are subscribed to the Google Groups "Stateless .NET State Machine Framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dotnet-state-machine-...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Arun Mehta

unread,
Feb 17, 2015, 9:47:42 PM2/17/15
to dotnet-state-ma...@googlegroups.com
Thanks for the replies, guys!

@Grant: I read similar advice elsewhere in the forum and am following your approach for triggers that I want to fire within OnEnter/OnExit.  I'm using Unity (which is single-threaded for normal script logic, afaik) and I execute all triggers that exist in a queue (FILO) in the main Update loop of my game logic once a frame.

@Nicholas: In this case I am explicitly trying to reenter the superstate from a substate; transitions between substates correctly do not trigger reentry of the superstate.  Hitting the trigger once seems to take me out of the substate and *exclusively* into the superstate, at which point firing again correctly triggers reentry into the superstate (calling machine.IsInState for the sub and super states before the 1st and 2nd firing of the "StartPhase" trigger confirms this). Perhaps this use-case isn't common, and the behavior is correct?  Put another way, given my diagram above, which state configuration should specify the reentry transition?

The substate:
  BattleSM.Configure(FSM.Battle.DoAction.Instance)
  ....
  .Permit(BattleFSMTrigger.StartPhase, FSM.Battle.BattlePhase.Instance) // This line (A)
  .SubstateOf(FSM.Battle.BattlePhase.Instance);

or the superstate:

  BattleSM.Configure(FSM.Battle.BattlePhase.Instance)
  ....
  .PermitReentry(BattleFSMTrigger.StartPhase); // This line (B)

or both? Note that the 'StartPhase' trigger is correctly recognized in the DoAction state *without* line A so long as line B is included.

Sorry if this isn't clarifying the issue at all, I'll post any results of a deeper investigation.

Thanks,
Arun


To unsubscribe from this group and stop receiving emails from it, send an email to dotnet-state-machine-framework+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages