// Ryzom - 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 "stdpch.h" #include "vision_receiver.h" #include using namespace NLMISC; using namespace NLNET; using namespace std; CVisionReceiver *VisionReceiverInstance = NULL; /* * Constructor */ CVisionReceiver::CVisionReceiver() : _HasPendingDelta(false) { nlassert( ! VisionReceiverInstance ); VisionReceiverInstance = this; } /* * Initialisation */ void CVisionReceiver::init() { #ifdef NL_DEBUG nlwarning("To change, assign -1 is a bad idea."); #endif _FirstUpdatedEntityVision=TEntityIndex(); // Register callback function for receiving vision deltas NLNET::TUnifiedCallbackItem _cbArray[1]; _cbArray[0].Callback = cbDeltaNewVision; _cbArray[0].Key = "VISIONS_DELTA_2"; CUnifiedNetwork::getInstance()->addCallbackArray( _cbArray, 1 ); } //--------------------------------------------------- // Vision management : Set a new delta of vision // //--------------------------------------------------- bool CVisionReceiver::setVision( const CPlayerVisionDelta &visionDelta ) { // Find the index //TEntityIndex iviewer = TheEntityContainer->entityIdToIndex( visionDelta.PlayerId ); const TEntityIndex& iviewer = visionDelta.PlayerIndex; if ( !iviewer.isValid() ) // the vision is too old, the player has gone { //nldebug( "Discarding vision for player %s because not found", visionDelta.PlayerId.toString().c_str() ); nldebug( "Discarding vision for player E%u because not found", visionDelta.PlayerIndex.getIndex() ); return false; } CEntity *p = TheEntityContainer->getEntity( iviewer ); // If entity has no unprocessed vision if( p->NextUpdatedEntityVision == LAST_VISION_CHANGE ) { // Insert the entity in the vision list p->NextUpdatedEntityVision = _FirstUpdatedEntityVision; _FirstUpdatedEntityVision = iviewer; for( vector< CPlayerVisionDelta::CIdSlot >::const_iterator itIn = visionDelta.EntitiesIn.begin(); itIn != visionDelta.EntitiesIn.end(); ++itIn ) { // Add //p->insertIntoVisionIn( iviewer, (*itIn).Id, (*itIn).Slot, false ); p->insertIntoVisionIn( iviewer, (*itIn).Index, (*itIn).Slot, false ); } for( vector< CPlayerVisionDelta::CIdSlot >::const_iterator itOut = visionDelta.EntitiesOut.begin(); itOut != visionDelta.EntitiesOut.end(); ++itOut ) { p->VisionOut.insert( (*itOut).Slot ); } /*for( vector< CPlayerVisionDelta::CIdSlot >::const_iterator itRep = visionDelta.EntitiesReplace.begin(); itRep != visionDelta.EntitiesReplace.end(); ++itRep ) { // Replace (e.g. character -> bag) //p->insertIntoVisionIn( iviewer, (*itRep).Id, (*itRep).Slot, true ); p->insertIntoVisionIn( iviewer, (*itRep).Index, (*itRep).Slot, true ); }*/ } else { // See 'Note' comments below nlwarning( "Deprecated code executed (merging vision), please warn the author" ); // Merging old and new delta vision update (only if front-end has not processed the previous vision update yet) for( vector< CPlayerVisionDelta::CIdSlot >::const_iterator itIn = visionDelta.EntitiesIn.begin(); itIn != visionDelta.EntitiesIn.end(); ++itIn ) { // Add //p->insertIntoVisionIn( iviewer, (*itIn).Id, (*itIn).Slot, false ); p->insertIntoVisionIn( iviewer, (*itIn).Index, (*itIn).Slot, false ); // Remove from VisionOut set< CLFECOMMON::TCLEntityId >::iterator it = p->VisionOut.find( (*itIn).Slot ); if( it != p->VisionOut.end() ) { p->VisionOut.erase( it ); } // Note: if the new entityId that comes in the slot is the same as the previous, // we should delete both entries from VisionIn and VisionOut. // If they are different, we should first removePair, then addPair (which is the // order done in CVisionProvider::processVision(). // // Instead of that, we always addPair and never removePair. Why this? // A long time ago, the CPlayerVisionDelta contained entityIds instead of slots // (these were allocated by the front-end). But what? // // Maybe the queue system (with _NextDeltas) made this case obsolete, meaning // we never get in this probably-bugged code again! } for( vector< CPlayerVisionDelta::CIdSlot >::const_iterator itOut = visionDelta.EntitiesOut.begin(); itOut != visionDelta.EntitiesOut.end(); ++itOut ) { // Find the index of the id //TEntityIndex iviewed = TheEntityContainer->entityIdToIndex( (*itOut).Id ); TEntityIndex iviewed = (*itOut).Index; if ( iviewed.isValid() ) { // Remove the index of the VisionIn list (for proper merging) //nlinfo( "** Add E%u to VisionOut", iviewed ); TMapOfVisionAssociations::iterator it = p->VisionIn.find( iviewed ); if( it != p->VisionIn.end() ) { p->VisionIn.erase( it ); } } p->VisionOut.insert( (*itOut).Slot ); // Note: see above } /*for( vector< CPlayerVisionDelta::CIdSlot >::const_iterator itRep = visionDelta.EntitiesReplace.begin(); itRep != visionDelta.EntitiesReplace.end(); ++itRep ) { // Replace (e.g. character -> sack) //p->insertIntoVisionIn( iviewer, (*itRep).Id, (*itRep).Slot, true ); p->insertIntoVisionIn( iviewer, (*itRep).Index, (*itRep).Slot, true ); // Note: ?? What next? }*/ } return true; } //--------------------------------------------------- // Vision management : Call it after getting all the updated vision (eg, the.GetNextUpdatedVision function return -1 ) // //--------------------------------------------------- void CVisionReceiver::endUpdatedVision() { // for all the entities in the list of updated while(_FirstUpdatedEntityVision.isValid()) { // Get the next entity TEntityIndex i = _FirstUpdatedEntityVision; CEntity *p = TheEntityContainer->getEntity( _FirstUpdatedEntityVision ); // Clean the lists p->VisionIn.clear(); p->VisionOut.clear(); // Remove it from list of updated entities _FirstUpdatedEntityVision = p->NextUpdatedEntityVision; p->NextUpdatedEntityVision.initToLastChanged(); } if ( _NextDeltas.empty() ) { // The only delta has been processed by the front-end //nldebug( "End of vision scanning" ); _HasPendingDelta = false; } else { // Somes more deltas need to be processed //nldebug( "End of vision scanning - Applying one more delta" ); nlassert( _HasPendingDelta ); list< CPlayerVisionDelta >& deltaVision = _NextDeltas.front(); // Apply the next delta to the vision for( list< CPlayerVisionDelta >::iterator it = deltaVision.begin(); it != deltaVision.end(); ++it ) { // setVision( (*it).Id, (*it).EntityIn, (*it).EntityOut ); setVision( *it ); } _NextDeltas.pop(); } } //--------------------------------------------------- // UpdateVision, unserial update vision message and process it // //--------------------------------------------------- inline void CVisionReceiver::updateNewVision( CMessage& msgin ) { //LOG_VISION("FEVIS:%u: Receiving a vision update", CTickEventHandler::getGameCycle() ); list< CPlayerVisionDelta > deltaVision; CPlayerVisionDelta::decodeVisionDelta(msgin, deltaVision); //list< SPlayerVisionDelta > deltaVision; //msgin.serialCont( deltaVision ); if ( ! _HasPendingDelta ) { // Apply the delta to the vision //nldebug( "Applying delta" ); //for( list< SPlayerVisionDelta >::iterator it = deltaVision.begin(); it != deltaVision.end(); ++it ) for( list< CPlayerVisionDelta >::iterator it = deltaVision.begin(); it != deltaVision.end(); ++it ) { setVision( *it ); } _HasPendingDelta = true; } else { // Store the delta //nldebug( "Storing delta" ); _NextDeltas.push( deltaVision ); } } //--------------------------------------------------- // Callback for delta vision update received // //--------------------------------------------------- void cbDeltaNewVision( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId ) { //H_BEFORE(RcvUpdateDeltaNewVision); //CFrontEndService::instance()->BackEndRecvWatch3.start(); VisionReceiverInstance->updateNewVision( msgin ); //CFrontEndService::instance()->BackEndRecvWatch3.stop(); //H_AFTER(RcvUpdateDeltaNewVision); }