khanat-opennel-code/code/nel/src/logic/logic_state.cpp

431 lines
11 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// 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 <http://www.gnu.org/licenses/>.
#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)<CLogicCondition::setLogicStateMachine> 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<CLogicEvent>::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<CLogicEventMessage>::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<CLogicEvent>::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<CLogicEvent>::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<CLogicEventMessage>::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<CLogicEvent>::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<CLogicEventMessage>::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<CLogicEvent>::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<CEntityId,CMessage>& msgs )
{
multimap<CEntityId,CMessage>::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<CEntityId,string >& stateMachineVariables )
{
// events
vector<CLogicEvent>::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<string> condVars;
condition.fillVarSet( condVars );
// add var with related service
set<string>::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<nb)
{
CLogicEventMessage v;
v.read(parent);
_EntryMessages.push_back(v);
// Next parent
parent = CIXml::getNextChildNode (parent, "ENTRY_EVENT_MESSAGE");
i++;
}
}
{
// Count the parent
uint nb = CIXml::countChildren (node, "EXIT_EVENT_MESSAGE");
uint i = 0;
xmlNodePtr parent = CIXml::getFirstChildNode (node, "EXIT_EVENT_MESSAGE");
while (i<nb)
{
CLogicEventMessage v;
v.read(parent);
_ExitMessages.push_back(v);
// Next parent
parent = CIXml::getNextChildNode (parent, "EXIT_EVENT_MESSAGE");
i++;
}
}
{
// Count the parent
uint nb = CIXml::countChildren (node, "EVENT");
uint i = 0;
xmlNodePtr parent = CIXml::getFirstChildNode (node, "EVENT");
while (i<nb)
{
CLogicEvent v;
v.read(parent);
_Events.push_back(v);
// Next parent
parent = CIXml::getNextChildNode (parent, "EVENT");
i++;
}
}
}
} // NLLOGIC