// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "nel/logic/logic_state.h" #include "nel/logic/logic_state_machine.h" using namespace std; using namespace NLMISC; using namespace NLNET; namespace NLLOGIC { //--------------------------------------------------- // CLogicState // //--------------------------------------------------- CLogicState::CLogicState() { _StateName = "no_state"; _LogicStateMachine = 0; } // CLogicState // //--------------------------------------------------- // setLogicStateMachine // //--------------------------------------------------- void CLogicState::setLogicStateMachine( CLogicStateMachine * logicStateMachine ) { if( logicStateMachine == 0 ) { nlwarning("(LOGIC) The state machine is null"); } else { // init the logic state machine for this state _LogicStateMachine = logicStateMachine; // init the logic state machine in each event vector::iterator itEvent; for( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent ) { (*itEvent).setLogicStateMachine( logicStateMachine ); } } } // setLogicStateMachine // //--------------------------------------------------- // addEvent : // //--------------------------------------------------- void CLogicState::addEvent( CLogicEvent event ) { event.setLogicStateMachine( _LogicStateMachine ); _Events.push_back( event ); } // addEvent // //--------------------------------------------------- // addSIdMap : // // looks in all the messages of the state if the // destination names can be associated with a sid. //--------------------------------------------------- void CLogicState::addSIdMap( const TSIdMap& sIdMap ) { vector::iterator itMsg; /// entry messages for( itMsg = _EntryMessages.begin(); itMsg != _EntryMessages.end(); ++itMsg ) { TSIdMap::const_iterator itId = sIdMap.find( (*itMsg).Destination ); // if message destination exists in the map we associate the sid with the message if( itId != sIdMap.end() ) { (*itMsg).DestinationId = (*itId).second; } } /// send the entry messages that can be sent trySendEntryMessages(); // event messages vector::iterator itEvt; for( itEvt = _Events.begin(); itEvt != _Events.end(); ++itEvt ) { string dest = (*itEvt).EventAction.EventMessage.Destination; TSIdMap::const_iterator itId = sIdMap.find( dest ); // if message destination exists in the map we associate the sid with the message if( itId != sIdMap.end() ) { (*itEvt).EventAction.EventMessage.DestinationId = (*itId).second; } } /// send the event messages that can be sent trySendEventMessages(); /// exit messages for( itMsg = _ExitMessages.begin(); itMsg != _ExitMessages.end(); ++itMsg ) { TSIdMap::const_iterator itId = sIdMap.find( (*itMsg).Destination ); // if message destination exists in the map we associate the sid with the message if( itId != sIdMap.end() ) { (*itMsg).DestinationId = (*itId).second; } } } // addSIdMap // //--------------------------------------------------- // processLogic : // //--------------------------------------------------- void CLogicState::processLogic() { // test all conditions managed by this state vector::iterator itEvent; for( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent ) { if( (*itEvent).testCondition() ) { //nlinfo("The condition %s is valid",(*itEvent).ConditionName.c_str()); if( (*itEvent).EventAction.IsStateChange ) { _LogicStateMachine->setCurrentState( (*itEvent).EventAction.StateChange ); } else { // this message will be sent as soon as the dest id will be given (*itEvent).EventAction.enableSendMessage(); /// send the event messages that must and can be sent trySendEventMessages(); } } else { // reset message send status here to be able to send messages several times in the logic state // --> this has to be done if we want messages to be sent every time the condition becomes verified } } } // processLogic // //--------------------------------------------------- // enterState : // //--------------------------------------------------- void CLogicState::enterState() { /// send the entry messages that can be sent trySendEntryMessages(); } // enterState // //--------------------------------------------------- // exitState : // //--------------------------------------------------- void CLogicState::exitState() { vector::iterator itMsg; for( itMsg = _ExitMessages.begin(); itMsg != _ExitMessages.end(); ++itMsg ) { if( (*itMsg).DestinationId != CEntityId() ) { CMessage msgOut( (*itMsg).MessageId ); msgOut.serial( (*itMsg).Arguments ); _MessagesToSend.insert( make_pair((*itMsg).DestinationId,msgOut) ); } } // reset the entry messages send status for( itMsg = _EntryMessages.begin(); itMsg != _EntryMessages.end(); ++itMsg ) { (*itMsg).ToSend = false; (*itMsg).Sent = false; } // reset all events vector::iterator itEvent; for( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent ) { (*itEvent).reset(); } // reset the exit messages send status for( itMsg = _ExitMessages.begin(); itMsg != _ExitMessages.end(); ++itMsg ) { (*itMsg).ToSend = false; (*itMsg).Sent = false; } } // exitState // //--------------------------------------------------- // trySendEntryMessages : // //--------------------------------------------------- void CLogicState::trySendEntryMessages() { /// send the entry messages that can be sent vector::iterator itMsg; for( itMsg = _EntryMessages.begin(); itMsg != _EntryMessages.end(); ++itMsg ) { if( !(*itMsg).Sent && (*itMsg).DestinationId.getType() != 0xfe ) { CMessage msgOut( (*itMsg).MessageId ); msgOut.serial( (*itMsg).Arguments ); _MessagesToSend.insert( make_pair((*itMsg).DestinationId,msgOut) ); (*itMsg).ToSend = false; (*itMsg).Sent = true; } } } // trySendEntryMessages // //--------------------------------------------------- // trySendEventMessages : // //--------------------------------------------------- void CLogicState::trySendEventMessages() { // test all conditions managed by this state vector::iterator itEvent; for( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent ) { if( (*itEvent).EventAction.EventMessage.ToSend == true ) { if( (*itEvent).EventAction.EventMessage.Sent == false ) { if( (*itEvent).EventAction.EventMessage.DestinationId.getType() != 0xfe ) { CMessage msgOut( (*itEvent).EventAction.EventMessage.MessageId ); msgOut.serial( (*itEvent).EventAction.EventMessage.Arguments ); _MessagesToSend.insert( make_pair((*itEvent).EventAction.EventMessage.DestinationId,msgOut) ); (*itEvent).EventAction.EventMessage.ToSend = false; (*itEvent).EventAction.EventMessage.Sent = true; } } } } } // trySendEventMessages // //--------------------------------------------------- // getMessagesToSend : // //--------------------------------------------------- void CLogicState::getMessagesToSend( multimap& msgs ) { multimap::iterator itMsg; for( itMsg = _MessagesToSend.begin(); itMsg != _MessagesToSend.end(); ++itMsg ) { msgs.insert( *itMsg ); } // erase all the messages _MessagesToSend.clear(); } // getMessagesToSend // //--------------------------------------------------- // fillVarMap : // //--------------------------------------------------- void CLogicState::fillVarMap( multimap& stateMachineVariables ) { // events vector::iterator itEvt; for( itEvt = _Events.begin(); itEvt != _Events.end(); ++itEvt ) { // get the condition used in the event CLogicCondition condition; if( _LogicStateMachine->getCondition((*itEvt).ConditionName,condition) ) { // get vars used in the conditions set condVars; condition.fillVarSet( condVars ); // add var with related service set::iterator itCV; for( itCV = condVars.begin(); itCV != condVars.end(); ++itCV ) { stateMachineVariables.insert( make_pair((*itEvt).EventAction.EventMessage.DestinationId,*itCV) ); } } } } // fillVarMap // //--------------------------------------------------- // serial : // //--------------------------------------------------- /*void CLogicState::serial( IStream &f ) { f.xmlPush( "STATE"); f.serial( _StateName ); f.serialCont( _EntryMessages ); f.serialCont( _ExitMessages ); f.serialCont( _Events ); f.xmlPop(); } // serial //*/ void CLogicState::write (xmlNodePtr node) const { xmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)"STATE", NULL); xmlSetProp (elmPtr, (const xmlChar*)"Name", (const xmlChar*)_StateName.c_str()); uint i; for (i = 0; i < _EntryMessages.size(); i++) { _EntryMessages[i].write(elmPtr, "ENTRY_"); } for (i = 0; i < _ExitMessages.size(); i++) { _ExitMessages[i].write(elmPtr, "EXIT_"); } for (i = 0; i < _Events.size(); i++) { _Events[i].write(elmPtr); } } void CLogicState::read (xmlNodePtr node) { xmlCheckNodeName (node, "STATE"); _StateName = getXMLProp (node, "Name"); { // Count the parent uint nb = CIXml::countChildren (node, "ENTRY_EVENT_MESSAGE"); uint i = 0; xmlNodePtr parent = CIXml::getFirstChildNode (node, "ENTRY_EVENT_MESSAGE"); while (i