Line data Source code
1 : /* Copyright (C) 2015 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 0 : CFsmEvent::CFsmEvent( unsigned int type )
29 : {
30 0 : m_Type = type;
31 0 : m_Param = NULL;
32 0 : }
33 :
34 : //-----------------------------------------------------------------------------
35 : // Name; ~CFsmEvent()
36 : // Desc: Destructor
37 : //-----------------------------------------------------------------------------
38 0 : CFsmEvent::~CFsmEvent( void )
39 : {
40 0 : m_Param = NULL;
41 0 : }
42 :
43 : //-----------------------------------------------------------------------------
44 : // Name: SetParamRef()
45 : // Desc: Sets the parameter for the event
46 : //-----------------------------------------------------------------------------
47 0 : void CFsmEvent::SetParamRef( void* pParam )
48 : {
49 0 : m_Param = pParam;
50 0 : }
51 :
52 : //-----------------------------------------------------------------------------
53 : // Name: CFsmTransition()
54 : // Desc: Constructor
55 : //-----------------------------------------------------------------------------
56 0 : CFsmTransition::CFsmTransition( unsigned int state )
57 : {
58 0 : m_CurrState = state;
59 0 : }
60 :
61 : //-----------------------------------------------------------------------------
62 : // Name: ~CFsmTransition()
63 : // Desc: Destructor
64 : //-----------------------------------------------------------------------------
65 0 : CFsmTransition::~CFsmTransition( void )
66 : {
67 0 : m_Actions.clear();
68 0 : m_Conditions.clear();
69 0 : }
70 :
71 : //-----------------------------------------------------------------------------
72 : // Name: RegisterAction()
73 : // Desc: Adds action that will be executed when the transition will occur
74 : //-----------------------------------------------------------------------------
75 0 : void CFsmTransition::RegisterAction( void* pAction, void* pContext )
76 : {
77 0 : CallbackFunction callback;
78 :
79 : // Add action at the end of actions list
80 0 : callback.pFunction = pAction;
81 0 : callback.pContext = pContext;
82 :
83 0 : m_Actions.push_back( callback );
84 0 : }
85 :
86 : //-----------------------------------------------------------------------------
87 : // Name: AddCondition()
88 : // Desc: Adds condition which will be evaluated when the transition will occurs
89 : //-----------------------------------------------------------------------------
90 0 : void CFsmTransition::RegisterCondition( void* pCondition, void* pContext )
91 : {
92 0 : CallbackFunction callback;
93 :
94 : // Add condition at the end of conditions list
95 0 : callback.pFunction = pCondition;
96 0 : callback.pContext = pContext;
97 :
98 0 : m_Conditions.push_back( callback );
99 0 : }
100 :
101 : //-----------------------------------------------------------------------------
102 : // Name: SetEvent()
103 : // Desc: Set event for which transition will occur
104 : //-----------------------------------------------------------------------------
105 0 : void CFsmTransition::SetEvent( CFsmEvent* pEvent )
106 : {
107 0 : m_Event = pEvent;
108 0 : }
109 :
110 : //-----------------------------------------------------------------------------
111 : // Name: SetNextState()
112 : // Desc: Set next state the transition will switch the system to
113 : //-----------------------------------------------------------------------------
114 0 : void CFsmTransition::SetNextState( unsigned int nextState )
115 : {
116 0 : m_NextState = nextState;
117 0 : }
118 :
119 : //-----------------------------------------------------------------------------
120 : // Name: ApplyConditions()
121 : // Desc: Evaluate conditions for the transition
122 : // Note: If there are no conditions, assume true
123 : //-----------------------------------------------------------------------------
124 0 : bool CFsmTransition::ApplyConditions( void ) const
125 : {
126 0 : bool eval = true;
127 :
128 0 : CallbackList::const_iterator it = m_Conditions.begin();
129 0 : for( ; it != m_Conditions.end(); ++it )
130 : {
131 0 : if ( it->pFunction )
132 : {
133 : // Evaluate condition
134 0 : CONDITION Condition = ( CONDITION )it->pFunction;
135 0 : eval &= Condition( it->pContext );
136 : }
137 : }
138 :
139 0 : 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 0 : bool CFsmTransition::RunActions( void ) const
148 : {
149 0 : bool result = true;
150 :
151 0 : CallbackList::const_iterator it = m_Actions.begin();
152 0 : for( ; it != m_Actions.end(); ++it )
153 : {
154 0 : if ( it->pFunction )
155 : {
156 : // Run action
157 0 : ACTION Action = ( ACTION )it->pFunction;
158 0 : result &= Action( it->pContext, m_Event );
159 : }
160 : }
161 :
162 0 : return result;
163 : }
164 :
165 : //-----------------------------------------------------------------------------
166 : // Name: CFsm()
167 : // Desc: Constructor
168 : //-----------------------------------------------------------------------------
169 0 : CFsm::CFsm( void )
170 : {
171 0 : m_Done = false;
172 0 : m_FirstState = FSM_INVALID_STATE;
173 0 : m_CurrState = FSM_INVALID_STATE;
174 0 : m_NextState = FSM_INVALID_STATE;
175 0 : }
176 :
177 : //-----------------------------------------------------------------------------
178 : // Name: ~CFsm()
179 : // Desc: Destructor
180 : //-----------------------------------------------------------------------------
181 0 : CFsm::~CFsm( void )
182 : {
183 0 : Shutdown();
184 0 : }
185 0 :
186 : //-----------------------------------------------------------------------------
187 : // Name: Setup()
188 0 : // Desc: Setup events, actions and state transitions
189 0 : //-----------------------------------------------------------------------------
190 : void CFsm::Setup( void )
191 0 : {
192 0 : // Does nothing by default
193 : }
194 :
195 : //-----------------------------------------------------------------------------
196 : // Name: Reset()
197 : // Desc: Shuts down the state machine and releases any resources
198 0 : //-----------------------------------------------------------------------------
199 : void CFsm::Shutdown( void )
200 : {
201 0 : // 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 0 :
208 : delete pCurrTransition;
209 : }
210 0 :
211 0 : // Release events
212 : EventMap::iterator itEvent = m_Events.begin();
213 0 : for( ; itEvent != m_Events.end(); ++itEvent )
214 0 : {
215 : CFsmEvent* pCurrEvent = itEvent->second;
216 0 : if ( !pCurrEvent ) continue;
217 :
218 : delete pCurrEvent;
219 : }
220 0 :
221 0 : m_States.clear();
222 : m_Events.clear();
223 0 : m_Transitions.clear();
224 0 :
225 : m_Done = false;
226 0 : m_FirstState = FSM_INVALID_STATE;
227 : m_CurrState = FSM_INVALID_STATE;
228 : m_NextState = FSM_INVALID_STATE;
229 0 : }
230 0 :
231 0 : //-----------------------------------------------------------------------------
232 : // Name: AddState()
233 0 : // Desc: Adds the specified state to the internal list of states
234 0 : // Note: If a state with the specified ID exists, the state is not added
235 0 : //-----------------------------------------------------------------------------
236 0 : void CFsm::AddState( unsigned int state )
237 0 : {
238 : m_States.insert( state );
239 : }
240 :
241 : //-----------------------------------------------------------------------------
242 : // Name: AddEvent()
243 : // Desc: Adds the specified event to the internal list of events
244 0 : // Note: If an eveny with the specified ID exists, the event is not added
245 : //-----------------------------------------------------------------------------
246 0 : CFsmEvent* CFsm::AddEvent( unsigned int eventType )
247 0 : {
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 0 : pEvent = it->second;
255 : }
256 0 : else
257 : {
258 : pEvent = new CFsmEvent( eventType );
259 0 : if ( !pEvent ) return NULL;
260 0 :
261 : // Store new event into internal map
262 0 : m_Events[ eventType ] = pEvent;
263 : }
264 :
265 : return pEvent;
266 0 : }
267 0 :
268 : //-----------------------------------------------------------------------------
269 : // Name: AddTransition()
270 0 : // Desc: Adds a new transistion to the state machine
271 : //-----------------------------------------------------------------------------
272 : CFsmTransition* CFsm::AddTransition(
273 0 : 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 0 : // 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 0 :
287 : // Create new transition
288 : CFsmTransition* pNewTransition = new CFsmTransition( state );
289 0 : if ( !pNewTransition )
290 : {
291 : delete pEvent;
292 0 : return NULL;
293 0 : }
294 :
295 : // Setup new transition
296 0 : pNewTransition->SetEvent( pEvent );
297 0 : pNewTransition->SetNextState( nextState );
298 :
299 : // Store new transition
300 : m_Transitions.push_back( pNewTransition );
301 :
302 : return pNewTransition;
303 : }
304 0 :
305 0 : //-----------------------------------------------------------------------------
306 : // Name: AddTransition()
307 : // Desc: Adds a new transition to the state machine
308 0 : //-----------------------------------------------------------------------------
309 : CFsmTransition* CFsm::AddTransition(
310 0 : 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 0 : if ( !pTransition ) return NULL;
318 :
319 : // If action specified, register it
320 : if ( pAction )
321 : pTransition->RegisterAction( pAction, pContext );
322 :
323 : return pTransition;
324 0 : }
325 0 :
326 : //-----------------------------------------------------------------------------
327 : // Name: GetTransition()
328 0 : // Desc: Lookup transition given the state, event and next state to transition
329 0 : //-----------------------------------------------------------------------------
330 : CFsmTransition* CFsm::GetTransition(
331 : unsigned int state,
332 : unsigned int eventType ) const
333 : {
334 : // Valid state?
335 : if ( !IsValidState( state ) ) return NULL;
336 :
337 : // Valid event?
338 0 : 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 0 : {
344 : CFsmTransition* pCurrTransition = *it;
345 : if ( !pCurrTransition ) continue;
346 0 :
347 : CFsmEvent* pCurrEvent = pCurrTransition->GetEvent();
348 : if ( !pCurrEvent ) continue;
349 0 :
350 0 : // Is it our transition?
351 : if ( pCurrTransition->GetCurrState() == state &&
352 0 : pCurrEvent->GetType() == eventType )
353 0 : {
354 : return pCurrTransition;
355 0 : }
356 0 : }
357 :
358 : // No transition found
359 0 : return NULL;
360 0 : }
361 :
362 0 : //-----------------------------------------------------------------------------
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 0 : //-----------------------------------------------------------------------------
375 : void CFsm::SetCurrState( unsigned int state )
376 0 : {
377 0 : m_CurrState = state;
378 : }
379 :
380 : //-----------------------------------------------------------------------------
381 : // Name: IsFirstTime()
382 : // Desc: Verifies if the state machine has been already updated
383 0 : //-----------------------------------------------------------------------------
384 : bool CFsm::IsFirstTime( void ) const
385 0 : {
386 0 : return ( m_CurrState == FSM_INVALID_STATE );
387 : }
388 :
389 : //-----------------------------------------------------------------------------
390 : // Name: Update()
391 : // Desc: Updates state machine and retrieves next state
392 0 : //-----------------------------------------------------------------------------
393 : bool CFsm::Update( unsigned int eventType, void* pEventParam )
394 0 : {
395 : // Valid event?
396 : if ( !IsValidEvent( eventType ) )
397 : return false;
398 :
399 : // First time update?
400 : if ( IsFirstTime() )
401 0 : m_CurrState = m_FirstState;
402 :
403 : // Lookup transition
404 0 : CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
405 : if ( !pTransition )
406 : return false;
407 :
408 0 : // Setup event parameter
409 0 : EventMap::iterator it = m_Events.find( eventType );
410 : if ( it != m_Events.end() )
411 : {
412 0 : CFsmEvent* pEvent = it->second;
413 0 : if ( pEvent ) pEvent->SetParamRef( pEventParam );
414 : }
415 :
416 : // Valid transition?
417 0 : if ( !pTransition->ApplyConditions() )
418 0 : return false;
419 :
420 0 : // Save the default state transition (actions might call SetNextState
421 0 : // to override this)
422 : SetNextState( pTransition->GetNextState() );
423 :
424 : // Run transition actions
425 0 : if ( !pTransition->RunActions() )
426 : return false;
427 :
428 : // Switch state
429 : SetCurrState( GetNextState() );
430 0 :
431 : // Reset the next state since it's no longer valid
432 : SetNextState( FSM_INVALID_STATE );
433 0 :
434 : return true;
435 : }
436 :
437 0 : //-----------------------------------------------------------------------------
438 : // Name: IsDone()
439 : // Desc: Tests whether the state machine has finished its work
440 0 : // Note: This is state machine specific
441 : //-----------------------------------------------------------------------------
442 0 : bool CFsm::IsDone( void ) const
443 : {
444 : // By default the internal flag m_Done is tested
445 : return m_Done;
446 : }
447 :
448 : //-----------------------------------------------------------------------------
449 : // Name: IsValidState()
450 0 : // Desc: Verifies whether the specified state is managed by FSM
451 : //-----------------------------------------------------------------------------
452 : bool CFsm::IsValidState( unsigned int state ) const
453 0 : {
454 : StateSet::const_iterator it = m_States.find( state );
455 : if ( it == m_States.end() ) return false;
456 :
457 : return true;
458 : }
459 :
460 0 : //-----------------------------------------------------------------------------
461 : // Name: IsValidEvent()
462 0 : // Desc: Verifies whether the specified event is managed by FSM
463 0 : //-----------------------------------------------------------------------------
464 : bool CFsm::IsValidEvent( unsigned int eventType ) const
465 : {
466 : EventMap::const_iterator it = m_Events.find( eventType );
467 : if ( it == m_Events.end() ) return false;
468 :
469 : return true;
470 : }
|