1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/logic/logic_state.h"
20 #include "nel/logic/logic_state_machine.h"
24 using namespace NLMISC
;
25 using namespace NLNET
;
30 //---------------------------------------------------
33 //---------------------------------------------------
34 CLogicState::CLogicState()
36 _StateName
= "no_state";
37 _LogicStateMachine
= 0;
42 //---------------------------------------------------
43 // setLogicStateMachine
45 //---------------------------------------------------
46 void CLogicState::setLogicStateMachine( CLogicStateMachine
* logicStateMachine
)
48 if( logicStateMachine
== 0 )
50 nlwarning("(LOGIC)<CLogicCondition::setLogicStateMachine> The state machine is null");
54 // init the logic state machine for this state
55 _LogicStateMachine
= logicStateMachine
;
57 // init the logic state machine in each event
58 vector
<CLogicEvent
>::iterator itEvent
;
59 for( itEvent
= _Events
.begin(); itEvent
!= _Events
.end(); ++itEvent
)
61 (*itEvent
).setLogicStateMachine( logicStateMachine
);
65 } // setLogicStateMachine //
69 //---------------------------------------------------
72 //---------------------------------------------------
73 void CLogicState::addEvent( CLogicEvent event
)
75 event
.setLogicStateMachine( _LogicStateMachine
);
76 _Events
.push_back( event
);
82 //---------------------------------------------------
85 // looks in all the messages of the state if the
86 // destination names can be associated with a sid.
87 //---------------------------------------------------
88 void CLogicState::addSIdMap( const TSIdMap
& sIdMap
)
90 vector
<CLogicEventMessage
>::iterator itMsg
;
93 for( itMsg
= _EntryMessages
.begin(); itMsg
!= _EntryMessages
.end(); ++itMsg
)
95 TSIdMap::const_iterator itId
= sIdMap
.find( (*itMsg
).Destination
);
96 // if message destination exists in the map we associate the sid with the message
97 if( itId
!= sIdMap
.end() )
99 (*itMsg
).DestinationId
= (*itId
).second
;
102 /// send the entry messages that can be sent
103 trySendEntryMessages();
107 vector
<CLogicEvent
>::iterator itEvt
;
108 for( itEvt
= _Events
.begin(); itEvt
!= _Events
.end(); ++itEvt
)
110 string dest
= (*itEvt
).EventAction
.EventMessage
.Destination
;
111 TSIdMap::const_iterator itId
= sIdMap
.find( dest
);
112 // if message destination exists in the map we associate the sid with the message
113 if( itId
!= sIdMap
.end() )
115 (*itEvt
).EventAction
.EventMessage
.DestinationId
= (*itId
).second
;
118 /// send the event messages that can be sent
119 trySendEventMessages();
123 for( itMsg
= _ExitMessages
.begin(); itMsg
!= _ExitMessages
.end(); ++itMsg
)
125 TSIdMap::const_iterator itId
= sIdMap
.find( (*itMsg
).Destination
);
126 // if message destination exists in the map we associate the sid with the message
127 if( itId
!= sIdMap
.end() )
129 (*itMsg
).DestinationId
= (*itId
).second
;
136 //---------------------------------------------------
139 //---------------------------------------------------
140 void CLogicState::processLogic()
142 // test all conditions managed by this state
143 vector
<CLogicEvent
>::iterator itEvent
;
144 for( itEvent
= _Events
.begin(); itEvent
!= _Events
.end(); ++itEvent
)
146 if( (*itEvent
).testCondition() )
148 //nlinfo("The condition %s is valid",(*itEvent).ConditionName.c_str());
149 if( (*itEvent
).EventAction
.IsStateChange
)
151 _LogicStateMachine
->setCurrentState( (*itEvent
).EventAction
.StateChange
);
155 // this message will be sent as soon as the dest id will be given
156 (*itEvent
).EventAction
.enableSendMessage();
158 /// send the event messages that must and can be sent
159 trySendEventMessages();
164 // reset message send status here to be able to send messages several times in the logic state
165 // --> this has to be done if we want messages to be sent every time the condition becomes verified
172 //---------------------------------------------------
175 //---------------------------------------------------
176 void CLogicState::enterState()
178 /// send the entry messages that can be sent
179 trySendEntryMessages();
184 //---------------------------------------------------
187 //---------------------------------------------------
188 void CLogicState::exitState()
190 vector
<CLogicEventMessage
>::iterator itMsg
;
191 for( itMsg
= _ExitMessages
.begin(); itMsg
!= _ExitMessages
.end(); ++itMsg
)
193 if( (*itMsg
).DestinationId
!= CEntityId() )
195 CMessage
msgOut( (*itMsg
).MessageId
);
196 msgOut
.serial( (*itMsg
).Arguments
);
198 _MessagesToSend
.insert( make_pair((*itMsg
).DestinationId
,msgOut
) );
202 // reset the entry messages send status
203 for( itMsg
= _EntryMessages
.begin(); itMsg
!= _EntryMessages
.end(); ++itMsg
)
205 (*itMsg
).ToSend
= false;
206 (*itMsg
).Sent
= false;
210 vector
<CLogicEvent
>::iterator itEvent
;
211 for( itEvent
= _Events
.begin(); itEvent
!= _Events
.end(); ++itEvent
)
216 // reset the exit messages send status
217 for( itMsg
= _ExitMessages
.begin(); itMsg
!= _ExitMessages
.end(); ++itMsg
)
219 (*itMsg
).ToSend
= false;
220 (*itMsg
).Sent
= false;
227 //---------------------------------------------------
228 // trySendEntryMessages :
230 //---------------------------------------------------
231 void CLogicState::trySendEntryMessages()
233 /// send the entry messages that can be sent
234 vector
<CLogicEventMessage
>::iterator itMsg
;
235 for( itMsg
= _EntryMessages
.begin(); itMsg
!= _EntryMessages
.end(); ++itMsg
)
237 if( !(*itMsg
).Sent
&& (*itMsg
).DestinationId
.getType() != 0xfe )
239 CMessage
msgOut( (*itMsg
).MessageId
);
240 msgOut
.serial( (*itMsg
).Arguments
);
242 _MessagesToSend
.insert( make_pair((*itMsg
).DestinationId
,msgOut
) );
244 (*itMsg
).ToSend
= false;
245 (*itMsg
).Sent
= true;
249 } // trySendEntryMessages //
253 //---------------------------------------------------
254 // trySendEventMessages :
256 //---------------------------------------------------
257 void CLogicState::trySendEventMessages()
259 // test all conditions managed by this state
260 vector
<CLogicEvent
>::iterator itEvent
;
261 for( itEvent
= _Events
.begin(); itEvent
!= _Events
.end(); ++itEvent
)
263 if( (*itEvent
).EventAction
.EventMessage
.ToSend
== true )
265 if( (*itEvent
).EventAction
.EventMessage
.Sent
== false )
267 if( (*itEvent
).EventAction
.EventMessage
.DestinationId
.getType() != 0xfe )
269 CMessage
msgOut( (*itEvent
).EventAction
.EventMessage
.MessageId
);
270 msgOut
.serial( (*itEvent
).EventAction
.EventMessage
.Arguments
);
272 _MessagesToSend
.insert( make_pair((*itEvent
).EventAction
.EventMessage
.DestinationId
,msgOut
) );
274 (*itEvent
).EventAction
.EventMessage
.ToSend
= false;
275 (*itEvent
).EventAction
.EventMessage
.Sent
= true;
281 } // trySendEventMessages //
284 //---------------------------------------------------
285 // getMessagesToSend :
287 //---------------------------------------------------
288 void CLogicState::getMessagesToSend( multimap
<CEntityId
,CMessage
>& msgs
)
290 multimap
<CEntityId
,CMessage
>::iterator itMsg
;
291 for( itMsg
= _MessagesToSend
.begin(); itMsg
!= _MessagesToSend
.end(); ++itMsg
)
293 msgs
.insert( *itMsg
);
296 // erase all the messages
297 _MessagesToSend
.clear();
299 } // getMessagesToSend //
303 //---------------------------------------------------
306 //---------------------------------------------------
307 void CLogicState::fillVarMap( multimap
<CEntityId
,string
>& stateMachineVariables
)
310 vector
<CLogicEvent
>::iterator itEvt
;
311 for( itEvt
= _Events
.begin(); itEvt
!= _Events
.end(); ++itEvt
)
313 // get the condition used in the event
314 CLogicCondition condition
;
315 if( _LogicStateMachine
->getCondition((*itEvt
).ConditionName
,condition
) )
317 // get vars used in the conditions
318 set
<string
> condVars
;
319 condition
.fillVarSet( condVars
);
321 // add var with related service
322 set
<string
>::iterator itCV
;
323 for( itCV
= condVars
.begin(); itCV
!= condVars
.end(); ++itCV
)
325 stateMachineVariables
.insert( make_pair((*itEvt
).EventAction
.EventMessage
.DestinationId
,*itCV
) );
334 //---------------------------------------------------
337 //---------------------------------------------------
338 /*void CLogicState::serial( IStream &f )
342 f.serial( _StateName );
343 f.serialCont( _EntryMessages );
344 f.serialCont( _ExitMessages );
345 f.serialCont( _Events );
351 void CLogicState::write (xmlNodePtr node
) const
353 xmlNodePtr elmPtr
= xmlNewChild ( node
, NULL
, (const xmlChar
*)"STATE", NULL
);
354 xmlSetProp (elmPtr
, (const xmlChar
*)"Name", (const xmlChar
*)_StateName
.c_str());
357 for (i
= 0; i
< _EntryMessages
.size(); i
++)
359 _EntryMessages
[i
].write(elmPtr
, "ENTRY_");
361 for (i
= 0; i
< _ExitMessages
.size(); i
++)
363 _ExitMessages
[i
].write(elmPtr
, "EXIT_");
365 for (i
= 0; i
< _Events
.size(); i
++)
367 _Events
[i
].write(elmPtr
);
371 void CLogicState::read (xmlNodePtr node
)
373 xmlCheckNodeName (node
, "STATE");
375 _StateName
= getXMLProp (node
, "Name");
379 uint nb
= CIXml::countChildren (node
, "ENTRY_EVENT_MESSAGE");
381 xmlNodePtr parent
= CIXml::getFirstChildNode (node
, "ENTRY_EVENT_MESSAGE");
384 CLogicEventMessage v
;
386 _EntryMessages
.push_back(v
);
389 parent
= CIXml::getNextChildNode (parent
, "ENTRY_EVENT_MESSAGE");
396 uint nb
= CIXml::countChildren (node
, "EXIT_EVENT_MESSAGE");
398 xmlNodePtr parent
= CIXml::getFirstChildNode (node
, "EXIT_EVENT_MESSAGE");
401 CLogicEventMessage v
;
403 _ExitMessages
.push_back(v
);
406 parent
= CIXml::getNextChildNode (parent
, "EXIT_EVENT_MESSAGE");
413 uint nb
= CIXml::countChildren (node
, "EVENT");
415 xmlNodePtr parent
= CIXml::getFirstChildNode (node
, "EVENT");
420 _Events
.push_back(v
);
423 parent
= CIXml::getNextChildNode (parent
, "EVENT");