Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / logic / logic_state_machine.cpp
blob0492671f62283c925751cf60fa0bad6b47192e53
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdlogic.h"
22 #include "nel/logic/logic_state_machine.h"
24 #include "nel/net/service.h"
26 using namespace std;
27 using namespace NLMISC;
28 using namespace NLNET;
30 namespace NLLOGIC
33 // test if a string is valid considering a filter and a motif
34 bool testNameWithFilter( sint8 filter, string motif, string varName );
36 void xmlCheckNodeName (xmlNodePtr &node, const char *nodeName)
38 // Check node name
39 if ( node == NULL || ((const char*)node->name == NULL) || (strcmp ((const char*)node->name, nodeName) != 0) )
42 // try to find a child
43 if (node != NULL)
45 node = CIXml::getFirstChildNode (node, nodeName);
46 if ( node != NULL && ((const char*)node->name != NULL) && (strcmp ((const char*)node->name, nodeName) == 0) )
48 nlinfo ("check node %s ok in the child", nodeName);
49 return;
53 // Make an error message
54 char tmp[512];
55 smprintf (tmp, 512, "LogicStateMachine STATE_MACHINE XML Syntax error in block line %d, node %s should be %s",
56 node ? (int)node->line:-1, node ? (const char *)node->name : "NULL", nodeName);
58 nlinfo (tmp);
59 nlstop;
60 throw EXmlParsingError (tmp);
63 nlinfo ("check node %s ok", nodeName);
66 std::string getXMLProp (xmlNodePtr node, const char *propName)
68 const char *name = (const char*)xmlGetProp (node, (xmlChar*)propName);
69 if (name)
71 nlinfo ("get prop %s = %s", propName, name);
72 string n = name;
73 xmlFree ((void*)name);
74 return n;
76 else
78 // Make an error message
79 char tmp[512];
80 smprintf (tmp, 512, "LogicStateMachine XML Syntax error in block %s line %d, aguments Name not found",
81 node->name, (int)node->line);
82 throw EXmlParsingError (tmp);
83 return "";
88 //---------------------------------------------------
89 // setCurrentState :
91 //---------------------------------------------------
92 void CLogicStateMachine::setCurrentState( string stateName )
94 map<string,CLogicState>::iterator itStates = _States.find( stateName );
95 if( itStates != _States.end() )
97 (*itStates).second.exitState();
99 _CurrentState = stateName;
101 (*itStates).second.enterState();
103 nlinfo("Switching to state \"%s\"",_CurrentState.c_str());
105 else
107 nlwarning("(LOGIC)<CLogicStateMachine::setCurrentState> The state \"%s\" is not in the state machine \"%s\"",stateName.c_str(),_Name.c_str());
110 } // setCurrentState //
114 //---------------------------------------------------
115 // addCondition :
117 //---------------------------------------------------
118 void CLogicStateMachine::addCondition( CLogicCondition condition )
120 condition.setLogicStateMachine(this);
121 _Conditions.insert(make_pair(condition.getName(),condition));
123 } // addCondition //
127 //---------------------------------------------------
128 // addState :
130 //---------------------------------------------------
131 void CLogicStateMachine::addState( CLogicState logicState )
133 logicState.setLogicStateMachine( this );
134 _States.insert( std::make_pair(logicState.getName(),logicState) );
136 } // addState //
141 //---------------------------------------------------
142 // addSIdMap :
144 //---------------------------------------------------
145 void CLogicStateMachine::addSIdMap( const TSIdMap& sIdMap )
147 // call addSIdMap for each state
148 map<string,CLogicState>::iterator itStates;
149 for( itStates = _States.begin(); itStates != _States.end(); ++itStates )
151 (*itStates).second.addSIdMap( sIdMap );
154 } // addSIdMap //
158 //---------------------------------------------------
159 // processLogic :
161 //---------------------------------------------------
162 void CLogicStateMachine::processLogic()
164 // call processLogic for the current state
165 map<string,CLogicState>::iterator itStates = _States.find( _CurrentState );
166 nlassert( itStates != _States.end() );
167 (*itStates).second.processLogic();
169 // update the counters
170 map<string,CLogicCounter>::iterator itCount;
171 for( itCount = _Counters.begin(); itCount != _Counters.end(); ++itCount )
173 (*itCount).second.update();
176 } // processLogic //
180 //---------------------------------------------------
181 // getMessagesToSend :
183 //---------------------------------------------------
184 void CLogicStateMachine::getMessagesToSend( multimap<CEntityId,CMessage>& msgs )
186 map<std::string, CLogicState>::iterator itState;
187 for( itState = _States.begin(); itState != _States.end(); ++itState )
189 (*itState).second.getMessagesToSend( msgs );
192 } // getMessagesToSend //
197 //---------------------------------------------------
198 // getVariable :
200 //---------------------------------------------------
201 bool CLogicStateMachine::getVariable( std::string& varName, CLogicVariable& var )
203 map<string,CLogicVariable>::iterator itVar = _Variables.find( varName );
204 if( itVar != _Variables.end() )
206 var = (*itVar).second;
207 return true;
210 map<string,CLogicCounter>::iterator itCount = _Counters.find( varName );
211 if( itCount != _Counters.end() )
213 var = (*itCount).second;
214 return true;
217 return false;
219 } // getVariable //
223 //---------------------------------------------------
224 // getCondition :
226 //---------------------------------------------------
227 bool CLogicStateMachine::getCondition( const std::string& condName, CLogicCondition& cond )
229 map<string,CLogicCondition>::iterator itCond = _Conditions.find( condName );
230 if( itCond != _Conditions.end() )
232 cond = (*itCond).second;
233 return true;
235 else
237 return false;
240 } // getCondition //
243 //---------------------------------------------------
244 // modifyVariable :
246 //---------------------------------------------------
247 void CLogicStateMachine::modifyVariable( string varName, string modifOperator, sint64 value )
249 map<string,CLogicVariable>::iterator itVar = _Variables.find( varName );
250 if( itVar != _Variables.end() )
252 (*itVar).second.applyModification( modifOperator, value );
253 return;
255 map<string,CLogicCounter>::iterator itCount = _Counters.find( varName );
256 if( itCount != _Counters.end() )
258 (*itCount).second.applyModification( modifOperator, value );
259 return;
262 nlwarning("(LOGIC)<CLogicStateMachine::modifyVariable> The variable \"%s\" is not in the state machine \"%s\"",varName.c_str(),_Name.c_str());
264 } // modifyVariable //
268 //---------------------------------------------------
269 // serial :
271 //---------------------------------------------------
272 /*void CLogicStateMachine::serial( IStream &f )
274 f.xmlPush("STATE_MACHINE");
277 f.serialCont( _Variables );
278 f.serialCont( _Counters );
279 f.serialCont( _Conditions );
280 f.serialCont( _States );
281 f.serial( _CurrentState );
282 f.serial( _Name );
284 if( f.isReading() )
286 // set the logic state machine addr in each state
287 map<string,CLogicState>::iterator itStates;
288 for( itStates = _States.begin(); itStates != _States.end(); ++itStates )
290 (*itStates).second.setLogicStateMachine( this );
293 // set the logic state machine addr in each conditions
294 map<string,CLogicCondition>::iterator itCond;
295 for( itCond = _Conditions.begin(); itCond != _Conditions.end(); ++itCond )
297 (*itCond).second.setLogicStateMachine( this );
301 f.xmlPop();
303 } // serial //*/
306 //---------------------------------------------------
307 // Display the variables
309 //---------------------------------------------------
310 void CLogicStateMachine::displayVariables()
312 multimap<CEntityId,string> allVariables;
314 // // get vars referenced in the states
315 map<string, CLogicState>::iterator itS;
316 for( itS = _States.begin(); itS != _States.end(); ++itS )
318 (*itS).second.fillVarMap( allVariables );
321 // extract the unclaimed variables from all the variables
322 vector<string> unclaimedVariables;
323 CEntityId unknown;
324 unknown.setType( 0xfe );
325 unknown.setCreatorId( 0 );
326 unknown.setDynamicId( 0 );
327 pair<multimap<CEntityId,string>::iterator,multimap<CEntityId,string>::iterator> itVarsRng = allVariables.equal_range(unknown);
328 multimap<CEntityId,string>::iterator itVars;
330 for( itVars = itVarsRng.first; itVars != itVarsRng.second; )
332 multimap<CEntityId,string>::iterator itDel = itVars++;
333 unclaimedVariables.push_back( (*itDel).second );
334 allVariables.erase( itDel );
337 if( itVarsRng.first != allVariables.end() )
339 itVars = itVarsRng.first;
342 multimap<CEntityId,string>::iterator itDel = itVars++;
343 unclaimedVariables.push_back( (*itDel).second );
344 allVariables.erase( itDel );
346 while( itVars != itVarsRng.second );
351 nlinfo("VARIABLES/COUNTERS in %s : %d/%d are registered : ",_Name.c_str(),allVariables.size(),allVariables.size()+unclaimedVariables.size());
352 // display the registered variables
353 for( itVars = allVariables.begin(); itVars != allVariables.end(); ++itVars )
355 map<string, CLogicVariable>::const_iterator itV = _Variables.find( (*itVars).second );
356 nlinfo("[%d] %s = %f",(uint8)(*itVars).first.getDynamicId(),(*itV).first.c_str(),(double)(*itV).second.getValue());
359 // display the unclaimed variables
360 sort( unclaimedVariables.begin(), unclaimedVariables.end() );
361 vector<string>::iterator itUV;
362 for( itUV = unclaimedVariables.begin(); itUV != unclaimedVariables.end(); ++itUV )
364 map<string, CLogicVariable>::const_iterator itV = _Variables.find( *itUV );
365 nlinfo("(-)%s = %f",(*itV).first.c_str(),(double)(*itV).second.getValue());
368 } // displayVariables //
371 //---------------------------------------------------
372 // Display the states
374 //---------------------------------------------------
375 void CLogicStateMachine::displayStates()
377 nlinfo("There are %d STATES in the state machine \"%s\": ",_States.size(),_Name.c_str());
378 map<string, CLogicState>::const_iterator itS;
379 for( itS = _States.begin(); itS != _States.end(); ++itS )
381 nlinfo("%s",(*itS).first.c_str());
383 nlinfo("The current state is : \"%s\"",_CurrentState.c_str());
385 } // displayStates //
388 //---------------------------------------------------
389 // Set the verbose mode for the variable
391 //---------------------------------------------------
392 void CLogicStateMachine::setVerbose( string varName, bool b )
394 if( varName == "all" )
396 map<string, CLogicVariable>::iterator itV;
397 for( itV = _Variables.begin(); itV != _Variables.end(); ++itV )
399 (*itV).second.setVerbose( b );
401 map<string, CLogicCounter>::iterator itC;
402 for( itC = _Counters.begin(); itC != _Counters.end(); ++itC )
404 (*itC).second.setVerbose( b );
406 if(b)
408 nlinfo("the verbose mode has been activated for all the variables",varName.c_str());
410 else
412 nlinfo("the verbose mode has been desactivated for all the variables",varName.c_str());
414 return;
417 sint8 filter = -1;
418 string motif;
419 // *xxx* => we look for a string with xxx inside
420 if( varName[0]=='*' && varName[varName.size()-1]=='*')
422 motif = varName.substr(1,varName.size()-2);
423 filter = 0;
425 else
426 // *xxx => we look for a string with xxx at the end
427 if( varName[0]=='*' )
429 motif = varName.substr(1,varName.size()-1);
430 filter = 1;
432 else
433 // xxx* => we look for a string with xxx at the beginning
434 if( varName[varName.size()-1]=='*' )
436 motif = varName.substr(0,varName.size()-1);
437 filter = 2;
440 // if no filter
441 if( filter == -1 )
443 map<string, CLogicVariable>::iterator itV = _Variables.find( varName );
444 if( itV != _Variables.end() )
446 (*itV).second.setVerbose( b );
448 map<string, CLogicCounter>::iterator itC = _Counters.find( varName );
449 if( itC != _Counters.end() || varName =="all" )
451 (*itC).second.setVerbose( b );
454 // if filter
455 else
457 map<string, CLogicVariable>::iterator itV;
458 for( itV = _Variables.begin(); itV != _Variables.end(); ++itV )
460 if( testNameWithFilter( filter, motif,(*itV).second.getName()) )
462 (*itV).second.setVerbose( b );
465 map<string, CLogicCounter>::iterator itC;
466 for( itC = _Counters.begin(); itC != _Counters.end(); ++itC )
468 if( testNameWithFilter( filter, motif,(*itC).second.getName()) )
470 (*itC).second.setVerbose( b );
474 if(b)
476 nlinfo("the verbose mode for variable \"%s\" has been activated",varName.c_str());
478 else
480 nlinfo("the verbose mode for variable \"%s\" has been desactivated",varName.c_str());
483 } // setVerbose //
487 //---------------------------------------------------
488 // testNameWithFilter :
490 //---------------------------------------------------
491 bool testNameWithFilter( sint8 filter, string motif, string varName )
493 if( varName.size() > motif.size() )
495 switch( filter )
497 // *xxx*
498 case 0 :
500 if(varName.find(motif) != string::npos)
502 return true;
505 break;
507 // *xxx
508 case 1 :
510 sint beginIndex = (sint)(varName.size() - motif.size() - 1);
511 string endOfVarName = varName.substr(beginIndex,motif.size());
512 if( endOfVarName == motif )
514 return true;
517 break;
519 // xxx*
520 case 2 :
522 string beginOfVarName = varName.substr(0,motif.size());
523 if( beginOfVarName == motif )
525 return true;
528 break;
532 return false;
534 } // testNameWithFilter //
536 void CLogicStateMachine::write (xmlDocPtr doc) const
538 // Create the first node
539 xmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)"STATE_MACHINE", NULL);
540 xmlDocSetRootElement (doc, node);
541 xmlSetProp (node, (const xmlChar*)"Name", (const xmlChar*)_Name.c_str());
542 xmlSetProp (node, (const xmlChar*)"CurrentState", (const xmlChar*)_CurrentState.c_str());
544 for (std::map<std::string, CLogicVariable>::const_iterator vit = _Variables.begin(); vit != _Variables.end(); vit++)
546 (*vit).second.write(node);
549 for (std::map<std::string, CLogicCounter>::const_iterator cit = _Counters.begin(); cit != _Counters.end(); cit++)
551 (*cit).second.write(node);
554 for (std::map<std::string, CLogicCondition>::const_iterator c2it = _Conditions.begin(); c2it != _Conditions.end(); c2it++)
556 (*c2it).second.write(node);
559 for (std::map<std::string, CLogicState>::const_iterator sit = _States.begin(); sit != _States.end(); sit++)
561 (*sit).second.write(node);
565 void CLogicStateMachine::read (xmlNodePtr node)
567 xmlCheckNodeName (node, "STATE_MACHINE");
569 setName (getXMLProp (node, "Name"));
572 // Count the parent
573 uint nb = CIXml::countChildren (node, "VARIABLE");
574 uint i = 0;
575 xmlNodePtr parent = CIXml::getFirstChildNode (node, "VARIABLE");
576 while (i<nb)
578 CLogicVariable v;
579 v.read(parent);
580 _Variables.insert (make_pair(v.getName(), v));
582 // Next parent
583 parent = CIXml::getNextChildNode (parent, "VARIABLE");
584 i++;
589 // Count the parent
590 uint nb = CIXml::countChildren (node, "COUNTER");
591 uint i = 0;
592 xmlNodePtr parent = CIXml::getFirstChildNode (node, "COUNTER");
593 while (i<nb)
595 CLogicCounter v;
596 v.read(parent);
597 _Counters.insert (make_pair(v.getName(), v));
599 // Next parent
600 parent = CIXml::getNextChildNode (parent, "COUNTER");
601 i++;
606 // Count the parent
607 uint nb = CIXml::countChildren (node, "CONDITION");
608 uint i = 0;
609 xmlNodePtr parent = CIXml::getFirstChildNode (node, "CONDITION");
610 while (i<nb)
612 CLogicCondition v;
613 v.read(parent);
614 _Conditions.insert (make_pair(v.getName(), v));
616 // Next parent
617 parent = CIXml::getNextChildNode (parent, "CONDITION");
618 i++;
623 // Count the parent
624 uint nb = CIXml::countChildren (node, "STATE");
625 uint i = 0;
626 xmlNodePtr parent = CIXml::getFirstChildNode (node, "STATE");
627 while (i<nb)
629 CLogicState v;
630 v.read(parent);
631 _States.insert (make_pair(v.getName(), v));
633 // Next parent
634 parent = CIXml::getNextChildNode (parent, "STATE");
635 i++;
639 setCurrentState (getXMLProp (node, "CurrentState"));
642 } // NLLOGIC