aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcharacter/llstatemachine.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llstatemachine.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcharacter/llstatemachine.cpp')
-rw-r--r--linden/indra/llcharacter/llstatemachine.cpp397
1 files changed, 397 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/llstatemachine.cpp b/linden/indra/llcharacter/llstatemachine.cpp
new file mode 100644
index 0000000..6920bcf
--- /dev/null
+++ b/linden/indra/llcharacter/llstatemachine.cpp
@@ -0,0 +1,397 @@
1/**
2 * @file llstatemachine.cpp
3 * @brief LLStateMachine implementation file.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llstatemachine.h"
31#include "llapr.h"
32
33#define FSM_PRINT_STATE_TRANSITIONS (0)
34
35U32 LLUniqueID::sNextID = 0;
36
37bool operator==(const LLUniqueID &a, const LLUniqueID &b)
38{
39 return (a.mId == b.mId);
40}
41
42bool operator!=(const LLUniqueID &a, const LLUniqueID &b)
43{
44 return (a.mId != b.mId);
45}
46
47//-----------------------------------------------------------------------------
48// LLStateDiagram
49//-----------------------------------------------------------------------------
50LLStateDiagram::LLStateDiagram()
51{
52 mUseDefaultState = FALSE;
53}
54
55LLStateDiagram::~LLStateDiagram()
56{
57
58}
59
60// add a state to the state graph
61BOOL LLStateDiagram::addState(LLFSMState *state)
62{
63 mStates[state] = Transitions();
64 return TRUE;
65}
66
67// add a directed transition between 2 states
68BOOL LLStateDiagram::addTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition)
69{
70 StateMap::iterator state_it;
71 state_it = mStates.find(&start_state);
72 Transitions* state_transitions = NULL;
73 if (state_it == mStates.end() )
74 {
75 addState(&start_state);
76 state_transitions = &mStates[&start_state];
77 }
78 else
79 {
80 state_transitions = &state_it->second;
81 }
82 state_it = mStates.find(&end_state);
83 if (state_it == mStates.end() )
84 {
85 addState(&end_state);
86 }
87
88 Transitions::iterator transition_it = state_transitions->find(&transition);
89 if (transition_it != state_transitions->end())
90 {
91 llerrs << "LLStateTable::addDirectedTransition() : transition already exists" << llendl;
92 return FALSE; // transition already exists
93 }
94
95 (*state_transitions)[&transition] = &end_state;
96 return TRUE;
97}
98
99// add an undirected transition between 2 states
100BOOL LLStateDiagram::addUndirectedTransition(LLFSMState& start_state, LLFSMState& end_state, LLFSMTransition& transition)
101{
102 BOOL result;
103 result = addTransition(start_state, end_state, transition);
104 if (result)
105 {
106 result = addTransition(end_state, start_state, transition);
107 }
108 return result;
109}
110
111// add a transition that exists for every state
112void LLStateDiagram::addDefaultTransition(LLFSMState& end_state, LLFSMTransition& transition)
113{
114 mDefaultTransitions[&transition] = &end_state;
115}
116
117// process a possible transition, and get the resulting state
118LLFSMState* LLStateDiagram::processTransition(LLFSMState& start_state, LLFSMTransition& transition)
119{
120 // look up transition
121 //LLFSMState** dest_state = (mStates.getValue(&start_state))->getValue(&transition);
122 LLFSMState* dest_state = NULL;
123 StateMap::iterator state_it = mStates.find(&start_state);
124 if (state_it == mStates.end())
125 {
126 return NULL;
127 }
128 Transitions::iterator transition_it = state_it->second.find(&transition);
129
130 // try default transitions if state-specific transition not found
131 if (transition_it == state_it->second.end())
132 {
133 dest_state = mDefaultTransitions[&transition];
134 }
135 else
136 {
137 dest_state = transition_it->second;
138 }
139
140 // if we have a destination state...
141 if (NULL != dest_state)
142 {
143 // ...return it...
144 return dest_state;
145 }
146 // ... otherwise ...
147 else
148 {
149 // ...look for default state...
150 if (mUseDefaultState)
151 {
152 // ...return it if we have it...
153 return mDefaultState;
154 }
155 else
156 {
157 // ...or else we're still in the same state.
158 return &start_state;
159 }
160 }
161}
162
163void LLStateDiagram::setDefaultState(LLFSMState& default_state)
164{
165 mUseDefaultState = TRUE;
166 mDefaultState = &default_state;
167}
168
169S32 LLStateDiagram::numDeadendStates()
170{
171 S32 numDeadends = 0;
172 StateMap::iterator state_it;
173 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
174 {
175 if (state_it->second.size() == 0)
176 {
177 numDeadends++;
178 }
179 }
180 return numDeadends;
181}
182
183BOOL LLStateDiagram::stateIsValid(LLFSMState& state)
184{
185 if (mStates.find(&state) != mStates.end())
186 {
187 return TRUE;
188 }
189 return FALSE;
190}
191
192LLFSMState* LLStateDiagram::getState(U32 state_id)
193{
194 StateMap::iterator state_it;
195 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
196 {
197 if (state_it->first->getID() == state_id)
198 {
199 return state_it->first;
200 }
201 }
202 return NULL;
203}
204
205BOOL LLStateDiagram::saveDotFile(const char* filename)
206{
207 apr_file_t* dot_file = ll_apr_file_open(filename, LL_APR_W);
208
209 if (!dot_file)
210 {
211 llwarns << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << llendl;
212 return FALSE;
213 }
214 apr_file_printf(dot_file, "digraph StateMachine {\n\tsize=\"100,100\";\n\tfontsize=40;\n\tlabel=\"Finite State Machine\";\n\torientation=landscape\n\tratio=.77\n");
215
216 StateMap::iterator state_it;
217 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
218 {
219 apr_file_printf(dot_file, "\t\"%s\" [fontsize=28,shape=box]\n", state_it->first->getName().c_str());
220 }
221 apr_file_printf(dot_file, "\t\"All States\" [fontsize=30,style=bold,shape=box]\n");
222
223 Transitions::iterator transitions_it;
224 for(transitions_it = mDefaultTransitions.begin(); transitions_it != mDefaultTransitions.end(); ++transitions_it)
225 {
226 apr_file_printf(dot_file, "\t\"All States\" -> \"%s\" [label = \"%s\",fontsize=24];\n", transitions_it->second->getName().c_str(),
227 transitions_it->second->getName().c_str());
228 }
229
230 if (mDefaultState)
231 {
232 apr_file_printf(dot_file, "\t\"All States\" -> \"%s\";\n", mDefaultState->getName().c_str());
233 }
234
235
236 for(state_it = mStates.begin(); state_it != mStates.end(); ++state_it)
237 {
238 LLFSMState *state = state_it->first;
239
240 Transitions::iterator transitions_it;
241 for(transitions_it = state_it->second.begin();
242 transitions_it != state_it->second.end();
243 ++transitions_it)
244 {
245 std::string state_name = state->getName();
246 std::string target_name = transitions_it->second->getName();
247 std::string transition_name = transitions_it->first->getName();
248 apr_file_printf(dot_file, "\t\"%s\" -> \"%s\" [label = \"%s\",fontsize=24];\n", state->getName().c_str(),
249 target_name.c_str(),
250 transition_name.c_str());
251 }
252 }
253
254 apr_file_printf(dot_file, "}\n");
255
256 apr_file_close(dot_file);
257
258 return TRUE;
259}
260
261std::ostream& operator<<(std::ostream &s, LLStateDiagram &FSM)
262{
263 if (FSM.mDefaultState)
264 {
265 s << "Default State: " << FSM.mDefaultState->getName() << "\n";
266 }
267
268 LLStateDiagram::Transitions::iterator transitions_it;
269 for(transitions_it = FSM.mDefaultTransitions.begin();
270 transitions_it != FSM.mDefaultTransitions.end();
271 ++transitions_it)
272 {
273 s << "Any State -- " << transitions_it->first->getName()
274 << " --> " << transitions_it->second->getName() << "\n";
275 }
276
277 LLStateDiagram::StateMap::iterator state_it;
278 for(state_it = FSM.mStates.begin(); state_it != FSM.mStates.end(); ++state_it)
279 {
280 LLStateDiagram::Transitions::iterator transitions_it;
281 for(transitions_it = state_it->second.begin();
282 transitions_it != state_it->second.end();
283 ++transitions_it)
284 {
285 s << state_it->first->getName() << " -- " << transitions_it->first->getName()
286 << " --> " << transitions_it->second->getName() << "\n";
287 }
288 s << "\n";
289 }
290
291 return s;
292}
293
294//-----------------------------------------------------------------------------
295// LLStateMachine
296//-----------------------------------------------------------------------------
297
298LLStateMachine::LLStateMachine()
299{
300 // we haven't received a starting state yet
301 mCurrentState = NULL;
302 mLastState = NULL;
303 mStateDiagram = NULL;
304}
305
306LLStateMachine::~LLStateMachine()
307{
308
309}
310
311// returns current state
312LLFSMState* LLStateMachine::getCurrentState() const
313{
314 return mCurrentState;
315}
316
317// executes current state
318void LLStateMachine::runCurrentState(void *data)
319{
320 mCurrentState->execute(data);
321}
322
323// set current state
324BOOL LLStateMachine::setCurrentState(LLFSMState *initial_state, void* user_data, BOOL skip_entry)
325{
326 llassert(mStateDiagram);
327
328 if (mStateDiagram->stateIsValid(*initial_state))
329 {
330 mLastState = mCurrentState = initial_state;
331 if (!skip_entry)
332 {
333 initial_state->onEntry(user_data);
334 }
335 return TRUE;
336 }
337
338 return FALSE;
339}
340
341BOOL LLStateMachine::setCurrentState(U32 state_id, void* user_data, BOOL skip_entry)
342{
343 llassert(mStateDiagram);
344
345 LLFSMState* state = mStateDiagram->getState(state_id);
346
347 if (state)
348 {
349 mLastState = mCurrentState = state;
350 if (!skip_entry)
351 {
352 state->onEntry(user_data);
353 }
354 return TRUE;
355 }
356
357 return FALSE;
358}
359
360void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_data)
361{
362 llassert(mStateDiagram);
363
364 LLFSMState* new_state = mStateDiagram->processTransition(*mCurrentState, transition);
365
366 mLastTransition = &transition;
367 mLastState = mCurrentState;
368
369 if (*mCurrentState != *new_state)
370 {
371 if (mCurrentState && new_state && *mCurrentState != *new_state)
372 {
373 mCurrentState->onExit(user_data);
374 }
375 if (new_state)
376 {
377 if (!mCurrentState || *mCurrentState != *new_state)
378 {
379 mCurrentState = new_state;
380 if (mCurrentState)
381 {
382 mCurrentState->onEntry(user_data);
383 }
384 }
385 }
386#if FSM_PRINT_STATE_TRANSITIONS
387 llinfos << "Entering state " << mCurrentState->getName() <<
388 " on transition " << transition.getName() << " from state " <<
389 mLastState->getName() << llendl;
390#endif
391 }
392}
393
394void LLStateMachine::setStateDiagram(LLStateDiagram* diagram)
395{
396 mStateDiagram = diagram;
397}