# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

logic_state_machine.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 #include "nel/logic/logic_state_machine.h"
00028 
00029 #include "nel/net/service.h"
00030 
00031 using namespace std;
00032 using namespace NLMISC;
00033 using namespace NLNET;
00034 
00035 namespace NLLOGIC
00036 {
00037 
00038 // test if a string is valid considering a filter and a motif
00039 bool testNameWithFilter( sint8 filter, string motif, string varName );
00040 
00041 void xmlCheckNodeName (xmlNodePtr &node, const char *nodeName)
00042 {
00043         // Check node name
00044         if ( node == NULL || ((const char*)node->name == NULL) || (strcmp ((const char*)node->name, nodeName) != 0) )
00045         {
00046 
00047                 // try to find a child
00048                 if (node != NULL)
00049                 {
00050                         node = CIXml::getFirstChildNode (node, nodeName);
00051                         if ( node != NULL && ((const char*)node->name != NULL) && (strcmp ((const char*)node->name, nodeName) == 0) )
00052                         {
00053                                 nlinfo ("check node %s ok in the child", nodeName);
00054                                 return;
00055                         }
00056                 }
00057 
00058                 // Make an error message
00059                 char tmp[512];
00060                 smprintf (tmp, 512, "LogicStateMachine STATE_MACHINE XML Syntax error in block line %d, node %s should be %s", 
00061                         (int)node->content, node->name, nodeName);
00062                 
00063                 nlinfo (tmp);
00064                 nlstop;
00065                 throw EXmlParsingError (tmp);
00066         }
00067 
00068         nlinfo ("check node %s ok", nodeName);
00069 }
00070 
00071 std::string getXMLProp (xmlNodePtr node, const char *propName)
00072 {
00073         const char *name = (const char*)xmlGetProp (node, (xmlChar*)propName);
00074         if (name)
00075         {
00076                 nlinfo ("get prop %s = %s", propName, name);
00077                 string n = name;
00078                 xmlFree ((void*)name);
00079                 return n;
00080         }
00081         else
00082         {
00083                 // Make an error message
00084                 char tmp[512];
00085                 smprintf (tmp, 512, "LogicStateMachine XML Syntax error in block %s line %d, aguments Name not found", 
00086                         node->name, (int)node->content);
00087                 throw EXmlParsingError (tmp);
00088                 return "";
00089         }
00090 }
00091 
00092 
00093 //---------------------------------------------------
00094 // setCurrentState :
00095 // 
00096 //---------------------------------------------------
00097 void CLogicStateMachine::setCurrentState( string stateName )
00098 {
00099         map<string,CLogicState>::iterator itStates = _States.find( stateName );
00100         if( itStates != _States.end() )
00101         {
00102                 (*itStates).second.exitState();
00103         
00104                 _CurrentState = stateName;
00105 
00106                 (*itStates).second.enterState();
00107 
00108                 nlinfo("Switching to state \"%s\"",_CurrentState.c_str());
00109         }
00110         else
00111         {
00112                 nlwarning("(LOGIC)<CLogicStateMachine::setCurrentState> The state \"%s\" is not in the state machine \"%s\"",stateName.c_str(),_Name.c_str());
00113         }
00114 
00115 } // setCurrentState //
00116 
00117 
00118 
00119 //---------------------------------------------------
00120 // addCondition :
00121 // 
00122 //---------------------------------------------------
00123 void CLogicStateMachine::addCondition( CLogicCondition condition ) 
00124 { 
00125         condition.setLogicStateMachine(this);
00126         _Conditions.insert(make_pair(condition.getName(),condition)); 
00127 
00128 } // addCondition //
00129 
00130 
00131 
00132 //---------------------------------------------------
00133 // addState :
00134 // 
00135 //---------------------------------------------------
00136 void CLogicStateMachine::addState( CLogicState logicState ) 
00137 {
00138         logicState.setLogicStateMachine( this );
00139         _States.insert( std::make_pair(logicState.getName(),logicState) );
00140         
00141 } // addState //
00142 
00143 
00144 
00145 
00146 //---------------------------------------------------
00147 // addSIdMap :
00148 // 
00149 //---------------------------------------------------
00150 void CLogicStateMachine::addSIdMap( const TSIdMap& sIdMap )
00151 {
00152         // call addSIdMap for each state
00153         map<string,CLogicState>::iterator itStates;
00154         for( itStates = _States.begin(); itStates != _States.end(); ++itStates )
00155         {
00156                 (*itStates).second.addSIdMap( sIdMap );
00157         }
00158 
00159 } // addSIdMap //
00160 
00161 
00162 
00163 //---------------------------------------------------
00164 // processLogic :
00165 // 
00166 //---------------------------------------------------
00167 void CLogicStateMachine::processLogic()
00168 {       
00169         // call processLogic for the current state
00170         map<string,CLogicState>::iterator itStates = _States.find( _CurrentState );
00171         nlassert( itStates != _States.end() )
00172         (*itStates).second.processLogic();
00173 
00174         // update the counters
00175         map<string,CLogicCounter>::iterator itCount;
00176         for( itCount = _Counters.begin(); itCount != _Counters.end(); ++itCount )
00177         {
00178                 (*itCount).second.update();
00179         }
00180         
00181 } // processLogic //
00182 
00183 
00184 
00185 //---------------------------------------------------
00186 // getMessagesToSend :
00187 // 
00188 //---------------------------------------------------
00189 void CLogicStateMachine::getMessagesToSend( multimap<CEntityId,CMessage>& msgs )
00190 {
00191         map<std::string, CLogicState>::iterator itState;
00192         for( itState = _States.begin(); itState != _States.end(); ++itState )
00193         {
00194                 (*itState).second.getMessagesToSend( msgs );
00195         }       
00196         
00197 } // getMessagesToSend //
00198 
00199 
00200 
00201 
00202 //---------------------------------------------------
00203 // getVariable :
00204 // 
00205 //---------------------------------------------------
00206 bool CLogicStateMachine::getVariable( std::string& varName, CLogicVariable& var )
00207 {
00208         map<string,CLogicVariable>::iterator itVar = _Variables.find( varName );
00209         if( itVar != _Variables.end() )
00210         {
00211                 var = (*itVar).second;
00212                 return true;
00213         }
00214 
00215         map<string,CLogicCounter>::iterator itCount = _Counters.find( varName );
00216         if( itCount != _Counters.end() )
00217         {
00218                 var = (*itCount).second;
00219                 return true;
00220         }
00221         
00222         return false;
00223 
00224 } // getVariable //
00225 
00226 
00227 
00228 //---------------------------------------------------
00229 // getCondition :
00230 // 
00231 //---------------------------------------------------
00232 bool CLogicStateMachine::getCondition( const std::string& condName, CLogicCondition& cond )
00233 {
00234         map<string,CLogicCondition>::iterator itCond = _Conditions.find( condName );
00235         if( itCond != _Conditions.end() )
00236         {
00237                 cond = (*itCond).second;
00238                 return true;
00239         }
00240         else
00241         { 
00242                 return false;
00243         }
00244 
00245 } // getCondition //
00246 
00247 
00248 //---------------------------------------------------
00249 // modifyVariable :
00250 // 
00251 //---------------------------------------------------
00252 void CLogicStateMachine::modifyVariable( string varName, string modifOperator, sint64 value )
00253 {
00254         map<string,CLogicVariable>::iterator itVar = _Variables.find( varName );
00255         if( itVar != _Variables.end() )
00256         {
00257                 (*itVar).second.applyModification( modifOperator, value );
00258                 return;
00259         }
00260         map<string,CLogicCounter>::iterator itCount = _Counters.find( varName );
00261         if( itCount != _Counters.end() )
00262         {
00263                 (*itCount).second.applyModification( modifOperator, value );
00264                 return;
00265         }
00266 
00267         nlwarning("(LOGIC)<CLogicStateMachine::modifyVariable> The variable \"%s\" is not in the state machine \"%s\"",varName.c_str(),_Name.c_str());
00268 
00269 } // modifyVariable //
00270 
00271 
00272 
00273 //---------------------------------------------------
00274 // serial :
00275 // 
00276 //---------------------------------------------------
00277 /*void CLogicStateMachine::serial( IStream &f )
00278 {
00279         f.xmlPush("STATE_MACHINE");
00280 
00281         
00282         f.serialCont( _Variables );
00283         f.serialCont( _Counters );
00284         f.serialCont( _Conditions );
00285         f.serialCont( _States );
00286         f.serial( _CurrentState );
00287         f.serial( _Name );
00288         
00289         if( f.isReading() )
00290         {
00291                 // set the the logic state machine addr in each state
00292                 map<string,CLogicState>::iterator itStates;
00293                 for( itStates = _States.begin(); itStates != _States.end(); ++itStates )
00294                 {
00295                         (*itStates).second.setLogicStateMachine( this );
00296                 }
00297 
00298                 // set the the logic state machine addr in each conditions
00299                 map<string,CLogicCondition>::iterator itCond;
00300                 for( itCond = _Conditions.begin(); itCond != _Conditions.end(); ++itCond )
00301                 {
00302                         (*itCond).second.setLogicStateMachine( this );
00303                 }
00304         }
00305         
00306         f.xmlPop();
00307 
00308 } // serial //*/
00309 
00310 
00311 //---------------------------------------------------
00312 //      Display the variables
00313 //
00314 //---------------------------------------------------
00315 void CLogicStateMachine::displayVariables()
00316 {
00317         multimap<CEntityId,string> allVariables;
00318         
00319         // // get vars referenced in the states
00320         map<string, CLogicState>::iterator itS;
00321         for( itS = _States.begin(); itS != _States.end(); ++itS )
00322         {
00323                 (*itS).second.fillVarMap( allVariables );
00324         }
00325 
00326         // extract the unclaimed variables from all the variables
00327         vector<string> unclaimedVariables;
00328         CEntityId unknown;
00329         unknown.setType( 0xfe );
00330         unknown.setCreatorId( 0 );
00331         unknown.setDynamicId( 0 );
00332         pair<multimap<CEntityId,string>::iterator,multimap<CEntityId,string>::iterator> itVarsRng = allVariables.equal_range(unknown);
00333         multimap<CEntityId,string>::iterator itVars;
00334         
00335         for( itVars = itVarsRng.first; itVars != itVarsRng.second; )
00336         {
00337                 multimap<CEntityId,string>::iterator itDel = itVars++;
00338                 unclaimedVariables.push_back( (*itDel).second );
00339                 allVariables.erase( itDel );
00340         }
00341         /*
00342         if( itVarsRng.first != allVariables.end() )
00343         {
00344                 itVars = itVarsRng.first;
00345                 do
00346                 {
00347                         multimap<CEntityId,string>::iterator itDel = itVars++;
00348                         unclaimedVariables.push_back( (*itDel).second );
00349                         allVariables.erase( itDel );
00350                 }
00351                 while( itVars != itVarsRng.second );
00352         }
00353         */
00354 
00355 
00356         nlinfo("VARIABLES/COUNTERS in %s : %d/%d are registered : ",_Name.c_str(),allVariables.size(),allVariables.size()+unclaimedVariables.size());
00357         // display the registered variables
00358         for( itVars = allVariables.begin(); itVars != allVariables.end(); ++itVars )
00359         {
00360                 map<string, CLogicVariable>::const_iterator itV = _Variables.find( (*itVars).second );
00361                 nlinfo("[%d] %s = %f",(uint8)(*itVars).first.getDynamicId(),(*itV).first.c_str(),(double)(*itV).second.getValue());
00362         }
00363 
00364         // display the unclaimed variables
00365         sort( unclaimedVariables.begin(), unclaimedVariables.end() );
00366         vector<string>::iterator itUV;
00367         for( itUV = unclaimedVariables.begin(); itUV != unclaimedVariables.end(); ++itUV )
00368         {
00369                 map<string, CLogicVariable>::const_iterator itV = _Variables.find( *itUV );
00370                 nlinfo("(-)%s = %f",(*itV).first.c_str(),(double)(*itV).second.getValue());
00371         }
00372         
00373 } // displayVariables //
00374 
00375 
00376 //---------------------------------------------------
00377 //      Display the states
00378 //
00379 //---------------------------------------------------
00380 void CLogicStateMachine::displayStates()
00381 {
00382         nlinfo("There are %d STATES in the state machine \"%s\": ",_States.size(),_Name.c_str());
00383         map<string, CLogicState>::const_iterator itS;
00384         for( itS = _States.begin(); itS != _States.end(); ++itS )
00385         {
00386                 nlinfo("%s",(*itS).first.c_str());
00387         }
00388         nlinfo("The current state is : \"%s\"",_CurrentState.c_str());
00389 
00390 } // displayStates //
00391 
00392 
00393 //---------------------------------------------------
00394 //      Set the verbose mode for the variable
00395 //
00396 //---------------------------------------------------
00397 void CLogicStateMachine::setVerbose( string varName, bool b )
00398 {
00399         if( varName == "all" )
00400         {
00401                 map<string, CLogicVariable>::iterator itV;
00402                 for( itV = _Variables.begin(); itV != _Variables.end(); ++itV )
00403                 {
00404                         (*itV).second.setVerbose( b );
00405                 }
00406                 map<string, CLogicCounter>::iterator itC;
00407                 for( itC = _Counters.begin(); itC != _Counters.end(); ++itC )
00408                 {
00409                         (*itC).second.setVerbose( b );
00410                 }
00411                 if(b)
00412                 {
00413                         nlinfo("the verbose mode has been activated for all the variables",varName.c_str());
00414                 }
00415                 else
00416                 {
00417                         nlinfo("the verbose mode has been desactivated for all the variables",varName.c_str());
00418                 }
00419                 return;
00420         }
00421         
00422         sint8 filter = -1;
00423         string motif;
00424         // *xxx* => we look for a string with xxx inside
00425         if( varName[0]=='*' && varName[varName.size()-1]=='*') 
00426         {
00427                 motif = varName.substr(1,varName.size()-2);
00428                 filter = 0;
00429         }
00430         else
00431         // *xxx => we look for a string with xxx at the end
00432         if( varName[0]=='*' ) 
00433         {
00434                 motif = varName.substr(1,varName.size()-1);
00435                 filter = 1;
00436         }
00437         else
00438         // xxx* => we look for a string with xxx at the begining
00439         if( varName[varName.size()-1]=='*' ) 
00440         {
00441                 motif = varName.substr(0,varName.size()-1);
00442                 filter = 2;
00443         }
00444 
00445         // if no filter
00446         if( filter == -1 )
00447         {
00448                 map<string, CLogicVariable>::iterator itV = _Variables.find( varName );
00449                 if( itV != _Variables.end() )
00450                 {
00451                         (*itV).second.setVerbose( b );
00452                 }
00453                 map<string, CLogicCounter>::iterator itC = _Counters.find( varName );
00454                 if( itC != _Counters.end() || varName =="all" )
00455                 {
00456                         (*itC).second.setVerbose( b );
00457                 }
00458         }
00459         // if filter
00460         else
00461         {
00462                 map<string, CLogicVariable>::iterator itV;
00463                 for( itV = _Variables.begin(); itV != _Variables.end(); ++itV )
00464                 {
00465                         if( testNameWithFilter( filter, motif,(*itV).second.getName()) )
00466                         {
00467                                 (*itV).second.setVerbose( b );
00468                         }
00469                 }
00470                 map<string, CLogicCounter>::iterator itC;
00471                 for( itC = _Counters.begin(); itC != _Counters.end(); ++itC )
00472                 {
00473                         if( testNameWithFilter( filter, motif,(*itC).second.getName()) )
00474                         {
00475                                 (*itC).second.setVerbose( b );
00476                         }
00477                 }
00478         }
00479         if(b)
00480         {
00481                 nlinfo("the verbose mode for variable \"%s\" has been activated",varName.c_str());
00482         }
00483         else
00484         {
00485                 nlinfo("the verbose mode for variable \"%s\" has been desactivated",varName.c_str());
00486         }
00487         
00488 } // setVerbose //
00489 
00490 
00491 
00492 //---------------------------------------------------
00493 //      testNameWithFilter :
00494 //
00495 //---------------------------------------------------
00496 bool testNameWithFilter( sint8 filter, string motif, string varName )
00497 {
00498         if( varName.size() > motif.size() )
00499         {
00500                 switch( filter )
00501                 {
00502                         // *xxx*
00503                         case 0 :
00504                         {
00505                                 if(varName.find(motif) != -1)
00506                                 {
00507                                         return true;
00508                                 }
00509                         }
00510                         break;
00511 
00512                         // *xxx
00513                         case 1 :
00514                         {
00515                                 sint beginIndex = varName.size() - motif.size() - 1;
00516                                 string endOfVarName = varName.substr(beginIndex,motif.size());
00517                                 if( endOfVarName == motif )
00518                                 {
00519                                         return true;
00520                                 }
00521                         }
00522                         break;
00523         
00524                         // xxx*
00525                         case 2 :
00526                         {
00527                                 string beginOfVarName = varName.substr(0,motif.size());
00528                                 if( beginOfVarName == motif )
00529                                 {
00530                                         return true;
00531                                 }
00532                         }
00533                         break;
00534                 }
00535         }
00536 
00537         return false;
00538 
00539 } // testNameWithFilter //
00540 
00541 void CLogicStateMachine::write (xmlDocPtr doc) const
00542 {
00543         // Create the first node
00544         xmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)"STATE_MACHINE", NULL);
00545         xmlDocSetRootElement (doc, node);
00546         xmlSetProp (node, (const xmlChar*)"Name", (const xmlChar*)_Name.c_str());
00547         xmlSetProp (node, (const xmlChar*)"CurrentState", (const xmlChar*)_CurrentState.c_str());
00548 
00549         for (std::map<std::string, CLogicVariable>::const_iterator vit = _Variables.begin(); vit != _Variables.end(); vit++)
00550         {
00551                 (*vit).second.write(node);
00552         }
00553 
00554         for (std::map<std::string, CLogicCounter>::const_iterator cit = _Counters.begin(); cit != _Counters.end(); cit++)
00555         {
00556                 (*cit).second.write(node);
00557         }
00558 
00559         for (std::map<std::string, CLogicCondition>::const_iterator c2it = _Conditions.begin(); c2it != _Conditions.end(); c2it++)
00560         {
00561                 (*c2it).second.write(node);
00562         }
00563         
00564         for (std::map<std::string, CLogicState>::const_iterator sit = _States.begin(); sit != _States.end(); sit++)
00565         {
00566                 (*sit).second.write(node);
00567         }
00568 }
00569 
00570 void CLogicStateMachine::read (xmlNodePtr node)
00571 {
00572         xmlCheckNodeName (node, "STATE_MACHINE");
00573 
00574         setName (getXMLProp (node, "Name"));
00575 
00576         {
00577                 // Count the parent
00578                 uint nb = CIXml::countChildren (node, "VARIABLE");
00579                 uint i = 0;
00580                 xmlNodePtr parent = CIXml::getFirstChildNode (node, "VARIABLE");
00581                 while (i<nb)
00582                 {
00583                         CLogicVariable v;
00584                         v.read(parent);
00585                         _Variables.insert (make_pair(v.getName(), v));
00586 
00587                         // Next parent
00588                         parent = CIXml::getNextChildNode (parent, "VARIABLE");
00589                         i++;
00590                 }
00591         }
00592 
00593         {
00594                 // Count the parent
00595                 uint nb = CIXml::countChildren (node, "COUNTER");
00596                 uint i = 0;
00597                 xmlNodePtr parent = CIXml::getFirstChildNode (node, "COUNTER");
00598                 while (i<nb)
00599                 {
00600                         CLogicCounter v;
00601                         v.read(parent);
00602                         _Counters.insert (make_pair(v.getName(), v));
00603 
00604                         // Next parent
00605                         parent = CIXml::getNextChildNode (parent, "COUNTER");
00606                         i++;
00607                 }
00608         }
00609 
00610         {
00611                 // Count the parent
00612                 uint nb = CIXml::countChildren (node, "CONDITION");
00613                 uint i = 0;
00614                 xmlNodePtr parent = CIXml::getFirstChildNode (node, "CONDITION");
00615                 while (i<nb)
00616                 {
00617                         CLogicCondition v;
00618                         v.read(parent);
00619                         _Conditions.insert (make_pair(v.getName(), v));
00620 
00621                         // Next parent
00622                         parent = CIXml::getNextChildNode (parent, "CONDITION");
00623                         i++;
00624                 }
00625         }
00626 
00627         {
00628                 // Count the parent
00629                 uint nb = CIXml::countChildren (node, "STATE");
00630                 uint i = 0;
00631                 xmlNodePtr parent = CIXml::getFirstChildNode (node, "STATE");
00632                 while (i<nb)
00633                 {
00634                         CLogicState v;
00635                         v.read(parent);
00636                         _States.insert (make_pair(v.getName(), v));
00637 
00638                         // Next parent
00639                         parent = CIXml::getNextChildNode (parent, "STATE");
00640                         i++;
00641                 }
00642         }
00643 
00644         setCurrentState (getXMLProp (node, "CurrentState"));
00645 }
00646 
00647 } // NLLOGIC