llstatemachine.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:10k
源码类别:

游戏引擎

开发平台:

C++ Builder

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