Module Fsm

This module contains the FSM (Finite State Machine) class and derived FSM_ classes.

Finite State Machines (FSM) are design patterns allowing efficient (long-lasting) processes and workflows.

A FSM can only be in one of a finite number of states. The machine is in only one state at a time; the state it is in at any given time is called the current state. It can change from one state to another when initiated by an internal or external triggering event, which is called a transition. An FSM implementation is defined by a list of its states, its initial state, and the triggering events for each possible transition. An FSM implementation is composed out of two parts, a set of state transition rules, and an implementation set of state transition handlers, implementing those transitions.

The FSM class supports a hierarchical implementation of a Finite Stae Machine, that is, it allows to embed existing FSM implementations in a master FSM. FSM hierarchies allow for efficient FSM re-use, not having to re-invent the wheel every time again when designing complex processes.

Examples of ready made FSMs could be:

  • route a plane to a zone flown by a human
  • detect targets by an AI and report to humans
  • account for destroyed targets by human players
  • handle AI infantry to deploy from or embark to a helicopter or airplane or vehicle
  • let an AI patrol a zone

The MOOSE framework uses extensively the FSM class and derived FSM_ classes, because the goal of MOOSE is to simplify the mission design complexity for mission builders. By efficiently utilizing the FSM class, MOOSE allows mission designers to quickly build processes, that can be re-used or tailored at various places within their mission designs for various objects and purposes. Ready made FSM-based implementations classes exist within the MOOSE framework that can easily be re-used, extended and/or modified by mission builders through the implementation of the event handlers. Each of these FSM implementation classes start either with:

  • an acronym AI_, which indicates an FSM implementation directing AI controlled GROUP and/or UNIT.
  • an acronym TASK_, which indicates an FSM implementation executing a TASK executed by Groups of players.
  • an acronym ACT_, which indicates an FSM implementation directing Humans actions that need to be done in a TASK, seated in a CLIENT (slot) or a UNIT (CA join).

MOOSE contains 3 different types of FSM class types, which govern processes for specific objects or purposes:

  • FSM class: Governs a generic process.
  • FSM_CONTROLLABLE: Governs a process for a CONTROLLABLE, which is executed by AI GROUP, UNIT or CLIENT objects.
  • FSM_TASK: Governs a process for a TASK, which is executed by groups of players.
  • FSM_CLIENT: Governs a process for a TASK, executed by **ONE player seated in a CLIENT**.

Detailed explanations and API specifics are further below clarified.

Dislaimer:

The FSM class development is based on a finite state machine implementation made by Conroy Kyle. The state machine can be found on github I've reworked this development (taken the concept), and created a hierarchical state machine out of it, embedded within the DCS simulator. Additionally, I've added extendability and created an API that allows seamless FSM implementation.


Banner Image

1) Core.Fsm#FSM class, extends Core.Base#BASE

1.1) Event Handling

Event Handlers

An FSM transitions in 4 moments when an Event is being handled.
Each moment can be catched by handling methods defined by the mission designer,
that will be called by the FSM while executing the transition.
These methods define the flow of the FSM process; because in those methods the FSM Internal Events will be fired.

  • To handle State moments, create methods starting with OnLeave or OnEnter concatenated with the State name.
  • To handle Event moments, create methods starting with OnBefore or OnAfter concatenated with the Event name.

The OnLeave and OnBefore transition methods may return false, which will cancel the transition.

1.2) Event Triggers

Event Triggers

The FSM creates for each Event two Event Trigger methods.
There are two modes how Events can be triggered, which is embedded and delayed:

  • The method FSM:Event() triggers an Event that will be processed embedded or immediately.
  • The method FSM:__Event( seconds ) triggers an Event that will be processed delayed over time, waiting x seconds.

1.3) FSM Transition Rules

The FSM has transition rules that it follows and validates, as it walks the process. These rules define when an FSM can transition from a specific state towards an other specific state upon a triggered event.

The method FSM.AddTransition() specifies a new possible Transition Rule for the FSM.

The initial state can be defined using the method FSM.SetStartState(). The default start state of an FSM is "None".

Example

This example creates a new FsmDemo object from class FSM. It will set the start state of FsmDemo to Green. 2 Transition Rules are created, where upon the event Switch, the FsmDemo will transition from state Green to Red and vise versa.

 local FsmDemo = FSM:New() -- #FsmDemo
 FsmDemo:SetStartState( "Green" )
 FsmDemo:AddTransition( "Green", "Switch", "Red" )
 FsmDemo:AddTransition( "Red", "Switch", "Green" )

In the above example, the FsmDemo could flare every 5 seconds a Green or a Red flare into the air. The next code implements this through the event handling method OnAfterSwitch.

 function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit )
   self:E( { From, Event, To, FsmUnit } )

   if From == "Green" then
     FsmUnit:Flare(FLARECOLOR.Green)
   else
     if From == "Red" then
       FsmUnit:Flare(FLARECOLOR.Red)
     end
   end
   FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds.
 end

 FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the first Switch event to happen in 5 seconds.

The OnAfterSwitch implements a loop. The last line of the code fragment triggers the Switch Event within 5 seconds. Upon the event execution (after 5 seconds), the OnAfterSwitch method is called of FsmDemo (cfr. the double point notation!!! ":"). The OnAfterSwitch method receives from the FSM the 3 transition parameter details ( From, Event, To ), and one additional parameter that was given when the event was triggered, which is in this case the Unit that is used within OnSwitchAfter.

 function FsmDemo:OnAfterSwitch( From, Event, To, FsmUnit )

For debugging reasons the received parameters are traced within the DCS.log.

    self:E( { From, Event, To, FsmUnit } )

The method will check if the From state received is either "Green" or "Red" and will flare the respective color from the FsmUnit.

   if From == "Green" then
     FsmUnit:Flare(FLARECOLOR.Green)
   else
     if From == "Red" then
       FsmUnit:Flare(FLARECOLOR.Red)
     end
   end

It is important that the Switch event is again triggered, otherwise, the FsmDemo would stop working after having the first Event being handled.

   FsmDemo:__Switch( 5, FsmUnit ) -- Trigger the next Switch event to happen in 5 seconds.

This example is fully implemented in the MOOSE test mission on GITHUB: FSM-100 - Transition Explanation

Some additional comments:

Note that transition rules can be declared with a few variations:

  • The From states can be a table of strings, indicating that the transition rule will be valid if the current state of the FSM will be one of the given From states.
  • The From state can be a "*", indicating that the transition rule will always be valid, regardless of the current state of the FSM.

This transition will create a new FsmDemo object from class FSM. It will set the start state of FsmDemo to Green. A new event is added in addition to the above example. The new event Stop will cancel the Switching process. So, the transtion for event Stop can be executed if the current state of the FSM is either "Red" or "Green".

 local FsmDemo = FSM:New() -- #FsmDemo
 FsmDemo:SetStartState( "Green" )
 FsmDemo:AddTransition( "Green", "Switch", "Red" )
 FsmDemo:AddTransition( "Red", "Switch", "Green" )
 FsmDemo:AddTransition( { "Red", "Green" }, "Stop", "Stopped" )

The transition for event Stop can also be simplified, as any current state of the FSM is valid.

 FsmDemo:AddTransition( "*", "Stop", "Stopped" )

1.4) FSM Process Rules

The FSM can implement sub-processes that will execute and return multiple possible states.
Depending upon which state is returned, the main FSM can continue tiggering different events.

The method FSM.AddProcess() adds a new Sub-Process FSM to the FSM.
A Sub-Process will start the Sub-Process of the FSM upon the defined triggered Event, with multiple possible States as a result.


API CHANGE HISTORY

The underlying change log documents the API changes. Please read this carefully. The following notation is used:

  • Added parts are expressed in bold type face.
  • Removed parts are expressed in italic type face.

YYYY-MM-DD: CLASS:NewFunction( Params ) replaces CLASS:OldFunction( Params ) YYYY-MM-DD: CLASS:NewFunction( Params ) added

Hereby the change log:

  • 2016-12-18: Released.

AUTHORS and CONTRIBUTIONS

Contributions:

  • None.

Authors:

  • FlightControl: Design & Programming

Global(s)

FSM
FSM_CONTROLLABLE
FSM_PROCESS
FSM_SET
FSM_TASK

Type FSM

FSM:AddEndState(State)

Adds an End state.

FSM:AddProcess(From, Event, Process, ReturnEvents)

Set the default Process template with key ProcessName providing the ProcessClass and the process object when it is assigned to a Controllable by the task.

FSM:AddScore(State, ScoreText, Score)

Adds a score for the FSM to be achieved.

FSM:AddScoreProcess(From, Event, State, ScoreText, Score)

Adds a score for the FSM_PROCESS to be achieved.

FSM:AddTransition(From, Event, To)

Add a new transition rule to the FSM.

FSM.ClassName
FSM:GetEndStates()

Returns the End states.

FSM:GetProcess(From, Event)
FSM:GetProcesses()

Returns a table of the SubFSM rules defined within the FSM.

FSM:GetScores()

Returns a table with the scores defined.

FSM:GetStartState()

Returns the start state of the FSM.

FSM:GetState()
FSM:GetSubs()

Returns a table with the Subs defined.

FSM:GetTransitions()

Returns a table of the transition rules defined within the FSM.

FSM:Is(State)
FSM:LoadCallBacks(CallBackTable)
FSM:New(FsmT)

Creates a new FSM object.

FSM:SetStartState(State)

Sets the start state of the FSM.

FSM._StartState
FSM:_add_to_map(Map, Event)
FSM:_call_handler(handler, params)
FSM:_create_transition(EventName)
FSM:_delayed_transition(EventName)
FSM:_eventmap(Events, EventStructure)
FSM:_gosub(ParentFrom, ParentEvent)
FSM:_handler(EventName, ...)
FSM:_isendstate(Current)
FSM:_submap(subs, sub, name)
FSM:can(e)
FSM:cannot(e)
FSM.current
FSM:is(state)

Type FSM_CONTROLLABLE

FSM_CONTROLLABLE.ClassName
FSM_CONTROLLABLE.Controllable
FSM_CONTROLLABLE:GetControllable()

Gets the CONTROLLABLE object that the FSM_CONTROLLABLE governs.

FSM_CONTROLLABLE:New(FSMT, Controllable)

Creates a new FSM_CONTROLLABLE object.

FSM_CONTROLLABLE:SetControllable(FSMControllable)

Sets the CONTROLLABLE object that the FSM_CONTROLLABLE governs.

FSM_CONTROLLABLE:_call_handler(handler, params)

Type FSM_PROCESS

FSM_PROCESS:AddScore(State, ScoreText, Score)

Adds a score for the FSM_PROCESS to be achieved.

FSM_PROCESS:Assign(Task, ProcessUnit)

Assign the process to a Unit and activate the process.

FSM_PROCESS.ClassName
FSM_PROCESS:Copy(Controllable, Task)

Creates a new FSMPROCESS object based on this FSMPROCESS.

FSM_PROCESS:GetCommandCenter()

Gets the mission of the process.

FSM_PROCESS:GetMission()

Gets the mission of the process.

FSM_PROCESS:GetTask()

Gets the task of the process.

FSM_PROCESS:Init(FsmProcess)
FSM_PROCESS:Message(Message)

Send a message of the Task to the Group of the Unit.

FSM_PROCESS:New(Controllable, Task)

Creates a new FSM_PROCESS object.

FSM_PROCESS:SetTask(Task)

Sets the task of the process.

FSM_PROCESS.Task
FSM_PROCESS:onenterAssigned(ProcessUnit)
FSM_PROCESS:onenterFailed(ProcessUnit)
FSM_PROCESS:onenterSuccess(ProcessUnit)
FSM_PROCESS:onstatechange(ProcessUnit, Event, From, To, Dummy)

StateMachine callback function for a FSM_PROCESS

Type FSM_SET

FSM_SET.ClassName
FSM_SET:Get()

Gets the SETBASE object that the FSMSET governs.

FSM_SET:New(FSMT, Set_SET_BASE, FSMSet)

Creates a new FSM_SET object.

FSM_SET.Set
FSM_SET:_call_handler(handler, params)

Type FSM_TASK

FSM_TASK.ClassName
FSM_TASK:New(FSMT, Task, TaskUnit)

Creates a new FSM_TASK object.

FSM_TASK.Task
FSM_TASK:_call_handler(handler, params)

Global(s)

#FSM FSM
#FSM_CONTROLLABLE FSM_CONTROLLABLE
#FSM_PROCESS FSM_PROCESS
#FSM_SET FSM_SET
#FSM_TASK FSM_TASK

Type Fsm

Type FSM

FSM class

Field(s)

FSM:AddEndState(State)

Adds an End state.

Parameter

  • State :

FSM:AddProcess(From, Event, Process, ReturnEvents)

Set the default Process template with key ProcessName providing the ProcessClass and the process object when it is assigned to a Controllable by the task.

Parameters

  • #table From : Can contain a string indicating the From state or a table of strings containing multiple From states.

  • #string Event : The Event name.

  • Core.Fsm#FSM_PROCESS Process : An sub-process FSM.

  • #table ReturnEvents : A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.

Return value

Core.Fsm#FSM_PROCESS: The SubFSM.

FSM:AddScore(State, ScoreText, Score)

Adds a score for the FSM to be achieved.

Parameters

  • #string State : is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).

  • #string ScoreText : is a text describing the score that is given according the status.

  • #number Score : is a number providing the score of the status.

Return value

#FSM: self

FSM:AddScoreProcess(From, Event, State, ScoreText, Score)

Adds a score for the FSM_PROCESS to be achieved.

Parameters

  • #string From : is the From State of the main process.

  • #string Event : is the Event of the main process.

  • #string State : is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).

  • #string ScoreText : is a text describing the score that is given according the status.

  • #number Score : is a number providing the score of the status.

Return value

#FSM: self

FSM:AddTransition(From, Event, To)

Add a new transition rule to the FSM.

A transition rule defines when and if the FSM can transition from a state towards another state upon a triggered event.

Parameters

  • #table From : Can contain a string indicating the From state or a table of strings containing multiple From states.

  • #string Event : The Event name.

  • #string To : The To state.

#string FSM.ClassName
FSM:GetEndStates()

Returns the End states.

FSM:GetProcess(From, Event)

Parameters

  • From :

  • Event :

FSM:GetProcesses()

Returns a table of the SubFSM rules defined within the FSM.

Return value

#table:

FSM:GetScores()

Returns a table with the scores defined.

FSM:GetStartState()

Returns the start state of the FSM.

Return value

#string: A string containing the start state.

FSM:GetState()
FSM:GetSubs()

Returns a table with the Subs defined.

FSM:GetTransitions()

Returns a table of the transition rules defined within the FSM.

Return value

#table:

FSM:Is(State)

Parameter

  • State :

FSM:LoadCallBacks(CallBackTable)

Parameter

  • CallBackTable :

FSM:New(FsmT)

Creates a new FSM object.

Parameter

  • FsmT :

Return value

#FSM:

FSM:SetStartState(State)

Sets the start state of the FSM.

Parameter

  • #string State : A string defining the start state.

FSM._StartState
FSM:_add_to_map(Map, Event)

Parameters

  • Map :

  • Event :

FSM:_call_handler(handler, params)

Parameters

  • handler :

  • params :

FSM:_create_transition(EventName)

Parameter

  • EventName :

FSM:_delayed_transition(EventName)

Parameter

  • EventName :

FSM:_eventmap(Events, EventStructure)

Parameters

  • Events :

  • EventStructure :

FSM:_gosub(ParentFrom, ParentEvent)

Parameters

  • ParentFrom :

  • ParentEvent :

FSM:_handler(EventName, ...)

Parameters

  • EventName :

  • ... :

FSM:_isendstate(Current)

Parameter

  • Current :

FSM:_submap(subs, sub, name)

Parameters

  • subs :

  • sub :

  • name :

FSM:can(e)

Parameter

  • e :

FSM:cannot(e)

Parameter

  • e :

FSM.current
FSM:is(state)

Parameter

  • state :

Type FSM_CONTROLLABLE

FSM_CONTROLLABLE class

Field(s)

#string FSM_CONTROLLABLE.ClassName
Wrapper.Controllable#CONTROLLABLE FSM_CONTROLLABLE.Controllable
FSM_CONTROLLABLE:GetControllable()

Gets the CONTROLLABLE object that the FSM_CONTROLLABLE governs.

Return value

Wrapper.Controllable#CONTROLLABLE:

FSM_CONTROLLABLE:New(FSMT, Controllable)

Creates a new FSM_CONTROLLABLE object.

Parameters

Return value

#FSM_CONTROLLABLE:

FSM_CONTROLLABLE:SetControllable(FSMControllable)

Sets the CONTROLLABLE object that the FSM_CONTROLLABLE governs.

Parameter

Return value

#FSM_CONTROLLABLE:

FSM_CONTROLLABLE:_call_handler(handler, params)

Parameters

  • handler :

  • params :

Type FSM_PROCESS

FSM_PROCESS class

Field(s)

FSM_PROCESS:AddScore(State, ScoreText, Score)

Adds a score for the FSM_PROCESS to be achieved.

Parameters

  • #string State : is the state of the process when the score needs to be given. (See the relevant state descriptions of the process).

  • #string ScoreText : is a text describing the score that is given according the status.

  • #number Score : is a number providing the score of the status.

Return value

#FSM_PROCESS: self

FSM_PROCESS:Assign(Task, ProcessUnit)

Assign the process to a Unit and activate the process.

Parameters

Return value

#FSM_PROCESS: self

#string FSM_PROCESS.ClassName
FSM_PROCESS:Copy(Controllable, Task)

Creates a new FSMPROCESS object based on this FSMPROCESS.

Parameters

  • Controllable :

  • Task :

Return value

#FSM_PROCESS:

FSM_PROCESS:GetCommandCenter()

Gets the mission of the process.

Return value

Tasking.CommandCenter#COMMANDCENTER:

FSM_PROCESS:GetMission()

Gets the mission of the process.

Return value

Tasking.Mission#MISSION:

FSM_PROCESS:GetTask()

Gets the task of the process.

Return value

Tasking.Task#TASK:

FSM_PROCESS:Init(FsmProcess)

Parameter

  • FsmProcess :

FSM_PROCESS:Message(Message)

Send a message of the Task to the Group of the Unit.

Parameter

  • Message :

FSM_PROCESS:New(Controllable, Task)

Creates a new FSM_PROCESS object.

Parameters

  • Controllable :

  • Task :

Return value

#FSM_PROCESS:

FSM_PROCESS:SetTask(Task)

Sets the task of the process.

Parameter

Return value

#FSM_PROCESS:

Tasking.Task#TASK FSM_PROCESS.Task
FSM_PROCESS:onenterAssigned(ProcessUnit)

Parameter

  • ProcessUnit :

FSM_PROCESS:onenterFailed(ProcessUnit)

Parameter

  • ProcessUnit :

FSM_PROCESS:onenterSuccess(ProcessUnit)

Parameter

  • ProcessUnit :

FSM_PROCESS:onstatechange(ProcessUnit, Event, From, To, Dummy)

StateMachine callback function for a FSM_PROCESS

Parameters

Type FSM_SET

FSM_SET class

Field(s)

#string FSM_SET.ClassName
FSM_SET:Get()

Gets the SETBASE object that the FSMSET governs.

Return value

Core.Set#SET_BASE:

FSM_SET:New(FSMT, Set_SET_BASE, FSMSet)

Creates a new FSM_SET object.

Parameters

  • #table FSMT : Finite State Machine Table

  • SetSETBASE : FSMSet (optional) The Set object that the FSM_SET governs.

  • FSMSet :

Return value

#FSM_SET:

Core.Set#SET_BASE FSM_SET.Set
FSM_SET:_call_handler(handler, params)

Parameters

  • handler :

  • params :

Type FSM_TASK

FSM_TASK class

Field(s)

#string FSM_TASK.ClassName
FSM_TASK:New(FSMT, Task, TaskUnit)

Creates a new FSM_TASK object.

Parameters

Return value

#FSM_TASK:

Tasking.Task#TASK FSM_TASK.Task
FSM_TASK:_call_handler(handler, params)

Parameters

  • handler :

  • params :