VR-Forces 5.2 Lua Function Documentation

fsm2

(For high level concepts about how to use Lua to write scripted tasks, please see VR-Forces User's Guide.)

A design pattern for implementing finite state machines (FSMs) in Lua.
==========================================================================================
Copyright 2013, VT MAK
Inspired by fsm.lua, written by Erik Cornelisse.
==========================================================================================

An FSM is defined with states and transitions between states. Each transition in is described with four elements: old_state, transition condition function, new_state, and action. The transition condition function is a predicate function that is run to determine if the transition should take place. If the transition takes place, the action, which is also a function, is run after the FSM transitions to the new_state.
Each state in the FSM (built with this FSM package) is a table with the following structure:

 {<state name> = 
{tickFunction = <tick function>,
transitionList =
{{predicateFunction = <condition function>,
newState = <state after the transition>,
actionFunction = <function run on transition>}
{<another transition>}
...
}
}
}
There is also a special state in the table, "*", that means "any state."

The FSM tick function executes as follows when the FSM is in state s, given transitions defined by (predicate, new-state, action):
 Run the state-specific tick function, if any, for s.
For each transition t defined for s do:
If predicate is true then
Change state to new-state.
Run function action.
Break

The FSM has a tick function that looks up the entry in the stt for the current state (which the FSM maintains internally). In the tick function the state's tick function is run, if it exists. If a tick function doesn't exist for the current state, the tick function for the "*" state is run, if it exists.
Next, the predicateFunctions in the transitionList are run one at a time. They are run in the order that they are added to the FSM. When the first predicate returns true, the FSM transitions to the associated newState and the actionFunction, if it exists, is run. If there are no predicate functions for the state, or if none are true, the predicate functions for the ANY state are checked.
The tick functions, the predicate functions, and the action functions all take a single parameter which is passed to them via the FSM tick function. This parameter is intended to represent information in the "world state," that the functions can use. For example, it could be the current time, or a table with the locations of all the agents in the world. The functions must be defined with this argument, but they don't have to use it.
Note that the fsm2 module keeps state internally, and this is local to each FSM instance. Since the state is not global, it is not saved in a scenario save. Therefore the script writer should do a :get() in the saveState() callback, and in the loadState() callback use :set() to recover the FSM state.

USAGE EXAMPLE:

FSM = require "fsm2"
testFSM = FSM.new()
-- For "start"
testFSM:addTransition("start", function(w) return true end, "state1", function(w) end)
-- For "state1"
testFSM:addTransition("state1", function(w) print ("S1 Cond 1") return false end, "state2", nil)
testFSM:addTransition("state1", function(w) print ("S1 Cond 2") return true end, "state3",
function(w) print("S1 C2 action") end)

--For "state2"
testFSM:addTransition("state2", function(w) return false end, "state2", nil)

--For "state3"
testFSM:addTransition("state3", function(w) print("S3 Cond 1") return false end,"state3", nil)

testFSM:addTickFunctions({ {"state1", function(w) print("S1 tick function ",w) end},
{"state2", function(w) print("S2 tick function ", w) end},
{"state3", function(w) print("S3 tick function ", w) end}
})
testFSM:set("start")

testFSM:dump()

--Assume this is a callback
function tick()

--Need an argument for tick; not used above; arbitrarily use sim time here
testFSM:tick(vrf:getSimulationTime())
end

function saveState()
-- By default, only member of table checkpointState get saved
checkpiontState.fsmState = testFSM:get()
end
function loadState()
testFSM:set(checkpointState.fsmState)
end

Function List

addTickFunctions (t) Add new state tick functions to the FSM.
addTransition (oldState, condition, nextState, action) Add a new state transition to the FSM.
get () Get the current state of the state machine.
new () Creates a new FSM instance and returns it.
set (s) Sets the current state
tick (worldState) Tick the FSM.


Functions

addTickFunctions (t)
Add new state tick functions to the FSM.
Each state can have one function that is run when the FSM is ticked in that state. This function is run before the transition predicate functions are run.
Adding at least one transition, or tick function, for a state makes the state a valid state in the FSM. The start state of the FSM will be set to the state in the first addTransition or addTickFunctions call made in the script.

Parameters:

  • t: A table of state tick functions to add to the FSM definition. The table will be in the form
    { {state, function}, {s, f}...}
    where
    state is the name of the state (a string)
    function is a function taking one argument. (This argument will be passed in from the FSM tick function.) Multiple calls to addTickFunction can be made; if a state in the input list already has a tick function, it will be replaced by the new one.

Return value:

    Nothing.
addTransition (oldState, condition, nextState, action)
Add a new state transition to the FSM.
Adding at least one transition, or tick function, for a state makes the state a valid state in the FSM. The state of the FSM will be set to the state parameter in the first addTransition or addTickFunctions call made in the script.

Parameters:

  • oldState: The FSM state that this transition will move out of.
  • condition: A function taking one argument and returning a boolean. If true, the transition will be taken. The argument is intended to provide information about the state of the world, to use in determining if the transition should be taken. This argument is the argument provided to the tick function.
  • nextState: The state to transition to if the condition is true.
  • action: A function taking one argument. This function will be executed if the transition is taken. The argument is the argument provided to the tick function. The action function can be nil.

Return value:

    True if successful, false otherwise (error in arguments).
get ()
Get the current state of the state machine.

Return value:

    The current state string.
new ()
Creates a new FSM instance and returns it.

Return value:

    A table defining the FSM. Use the FSM methods to set states, add transitions, add tick functions, and tick the FSM.
set (s)
Sets the current state

Parameters:

  • s: The new state name to become the current state. Must be a state defined in the initial state transition table.
tick (worldState)
Tick the FSM. The state-tick-function for the current state is executed; following that, each state transition predicate function is executed until one returns true; then the state is changed to the new-state associated with that transition function, and the FSM state is changed to the new-state.
If no transition predicate for a state is true, then transition predicate functions for the ANY state will be executed.
If there is no information in the state transition table for the current state--i.e., neither addTransitions nor addTickFunctions has added anything for the current state--then this tick does nothing (does not check the ANY tickFunction or transitions).

Parameters:

  • worldState: An argument of type determined by the user. This argument will be passed to the state tick function, the transition predicate functions and the transition action function. This argument can be used to pass in a table describing the state of the world, the current time, etc. (Alternatively, all of these functions may ignore the argument and use information in global variables.)

Return value:

    The result of the action function associated with the transition.

Copyright© 2025 MAK Technologies, Inc. All rights reserved.