Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fsm.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 // INCLUDES
19 #include "precompiled.h"
20 #include "fsm.h"
21 
22 // DECLARATIONS
23 
24 //-----------------------------------------------------------------------------
25 // Name: CFsmEvent()
26 // Desc: Constructor
27 //-----------------------------------------------------------------------------
28 CFsmEvent::CFsmEvent( unsigned int type )
29 {
30  m_Type = type;
31  m_Param = NULL;
32 }
33 
34 //-----------------------------------------------------------------------------
35 // Name; ~CFsmEvent()
36 // Desc: Destructor
37 //-----------------------------------------------------------------------------
39 {
40  m_Param = NULL;
41 }
42 
43 //-----------------------------------------------------------------------------
44 // Name: SetParamRef()
45 // Desc: Sets the parameter for the event
46 //-----------------------------------------------------------------------------
47 void CFsmEvent::SetParamRef( void* pParam )
48 {
49  m_Param = pParam;
50 }
51 
52 //-----------------------------------------------------------------------------
53 // Name: CFsmTransition()
54 // Desc: Constructor
55 //-----------------------------------------------------------------------------
57 {
59 }
60 
61 //-----------------------------------------------------------------------------
62 // Name: ~CFsmTransition()
63 // Desc: Destructor
64 //-----------------------------------------------------------------------------
66 {
67  m_Actions.clear();
68  m_Conditions.clear();
69 }
70 
71 //-----------------------------------------------------------------------------
72 // Name: RegisterAction()
73 // Desc: Adds action that will be executed when the transition will occur
74 //-----------------------------------------------------------------------------
75 void CFsmTransition::RegisterAction( void* pAction, void* pContext )
76 {
77  CallbackFunction callback;
78 
79  // Add action at the end of actions list
80  callback.pFunction = pAction;
81  callback.pContext = pContext;
82 
83  m_Actions.push_back( callback );
84 }
85 
86 //-----------------------------------------------------------------------------
87 // Name: AddCondition()
88 // Desc: Adds condition which will be evaluated when the transition will occurs
89 //-----------------------------------------------------------------------------
90 void CFsmTransition::RegisterCondition( void* pCondition, void* pContext )
91 {
92  CallbackFunction callback;
93 
94  // Add condition at the end of conditions list
95  callback.pFunction = pCondition;
96  callback.pContext = pContext;
97 
98  m_Conditions.push_back( callback );
99 }
100 
101 //-----------------------------------------------------------------------------
102 // Name: SetEvent()
103 // Desc: Set event for which transition will occur
104 //-----------------------------------------------------------------------------
106 {
107  m_Event = pEvent;
108 }
109 
110 //-----------------------------------------------------------------------------
111 // Name: SetNextState()
112 // Desc: Set next state the transition will switch the system to
113 //-----------------------------------------------------------------------------
114 void CFsmTransition::SetNextState( unsigned int nextState )
115 {
116  m_NextState = nextState;
117 }
118 
119 //-----------------------------------------------------------------------------
120 // Name: ApplyConditions()
121 // Desc: Evaluate conditions for the transition
122 // Note: If there are no conditions, assume true
123 //-----------------------------------------------------------------------------
125 {
126  bool eval = true;
127 
128  CallbackList::const_iterator it = m_Conditions.begin();
129  for( ; it != m_Conditions.end(); ++it )
130  {
131  if ( it->pFunction )
132  {
133  // Evaluate condition
134  CONDITION Condition = ( CONDITION )it->pFunction;
135  eval &= Condition( it->pContext );
136  }
137  }
138 
139  return eval;
140 }
141 
142 //-----------------------------------------------------------------------------
143 // Name: RunActions()
144 // Desc: Execute actions for the transition
145 // Note: If there are no actions, assume true
146 //-----------------------------------------------------------------------------
147 bool CFsmTransition::RunActions( void ) const
148 {
149  bool result = true;
150 
151  CallbackList::const_iterator it = m_Actions.begin();
152  for( ; it != m_Actions.end(); ++it )
153  {
154  if ( it->pFunction )
155  {
156  // Run action
157  ACTION Action = ( ACTION )it->pFunction;
158  result &= Action( it->pContext, m_Event );
159  }
160  }
161 
162  return result;
163 }
164 
165 //-----------------------------------------------------------------------------
166 // Name: CFsm()
167 // Desc: Constructor
168 //-----------------------------------------------------------------------------
169 CFsm::CFsm( void )
170 {
171  m_Done = false;
175 }
176 
177 //-----------------------------------------------------------------------------
178 // Name: ~CFsm()
179 // Desc: Destructor
180 //-----------------------------------------------------------------------------
181 CFsm::~CFsm( void )
182 {
183  Shutdown();
184 }
185 
186 //-----------------------------------------------------------------------------
187 // Name: Setup()
188 // Desc: Setup events, actions and state transitions
189 //-----------------------------------------------------------------------------
190 void CFsm::Setup( void )
191 {
192  // Does nothing by default
193 }
194 
195 //-----------------------------------------------------------------------------
196 // Name: Reset()
197 // Desc: Shuts down the state machine and releases any resources
198 //-----------------------------------------------------------------------------
199 void CFsm::Shutdown( void )
200 {
201  // Release transitions
202  TransitionList::iterator itTransition = m_Transitions.begin();
203  for ( ; itTransition < m_Transitions.end(); ++itTransition )
204  {
205  CFsmTransition* pCurrTransition = *itTransition;
206  if ( !pCurrTransition ) continue;
207 
208  delete pCurrTransition;
209  }
210 
211  // Release events
212  EventMap::iterator itEvent = m_Events.begin();
213  for( ; itEvent != m_Events.end(); ++itEvent )
214  {
215  CFsmEvent* pCurrEvent = itEvent->second;
216  if ( !pCurrEvent ) continue;
217 
218  delete pCurrEvent;
219  }
220 
221  m_States.clear();
222  m_Events.clear();
223  m_Transitions.clear();
224 
225  m_Done = false;
229 }
230 
231 //-----------------------------------------------------------------------------
232 // Name: AddState()
233 // Desc: Adds the specified state to the internal list of states
234 // Note: If a state with the specified ID exists, the state is not added
235 //-----------------------------------------------------------------------------
236 void CFsm::AddState( unsigned int state )
237 {
238  m_States.insert( state );
239 }
240 
241 //-----------------------------------------------------------------------------
242 // Name: AddEvent()
243 // Desc: Adds the specified event to the internal list of events
244 // Note: If an eveny with the specified ID exists, the event is not added
245 //-----------------------------------------------------------------------------
246 CFsmEvent* CFsm::AddEvent( unsigned int eventType )
247 {
248  CFsmEvent* pEvent = NULL;
249 
250  // Lookup event by type
251  EventMap::iterator it = m_Events.find( eventType );
252  if ( it != m_Events.end() )
253  {
254  pEvent = it->second;
255  }
256  else
257  {
258  pEvent = new CFsmEvent( eventType );
259  if ( !pEvent ) return NULL;
260 
261  // Store new event into internal map
262  m_Events[ eventType ] = pEvent;
263  }
264 
265  return pEvent;
266 }
267 
268 //-----------------------------------------------------------------------------
269 // Name: AddTransition()
270 // Desc: Adds a new transistion to the state machine
271 //-----------------------------------------------------------------------------
273  unsigned int state,
274  unsigned int eventType,
275  unsigned int nextState )
276 {
277  // Make sure we store the current state
278  AddState( state );
279 
280  // Make sure we store the next state
281  AddState( nextState );
282 
283  // Make sure we store the event
284  CFsmEvent* pEvent = AddEvent( eventType );
285  if ( !pEvent ) return NULL;
286 
287  // Create new transition
288  CFsmTransition* pNewTransition = new CFsmTransition( state );
289  if ( !pNewTransition )
290  {
291  delete pEvent;
292  return NULL;
293  }
294 
295  // Setup new transition
296  pNewTransition->SetEvent( pEvent );
297  pNewTransition->SetNextState( nextState );
298 
299  // Store new transition
300  m_Transitions.push_back( pNewTransition );
301 
302  return pNewTransition;
303 }
304 
305 //-----------------------------------------------------------------------------
306 // Name: AddTransition()
307 // Desc: Adds a new transition to the state machine
308 //-----------------------------------------------------------------------------
310  unsigned int state,
311  unsigned int eventType,
312  unsigned int nextState,
313  void* pAction,
314  void* pContext )
315 {
316  CFsmTransition* pTransition = AddTransition( state, eventType, nextState );
317  if ( !pTransition ) return NULL;
318 
319  // If action specified, register it
320  if ( pAction )
321  pTransition->RegisterAction( pAction, pContext );
322 
323  return pTransition;
324 }
325 
326 //-----------------------------------------------------------------------------
327 // Name: GetTransition()
328 // Desc: Lookup transition given the state, event and next state to transition
329 //-----------------------------------------------------------------------------
331  unsigned int state,
332  unsigned int eventType ) const
333 {
334  // Valid state?
335  if ( !IsValidState( state ) ) return NULL;
336 
337  // Valid event?
338  if ( !IsValidEvent( eventType ) ) return NULL;
339 
340  // Loop through the list of transitions
341  TransitionList::const_iterator it = m_Transitions.begin();
342  for ( ; it != m_Transitions.end(); ++it )
343  {
344  CFsmTransition* pCurrTransition = *it;
345  if ( !pCurrTransition ) continue;
346 
347  CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
348  if ( !pCurrEvent ) continue;
349 
350  // Is it our transition?
351  if ( pCurrTransition->GetCurrState() == state &&
352  pCurrEvent->GetType() == eventType )
353  {
354  return pCurrTransition;
355  }
356  }
357 
358  // No transition found
359  return NULL;
360 }
361 
362 //-----------------------------------------------------------------------------
363 // Name: SetFirstState()
364 // Desc: Set initial state for FSM
365 //-----------------------------------------------------------------------------
366 void CFsm::SetFirstState( unsigned int firstState )
367 {
368  m_FirstState = firstState;
369 }
370 
371 //-----------------------------------------------------------------------------
372 // Name: SetCurrState()
373 // Desc: Set current state and update last state to current state
374 //-----------------------------------------------------------------------------
375 void CFsm::SetCurrState( unsigned int state )
376 {
377  m_CurrState = state;
378 }
379 
380 //-----------------------------------------------------------------------------
381 // Name: IsFirstTime()
382 // Desc: Verifies if the state machine has been already updated
383 //-----------------------------------------------------------------------------
384 bool CFsm::IsFirstTime( void ) const
385 {
386  return ( m_CurrState == FSM_INVALID_STATE );
387 }
388 
389 //-----------------------------------------------------------------------------
390 // Name: Update()
391 // Desc: Updates state machine and retrieves next state
392 //-----------------------------------------------------------------------------
393 bool CFsm::Update( unsigned int eventType, void* pEventParam )
394 {
395  // Valid event?
396  if ( !IsValidEvent( eventType ) )
397  return false;
398 
399  // First time update?
400  if ( IsFirstTime() )
402 
403  // Lookup transition
404  CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
405  if ( !pTransition ) return false;
406 
407  // Setup event parameter
408  EventMap::iterator it = m_Events.find( eventType );
409  if ( it != m_Events.end() )
410  {
411  CFsmEvent* pEvent = it->second;
412  if ( pEvent ) pEvent->SetParamRef( pEventParam );
413  }
414 
415  // Valid transition?
416  if ( !pTransition->ApplyConditions() ) return false;
417 
418  // Save the default state transition (actions might call SetNextState
419  // to override this)
420  SetNextState( pTransition->GetNextState() );
421 
422  // Run transition actions
423  if ( !pTransition->RunActions() ) return false;
424 
425  // Switch state
427 
428  // Reset the next state since it's no longer valid
430 
431  return true;
432 }
433 
434 //-----------------------------------------------------------------------------
435 // Name: IsDone()
436 // Desc: Tests whether the state machine has finished its work
437 // Note: This is state machine specific
438 //-----------------------------------------------------------------------------
439 bool CFsm::IsDone( void ) const
440 {
441  // By default the internal flag m_Done is tested
442  return m_Done;
443 }
444 
445 //-----------------------------------------------------------------------------
446 // Name: IsValidState()
447 // Desc: Verifies whether the specified state is managed by FSM
448 //-----------------------------------------------------------------------------
449 bool CFsm::IsValidState( unsigned int state ) const
450 {
451  StateSet::const_iterator it = m_States.find( state );
452  if ( it == m_States.end() ) return false;
453 
454  return true;
455 }
456 
457 //-----------------------------------------------------------------------------
458 // Name: IsValidEvent()
459 // Desc: Verifies whether the specified event is managed by FSM
460 //-----------------------------------------------------------------------------
461 bool CFsm::IsValidEvent( unsigned int eventType ) const
462 {
463  EventMap::const_iterator it = m_Events.find( eventType );
464  if ( it == m_Events.end() ) return false;
465 
466  return true;
467 }
void RegisterCondition(void *pCondition, void *pContext)
Definition: fsm.cpp:90
unsigned int m_NextState
Definition: fsm.h:171
void RegisterAction(void *pAction, void *pContext)
Definition: fsm.cpp:75
void Shutdown(void)
Clear event, action and condition lists and reset state machine.
Definition: fsm.cpp:199
Represents a signal in the state machine that a change has occurred.
Definition: fsm.h:53
CFsmEvent * m_Event
Definition: fsm.h:101
void SetEvent(CFsmEvent *pEvent)
Definition: fsm.cpp:105
bool IsValidEvent(unsigned int eventType) const
Definition: fsm.cpp:461
void AddState(unsigned int state)
Definition: fsm.cpp:236
unsigned int m_Type
Definition: fsm.h:66
void * pFunction
Definition: fsm.h:38
bool m_Done
Definition: fsm.h:168
bool ApplyConditions(void) const
Definition: fsm.cpp:124
CFsmEvent * AddEvent(unsigned int eventType)
Definition: fsm.cpp:246
virtual void Setup(void)
Constructs the state machine.
Definition: fsm.cpp:190
void * pContext
Definition: fsm.h:39
CFsmTransition(unsigned int state)
Definition: fsm.cpp:56
unsigned int GetCurrState(void) const
Definition: fsm.h:92
CFsmTransition * GetTransition(unsigned int state, unsigned int eventType) const
Definition: fsm.cpp:330
#define FSM_INVALID_STATE
Definition: fsm.h:27
bool IsFirstTime(void) const
Definition: fsm.cpp:384
void * m_Param
Definition: fsm.h:67
void SetNextState(unsigned int nextState)
Definition: fsm.h:155
unsigned int m_CurrState
Definition: fsm.h:99
unsigned int m_CurrState
Definition: fsm.h:170
bool RunActions(void) const
Definition: fsm.cpp:147
CallbackList m_Conditions
Definition: fsm.h:103
bool(* ACTION)(void *pContext, const CFsmEvent *pEvent)
Definition: fsm.h:34
CFsm(void)
Definition: fsm.cpp:169
unsigned int GetNextState(void) const
Definition: fsm.h:91
bool IsValidState(unsigned int state) const
Definition: fsm.cpp:449
bool Update(unsigned int eventType, void *pEventData)
Definition: fsm.cpp:393
void SetCurrState(unsigned int state)
Definition: fsm.cpp:375
EventMap m_Events
Definition: fsm.h:173
CFsmEvent * GetEvent(void) const
Definition: fsm.h:89
virtual ~CFsm(void)
Definition: fsm.cpp:181
TransitionList m_Transitions
Definition: fsm.h:174
void SetParamRef(void *pParam)
Definition: fsm.cpp:47
CFsmTransition * AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState)
Definition: fsm.cpp:272
CFsmEvent(unsigned int type)
Definition: fsm.cpp:28
StateSet m_States
Definition: fsm.h:172
unsigned int m_FirstState
Definition: fsm.h:169
~CFsmTransition(void)
Definition: fsm.cpp:65
~CFsmEvent(void)
Definition: fsm.cpp:38
virtual bool IsDone(void) const
Definition: fsm.cpp:439
unsigned int m_NextState
Definition: fsm.h:100
CallbackList m_Actions
Definition: fsm.h:102
unsigned int GetType(void) const
Definition: fsm.h:61
void SetFirstState(unsigned int firstState)
Definition: fsm.cpp:366
unsigned int GetNextState(void) const
Definition: fsm.h:156
void SetNextState(unsigned int nextState)
Definition: fsm.cpp:114
bool(* CONDITION)(void *pContext)
Definition: fsm.h:33
An association of event, condition, action and next state.
Definition: fsm.h:74
static enum @41 state