diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llstatemachine.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 397 |
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 | |||
35 | U32 LLUniqueID::sNextID = 0; | ||
36 | |||
37 | bool operator==(const LLUniqueID &a, const LLUniqueID &b) | ||
38 | { | ||
39 | return (a.mId == b.mId); | ||
40 | } | ||
41 | |||
42 | bool operator!=(const LLUniqueID &a, const LLUniqueID &b) | ||
43 | { | ||
44 | return (a.mId != b.mId); | ||
45 | } | ||
46 | |||
47 | //----------------------------------------------------------------------------- | ||
48 | // LLStateDiagram | ||
49 | //----------------------------------------------------------------------------- | ||
50 | LLStateDiagram::LLStateDiagram() | ||
51 | { | ||
52 | mUseDefaultState = FALSE; | ||
53 | } | ||
54 | |||
55 | LLStateDiagram::~LLStateDiagram() | ||
56 | { | ||
57 | |||
58 | } | ||
59 | |||
60 | // add a state to the state graph | ||
61 | BOOL LLStateDiagram::addState(LLFSMState *state) | ||
62 | { | ||
63 | mStates[state] = Transitions(); | ||
64 | return TRUE; | ||
65 | } | ||
66 | |||
67 | // add a directed transition between 2 states | ||
68 | BOOL 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 | ||
100 | BOOL 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 | ||
112 | void 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 | ||
118 | LLFSMState* 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 | |||
163 | void LLStateDiagram::setDefaultState(LLFSMState& default_state) | ||
164 | { | ||
165 | mUseDefaultState = TRUE; | ||
166 | mDefaultState = &default_state; | ||
167 | } | ||
168 | |||
169 | S32 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 | |||
183 | BOOL LLStateDiagram::stateIsValid(LLFSMState& state) | ||
184 | { | ||
185 | if (mStates.find(&state) != mStates.end()) | ||
186 | { | ||
187 | return TRUE; | ||
188 | } | ||
189 | return FALSE; | ||
190 | } | ||
191 | |||
192 | LLFSMState* 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 | |||
205 | BOOL 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 | |||
261 | std::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 | |||
298 | LLStateMachine::LLStateMachine() | ||
299 | { | ||
300 | // we haven't received a starting state yet | ||
301 | mCurrentState = NULL; | ||
302 | mLastState = NULL; | ||
303 | mStateDiagram = NULL; | ||
304 | } | ||
305 | |||
306 | LLStateMachine::~LLStateMachine() | ||
307 | { | ||
308 | |||
309 | } | ||
310 | |||
311 | // returns current state | ||
312 | LLFSMState* LLStateMachine::getCurrentState() const | ||
313 | { | ||
314 | return mCurrentState; | ||
315 | } | ||
316 | |||
317 | // executes current state | ||
318 | void LLStateMachine::runCurrentState(void *data) | ||
319 | { | ||
320 | mCurrentState->execute(data); | ||
321 | } | ||
322 | |||
323 | // set current state | ||
324 | BOOL 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 | |||
341 | BOOL 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 | |||
360 | void 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 | |||
394 | void LLStateMachine::setStateDiagram(LLStateDiagram* diagram) | ||
395 | { | ||
396 | mStateDiagram = diagram; | ||
397 | } | ||