Add infos into target window
[ryzomcore.git] / ryzom / server / src / frontend_service / vision_provider.cpp
blob28350abd783f9ffa81829a83280ea430f8b63cd1
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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 "stdpch.h"
21 #include "game_share/action_association.h"
23 #include "vision_provider.h"
24 #include "frontend_service.h"
25 #include "client_host.h"
26 #include "fe_stat.h"
27 #include "vision_array.h"
29 using namespace std;
30 using namespace NLNET;
31 using namespace NLMISC;
32 using namespace CLFECOMMON;
35 bool verboseVision = false;
36 extern NLMISC::CMemDisplayer *TmpDebugDisplayer;// = NULL;
37 NLMISC::CLog *TmpDebugLogger = NULL;
41 * Constructor
43 CVisionProvider::CVisionProvider() :
44 _VisionArray( NULL ),
45 _History( NULL ),
46 _EntityToClient( NULL )
51 //TEMP
52 /*static CFileDisplayer fd("addrem.log", true);
53 static CLog flog;*/
56 #ifdef MEASURE_FRONTEND_TABLES
57 sint32 NbX, NbY;
58 NLMISC_VARIABLE( sint32, NbX, "NbX" );
59 NLMISC_VARIABLE( sint32, NbY, "NbY" );
60 #endif
63 NLMISC_DYNVARIABLE( uint, NbEntitiesSeenByMonitoredClient, "NbEntitiesSeenByMonitoredClient" )
65 // We can only read the value
66 if ( get )
68 CFrontEndService *fe = CFrontEndService::instance();
69 //nlassert( fe->MonitoredClient <= MAX_NB_CLIENTS );
70 CClientHost *client = fe->receiveSub()->clientIdCont()[fe->MonitoredClient];
71 if ( client )
73 *pointer = MAX_SEEN_ENTITIES_PER_CLIENT - client->NbFreeEntityItems;
74 return;
76 *pointer = 0;
82 * Initialization
84 void CVisionProvider::init( CVisionArray *va, CHistory *h, CClientIdLookup *cl )
86 _VisionArray = va;
87 _History = h;
88 _EntityToClient = cl;
90 DistanceSpreader.init();
91 _VisionReceiver.init();
92 //TEMP
93 //flog.addDisplayer( &fd );
95 if ( ! TmpDebugLogger )
97 TmpDebugDisplayer = new CMemDisplayer( "VisionLog" );
98 TmpDebugDisplayer->setParam( 2000 );
99 TmpDebugLogger = new CLog( CLog::LOG_DEBUG );
100 TmpDebugLogger->addDisplayer( TmpDebugDisplayer );
106 * Destructor
108 CVisionProvider::~CVisionProvider()
110 if ( TmpDebugLogger )
112 delete TmpDebugLogger;
113 delete TmpDebugDisplayer;
119 * Easy access to the client host object. Returns NULL and makes warning if not found.
121 CClientHost *CVisionProvider::clientHost( TClientId clientid )
123 nlassert( clientid <= MaxNbClients );
124 CClientHost *client = CFrontEndService::instance()->sendSub()->clientIdCont()[clientid];
125 if ( !client )
126 nlwarning( "C%hu not found in cont", clientid );
127 return client;
132 * Process the vision differences
134 void CVisionProvider::processVision()
136 CFrontEndService::instance()->ProcessVisionWatch.start();
137 TEntityIndex index;
139 /* 1. Process the changes in the vision pairs.
140 * The property receiver says which entities are seen, limited to MAX_SEEN_ENTITIES_PER_CLIENT per observer.
143 H_AUTO(ScanVision);
145 /* Multi-pass because the frontend_property_receiver may have received several deltas
146 * that cannot be merged (for example ADD 25 into slot 1, REM 25, ADD 25 into slot 3)
147 * but are stored in a queue.
149 while ( _VisionReceiver.visionChanged() )
151 /* TEMP
152 * Begin perf measures for vision processing
154 /*static bool resetM = true;
155 if ( resetM )
157 IService::getInstance()->requireResetMeasures();
158 resetM = false;
161 index=_VisionReceiver.getFirstUpdatedVision();
162 while (index.isValid())
164 // Get the description of the entity who sees some changes
165 CEntity *observerEntity = TheEntityContainer->getEntity( index );
167 // Look-up the corresponding client (player character) connected on this front-end
168 TClientId observerClientId = _EntityToClient->getClientId( index );
169 if ( observerClientId == INVALID_CLIENT )
171 const CEntityId &observerEntityId = TheDataset.getEntityId( index );
172 #ifdef NL_DEBUG
173 nldebug( "%u: Observer E%u not known by this FS...", CTickEventHandler::getGameCycle(), index.getIndex() );
174 #endif
176 observerClientId = TheEntityContainer->EntityToClient->getClientId( observerEntityId );
177 if ( observerClientId != INVALID_CLIENT )
179 CClientHost *clienthost = CFrontEndService::instance()->sendSub()->clientIdCont()[observerClientId];
180 clienthost->setEntityIndex( index );
181 TheEntityContainer->EntityToClient->addEntityIndex( index, observerClientId );
182 nlinfo( "%u: Setting mirror row to C%hu uid %u E%u (recovered)", CTickEventHandler::getGameCycle(), observerClientId, clienthost->Uid, index.getIndex() );
183 CFrontEndService::instance()->receiveSub()->ConnectionStatLog->displayNL( "Setting mirror row to C%hu uid %u E%u", observerClientId, clienthost->Uid, index.getIndex() );
185 else
187 #ifdef NL_DEBUG
188 nldebug( "Observer not found" );
189 #endif
190 index = _VisionReceiver.getNextUpdatedVision( index );
191 continue;
195 // 1. Remove the pairs corresponding to entities not seen anymore
196 TSetOfRemovedEntities::iterator iso;
197 for ( iso=observerEntity->VisionOut.begin(); iso!=observerEntity->VisionOut.end(); ++iso )
199 removePair( observerClientId, *iso );
202 // 2. Add or replace the pairs corresponding to entities now seen
203 TMapOfVisionAssociations::iterator isi;
204 for ( isi=observerEntity->VisionIn.begin(); isi!=observerEntity->VisionIn.end(); ++isi )
206 // Add or replace?
207 if ( (*isi).second.second )
209 replacePair( observerClientId, (*isi).first, (TCLEntityId)((*isi).second.first) );
211 else
213 addPair( observerClientId, (*isi).first, (TCLEntityId)((*isi).second.first) );
215 // Note: we don't add a pair for the symetric association
218 index = _VisionReceiver.getNextUpdatedVision( index );
221 _VisionReceiver.endUpdatedVision();
224 //flog.displayRawNL( "--" );
226 /* 2. Calculate new distances for active clients on this front-end.
227 * The entities that are modified were not advertised by getFirstUpdatedProperties() and getNextUpdatedProperties()
228 * because they are considered to be always modified, although their position is up to date in the mirror.
232 * Distance processing is spread over several cycles.
233 * DPClientMapIndex is the current index in the client map, DPIterator is the current iterator
234 * Note: the number of clients can increase or decrease between two cycles.
237 if ( DistanceSpreader.mustProcessNow() )
239 H_AUTO(UpdateDistances);
240 THostMap::iterator icm;
241 sint clientmapindex, outerBoundIndex;
242 DistanceSpreader.getProcessingBounds( icm, clientmapindex, outerBoundIndex );
244 while ( clientmapindex < outerBoundIndex )
246 CClientHost* client = GETCLIENTA(icm);
247 TPairState* state = _VisionArray->getClientStateArray(client->clientId()) + 1;
249 // Calculate the distance for all used slots (except slot 0 which always remains at distance 0)
250 for ( sint e=1; e!=MAX_SEEN_ENTITIES_PER_CLIENT; ++e, ++state )
252 //TPairState& state = _VisionArray->getPairState(client->clientId(), (TCLEntityId)e);
254 //if ( _VisionArray->getAssociationState( client, (TCLEntityId)e ) != CClientEntityIdTranslator::CEntityInfo::UnusedAssociation ) // CHANGED BEN
255 if (state->AssociationState != TPairState::UnusedAssociation )
257 state->DistanceCE = calcDistance( client, (TCLEntityId)e, state->EntityIndex );
260 ++clientmapindex;
261 ++icm;
263 DistanceSpreader.endProcessing( icm );
266 DistanceSpreader.incCycle();
268 CFrontEndService::instance()->ProcessVisionWatch.stop();
270 // After having removed the pairs of removed clients, free their ids
271 CFrontEndService::instance()->receiveSub()->freeIdsOfRemovedClients();
273 /*CFrontEndPropertyReceiver::SEntity *ent = CFrontEndPropertyReceiver::getEntity( 5 );
274 nlinfo( "Mileage = %u", ent->Mileage );*/
279 * Calculate the absolute distance between a client and an entity
281 inline TCoord CVisionProvider::calcDistance( CClientHost *client, TCLEntityId slot, const TEntityIndex& seenIndex )
283 // Indexes are not valid in the case when a client has just resetted, before getting the vision update from the GPMS
284 if ( (!client->entityIndex().isValid()) || (!seenIndex.isValid()) )
285 return UNSET_DISTANCE;
287 // Get client pos (assumes it is given by the GPMS)
288 CEntity *clientEntity = TheEntityContainer->getEntity( client->entityIndex() );
289 CEntity *seenEntity = TheEntityContainer->getEntity( seenIndex );
291 // The mirror properties can be not ready in such a multi-machine case (TODO: check it):
292 // Machine A: Service S1 spawns an entity
293 // Machine B: GPMS gets the entity and adds it to the vision of a player
294 // Machine C: FS gets the vision message
295 // FS gets the entity
296 if ( ! seenEntity->X.isReadable() )
298 nlwarning( "Multi-machine vision bug with entity E%u", seenIndex.getIndex() );
299 return UNSET_DISTANCE;
301 if ( ! clientEntity->X.isReadable() )
303 nlwarning( "Multi-machine vision bug with client %s", client->eId().toString().c_str() );
304 return UNSET_DISTANCE;
307 TCoord pos1x = clientEntity->X(), pos1y = clientEntity->Y();
308 TCoord pos2x = seenEntity->X(), pos2y = seenEntity->Y();
310 // Obsolete: we used to use the position in history (last sent pos). Now it's the official position
311 // in order to avoid problem in mode COMBAT_FLOAT...
312 // Get absolute entity pos (note: in local mode, the relative pos is not stored in the history)
313 //CAction::TValue vlastposx, vlastposy, vlastposz;
314 //bool histohasvalue = _History->getPosition( client->clientId(), slot, vlastposx, vlastposy, vlastposz );
315 //if ( histohasvalue )
317 // pos2x = getAbsoluteCoordinateFrom64( vlastposx );
318 // pos2y = getAbsoluteCoordinateFrom64( vlastposy );
319 // //nlinfo( "lastpos: %d %d, vlastpos: %" NL_I64 "u %" NL_I64 "u", pos2x, pos2y, vlastposx, vlastposy );
320 /*#ifdef NL_DEBUG
321 TCoord d = (TCoord)(abs(pos1x-pos2x) + abs(pos1y-pos2y));
322 if ( d < 0 )
324 nlwarning( "Invalid distance calculation with lastsent pos (C%hu S%hu D=%d)", client->clientId(), (uint16)slot, d );
325 nlstop;
327 #endif*/
328 /*#ifdef NL_DEBUG
329 TCoord d = (TCoord)(abs(pos1x-pos2x) + abs(pos1y-pos2y));
330 if ( d < 0 )
332 nlwarning( "Invalid distance calculation with real pos (C%hu S%hu D=%d)", client->clientId(), (uint16)slot, d );
333 nlstop;
335 #endif*/
338 // Calculate 2D Manhattan distance
339 TCoord result = (TCoord)(abs(pos1x-pos2x) + abs(pos1y-pos2y));
340 if ( result < 0 )
341 result = UNSET_DISTANCE; // correct error if positions are wrong
342 return result;
347 * Add a pair. The argument 'furthestceid' is used when removing an item is required.
349 bool CVisionProvider::addPair( TClientId clientid, const TEntityIndex& entityindex, CLFECOMMON::TCLEntityId slot )
351 CClientHost *client = clientHost(clientid);
352 if ( ! client )
353 return false;
355 // If we have unassociated but no removed the pair yet, complete the removal
356 //if ( client->IdTranslator.getInfo(slot).AssociationState != CClientEntityIdTranslator::CEntityInfo::UnusedAssociation ) // CHANGED BEN
357 if (_VisionArray->getAssociationState(clientid, slot) != TPairState::UnusedAssociation )
359 //LOG_VISION( "FEVIS:%u: Replacing E%u by E%u in slot %hu", CTickEventHandler::getGameCycle(), client->IdTranslator.getInfo(slot).EntityInSlot.getIndex(), entityindex.getIndex(), (uint16)slot ); // CHANGED BEN
360 LOG_VISION( "FEVIS:%u: Replacing E%u by E%u in slot %hu", CTickEventHandler::getGameCycle(), _VisionArray->getEntityIndex(clientid, slot).getIndex(), entityindex.getIndex(), (uint16)slot );
361 postRemovePair( clientid, slot );
364 //TEMP
365 //flog.displayRawNL( "ADD C%hu E%u, slot %hu, id %s", clientid, entityindex, slot, CFrontEndPropertyReceiver::getEntity(entityindex)->id.toString().c_str() );
367 /* 1. Associate Entity Index to a new TCLEntityId (or get exiting association if this new association occurred before a dissociation acknowledge from the client)
370 if ( slot < MAX_SEEN_ENTITIES_PER_CLIENT )
372 // Check if the entity is not still in a slot of the client
373 TCLEntityId slotFromEntityIndex = client->IdTranslator.getCEId( entityindex );
374 if ( slotFromEntityIndex != INVALID_SLOT )
376 // The entity was moved to a new slot (previous one unassociated but not removed yet)// The entity was moved to a new slot (previous one unassociated but not removed yet)
377 LOG_VISION( "FEVIS: Moving E%u from S%hu to S%hu", entityindex.getIndex(), (uint16)slotFromEntityIndex, (uint16)slot );
378 postRemovePair( clientid, slotFromEntityIndex );
380 if ( ! client->IdTranslator.acquireCEId( entityindex, (TCLEntityId)slot ) )
382 return false; // should not occur (see warning displayed by acquireCEId())
385 else
387 //nlwarning( "Invalid slot %hu given by GPMS for entity E%u seen by client %hu", slot, entityindex, clientid );
388 nlstop;
389 return false; // should not occur
392 ++AssocCounter;
393 //CClientEntityIdTranslator::CEntityInfo& info = client->IdTranslator.getInfo((TCLEntityId)slot); // CHANGED BEN
394 #ifdef NL_DEBUG
395 //info.AssociationState = CClientEntityIdTranslator::CEntityInfo::AwaitingAssAck; // CHANGED BEN
396 _VisionArray->setAssociationState(clientid, slot, TPairState::AwaitingAssAck);
397 // NormalAssociation set in CDistancePrioritizer::fillDiscreetProperty() with Sheet
398 #else
399 //info.AssociationState = CClientEntityIdTranslator::CEntityInfo::NormalAssociation; // CHANGED BEN
400 _VisionArray->setAssociationState(clientid, slot, TPairState::NormalAssociation);
401 #endif
403 /* 2. Fill the item attributes
405 LOG_VISION( "FEVIS: %u: Adding pair C%hu -> slot %hu (E%u_%hu)", CTickEventHandler::getGameCycle(), clientid, (uint16)slot, entityindex.getIndex(), entityindex.counter() );
406 CEntity *sentity = TheEntityContainer->getEntity( entityindex );
407 //nlinfo( "AddPair %hu %hu (E%u)", clientid, (uint16)slot, entityindex );
408 _VisionArray->setEntityIndex( clientid, slot, entityindex );
409 TPairState& pairState = _VisionArray->getPairState( clientid, slot );
410 pairState.associate();
411 if ( slot == 0 )
412 pairState.DistanceCE = 0; // slot 0's distance is always 0 because we can't use the last sent pos if it is not sent
413 else
414 pairState.DistanceCE = calcDistance( client, (TCLEntityId)slot, entityindex );
415 --client->NbFreeEntityItems;
416 #ifdef NL_DEBUG
417 if ( TheDataset.getEntityId( entityindex ).getType() == RYZOMID::player )
418 LOG_VISION( "FEVIS: Seen E%u is a player", entityindex.getIndex() );
419 #endif
421 CFrontEndService::instance()->PrioSub.Prioritizer.addEntitySeenByClient( clientid, slot );
423 // Add into history
424 //if ( slot != 0 )
426 if ( ! _History->addEntityToClient( (TCLEntityId)slot, client->clientId() ) )
428 nlwarning( "Cannot add entity to client in property history: entity already used" );
432 // Add to observer list: the clients who see the entity (and its ceid for them)
433 //_ObserverList[entityindex].insert( TPairClientSlot( clientid, (TCLEntityId)slot ) );
435 //client->displayClientProperties();
437 return true;
442 * Remove a pair.
444 void CVisionProvider::removePair( TClientId clientid, TCLEntityId slot )
446 LOG_VISION( "FEVIS:%u: Unassociating C%hu -> slot %hu", CTickEventHandler::getGameCycle(), clientid, (uint16)slot );
448 // Prevent a vision bug where two removals would occur (e.g. when the PC is stressed-slow)
449 CClientHost *client = clientHost( clientid );
450 if ( ! client ) // we had such a situation live once
451 return;
453 //CClientEntityIdTranslator::CEntityInfo &info = client->IdTranslator.getInfo(slot); // CHANGED BEN
454 //if ( info.AssociationState == CClientEntityIdTranslator::CEntityInfo::UnusedAssociation ) // CHANGED BEN
455 if (_VisionArray->getAssociationState(clientid, slot) == TPairState::UnusedAssociation )
457 nlwarning( "%u: Cannot remove pair twice (or pair not associated): C%hu S%hu", CTickEventHandler::getGameCycle(), clientid, (uint16)slot );
459 else
461 TPairState& pairState = _VisionArray->getPairState( clientid, slot );
462 pairState.unassociate();
470 void CVisionProvider::postRemovePair( TClientId clientid, TCLEntityId slot )
472 ++DisasCounter;
474 //TEMP
475 //flog.displayRawNL( "REM C%hu E%u, id %s", clientid, entityindex, CFrontEndPropertyReceiver::getEntity(entityindex)->id.toString().c_str() );
477 nlassert ( (clientid != INVALID_CLIENT) && (slot != INVALID_SLOT) );
478 CClientHost *client = clientHost( clientid );
479 if ( ! client )
480 return;
482 //CClientEntityIdTranslator::CEntityInfo &info = client->IdTranslator.getInfo(slot); // CHANGED BEN
483 //TEntityIndex entityindex = info.EntityInSlot; // CHANGED BEN
485 TEntityIndex entityindex = _VisionArray->getEntityIndex(clientid, slot);
486 if ( !entityindex.isValid() )
488 // No warning when slot 0 because this is normal at the beginning of the life of a client
489 if ( slot != 0 )
491 nlwarning( "Cannot remove vision pair C%hu -> slot %hu!", clientid, (uint16)slot );
493 return;
496 CFrontEndService::instance()->PrioSub.Prioritizer.removeEntitySeenByClient( clientid, slot );
498 //client->displayClientProperties();
500 LOG_VISION( "FEVIS: %u: Removing pair C%hu -> slot %hu (E%u_%hu)", CTickEventHandler::getGameCycle(), clientid, (uint16)slot, entityindex.getIndex(), entityindex.counter() );
501 CEntity *sentity = TheEntityContainer->getEntity( entityindex );
502 #ifdef NL_DEBUG
503 if ( TheDataset.getEntityId( entityindex ).getType() == RYZOMID::player )
504 LOG_VISION( "FEVIS: Unseen E%u is a player", entityindex.getIndex() );
505 #endif
507 //info.AssociationState = CClientEntityIdTranslator::CEntityInfo::UnusedAssociation; // CHANGED BEN
508 _VisionArray->setAssociationState(clientid, slot, TPairState::UnusedAssociation);
510 // Remove from history
511 //if ( slot != 0 )
512 _History->removeEntityOfClient( slot, clientid );
514 // Remove from observer list: the clients who see the entity (and its ceid for them)
515 //removeFromObserverList( entityindex, clientid, slot );
517 // Release Id !
518 client->IdTranslator.releaseId( entityindex /*_VisionArray->getEntityIndex( client->clientId(), ceid )*/ );
519 ++client->NbFreeEntityItems;
520 //LOG_VISION( "FEVIS: Client %hu has %hu free items (+)", client->clientId(), client->NbFreeEntityItems );
522 // Reset item in the vision array
523 TPairState& pairState = _VisionArray->getPairState( clientid, slot );
524 pairState.resetItem();
529 * Replace the entity in a slot (e.g. when transforming a dead character to a sack)
531 void CVisionProvider::replacePair( TClientId clientid, const TEntityIndex& newEntityIndex, CLFECOMMON::TCLEntityId slot )
534 * 1. Clear the old entityindex
536 ++DisasCounter;
538 nlassert ( (clientid != INVALID_CLIENT) && (slot != INVALID_SLOT) );
539 CClientHost *client = clientHost( clientid );
540 if ( ! client )
541 return;
543 //CClientEntityIdTranslator::CEntityInfo &info = client->IdTranslator.getInfo(slot); // CHANGED BEN
544 //TEntityIndex entityindex = info.EntityInSlot; // CHANGED BEN
546 TEntityIndex entityindex = _VisionArray->getEntityIndex(clientid, slot);
547 if ( !entityindex.isValid() )
549 nlwarning( "Cannot replace vision pair C%hu -> slot %hu!", clientid, (uint16)slot );
550 return;
553 //info.AssociationChannel == CClientEntityIdTranslator::CEntityInfo::NormalAssociation;
555 //client->displayClientProperties();
557 LOG_VISION( "FEVIS: %u: Replacing pair C%hu -> slot %hu (E%u becomes E%u)", CTickEventHandler::getGameCycle(), clientid, (uint16)slot, entityindex.getIndex(), newEntityIndex.getIndex() );
558 CEntity *sentity = TheEntityContainer->getEntity( entityindex );
559 #ifdef NL_DEBUG
560 if ( TheDataset.getEntityId( entityindex ).getType() == RYZOMID::player )
561 LOG_VISION( "FEVIS: Unseen E%u is a player", entityindex.getIndex() );
562 #endif
564 // Remove from history
565 //if ( slot != 0 )
566 _History->removeEntityOfClient( slot, clientid );
568 // Remove from observer list: the clients who see the entity (and its ceid for them)
569 //removeFromObserverList( entityindex, clientid, slot );
571 // Release Id !
572 client->IdTranslator.releaseId( entityindex /*_VisionArray->getEntityIndex( client->clientId(), ceid )*/ );
573 //LOG_VISION( "FEVIS: Client %hu has %hu free items (+)", client->clientId(), client->NbFreeEntityItems );
576 * 2. Set the new entityindex
579 ++AssocCounter;
581 // Associate Entity Index to the slot
582 if ( ! client->IdTranslator.acquireCEId( newEntityIndex, (TCLEntityId)slot ) )
584 // Should not occur
585 return;
588 /* 2. Fill the item attributes
590 //LOG_VISION( "FEVIS: Adding pair C%hu -> slot %hu (E%u) (replace)", clientid, slot, entityindex );
591 sentity = TheEntityContainer->getEntity( newEntityIndex );
592 //nlinfo( "AddPair %hu %hu (E%u)", clientid, (uint16)slot, entityindex );
593 TPairState& pairState = _VisionArray->getPairState( clientid, slot );
594 pairState.changeAssociation();
595 pairState.resetPrio();
596 pairState.EntityIndex = newEntityIndex;
597 if ( slot == 0 )
598 pairState.DistanceCE = 0;
599 else
600 pairState.DistanceCE = calcDistance( client, (TCLEntityId)slot, newEntityIndex );
601 #ifdef NL_DEBUG
602 if ( TheDataset.getEntityId( newEntityIndex ).getType() == RYZOMID::player )
603 LOG_VISION( "FEVIS: Seen E%u is a player", newEntityIndex.getIndex() );
604 #endif
606 // Add into history
607 //if ( slot != 0 )
609 if ( ! _History->addEntityToClient( (TCLEntityId)slot, clientid ) )
611 nlwarning( "Cannot add entity to client in property history: entity already used" );
615 // Add to observer list: the clients who see the entity (and its ceid for them)
616 //_ObserverList[newEntityIndex].insert( TPairClientSlot( clientid, (TCLEntityId)slot ) );
622 * Remove item from observer list of entityindex
624 /*void CVisionProvider::removeFromObserverList( const TEntityIndex& entityindex, TClientId clientid, TCLEntityId ceid )
626 _ObserverList[entityindex].erase( TPairClientSlot( clientid, ceid ) );
631 * Reset all slots of all clients (e.g. when GPMS falls down)
633 void CVisionProvider::resetVision()
635 nlinfo( "Resetting all slots of all clients..." );
636 THostMap& clientmap = CFrontEndService::instance()->receiveSub()->clientMap();
637 THostMap::iterator ihm;
638 for ( ihm=clientmap.begin(); ihm!=clientmap.end(); ++ihm )
640 resetVision( GETCLIENTA(ihm) );
646 * Reset all slots of one client (e.g. when a client is unspawned)
648 void CVisionProvider::resetVision( CClientHost *clienthost )
650 // Get all entities seen by this client
651 sint e;
652 for ( e=0; e!=MAX_SEEN_ENTITIES_PER_CLIENT; ++e )
654 //if ( _VisionArray->getAssociationState( clienthost, (TCLEntityId)e ) != CClientEntityIdTranslator::CEntityInfo::UnusedAssociation ) // CHANGED BEN
655 if ( _VisionArray->getAssociationState( clienthost->clientId(), (TCLEntityId)e ) != TPairState::UnusedAssociation )
657 // Remove pair on the FE and on the client
658 removePair( clienthost->clientId(), (TCLEntityId)e );
665 * Display the properties of an entity in the vision
667 void CVisionProvider::displayEntityInfo( const CEntity& e, const TEntityIndex& entityIndex, NLMISC::CLog *log ) const
669 if ( ! e.X.isReadable() )
671 log->displayNL( "Entity %u not initialized", entityIndex.getIndex() );
672 return;
675 const CEntityId& eid = TheDataset.getEntityId( entityIndex );
676 uint64 properties[NB_VISUAL_PROPERTIES];
677 CEntity::fillVisualPropertiesFromMirror( properties, entityIndex );
678 string sheetIdS = CSheetId((uint32)properties[PROPERTY_SHEET]).toString();
679 log->displayNL( "E%u %s Id %s Name %s Sheet %u (%s) GameCycle %u",
680 entityIndex.getIndex(), (eid.getType()==RYZOMID::player)?"PLAYER":RYZOMID::toString( (RYZOMID::TTypeId)eid.getType() ).c_str(), eid.toString().c_str(), getEntityName(entityIndex).c_str(), (uint32)properties[PROPERTY_SHEET], sheetIdS.c_str(), e.TickPosition() );
681 log->displayNL( "%u entities entered vision, %u entities left vision", e.VisionIn.size(), e.VisionOut.size() );
682 log->displayNL( "Position (m): %d %d %d - Local: %d %d %d - Mode: %s", e.posXm(entityIndex), e.posYm(entityIndex), e.posZm(entityIndex), e.posLocalXm(entityIndex), e.posLocalYm(entityIndex), e.posLocalZm(entityIndex), (properties[PROPERTY_POSZ]&0x1)?"Relative":"Absolute" );
683 e.displayProperties( entityIndex, log );
684 // stringstream ss;
685 string str;
686 str += NLMISC::toString(e.propIsInitializedState(0)) + "''"; // skip 1 & 2
687 // ss << e.propIsInitializedState(0) << "''"; // skip 1 & 2
688 /*for ( sint p=0; p!=NB_VISUAL_PROPERTIES; ++p )
690 ss << " " << e.properties[p];
692 nlinfo( "Property values: %s", ss.str().c_str() );
693 ss.clear();*/
694 for ( sint p=3; p!=NB_VISUAL_PROPERTIES; ++p )
696 //ss << e.propIsInitializedState(p);
697 str += NLMISC::toString(e.propIsInitializedState(p));
698 if ( (p+1) % 4 == 0 )
699 //ss << "-";
700 str += "-";
702 log->displayNL( "Initialized: %s", str.c_str() );
707 * Reset assoc/disas counters
709 void CVisionProvider::resetAssocCounter()
711 AssocCounter = 0;
712 DisasCounter = 0;
713 AssocStartTime = CTime::getLocalTime();
718 * Display assoc/disas freqs
720 void CVisionProvider::displayAssocFreqs(CLog *log)
722 float duration = ((float)(CTime::getLocalTime()-AssocStartTime))/1000.0f;
723 log->displayNL( "Assoc: %.1f Hz - Disac: %.1f Hz", ((float)AssocCounter)/duration, ((float)DisasCounter)/duration);
727 NLMISC_COMMAND( displayEntityInfo, "Display the properties of an entity", "<entityIndex>" )
729 // check args, if there s not the right number of parameter, return bad
730 if(args.size() != 1) return false;
732 // get the values
733 TDataSetIndex entityIndex;
734 NLMISC::fromString(args[0], entityIndex);
735 if ( entityIndex < (uint32)TheDataset.maxNbRows() )
737 TDataSetRow datasetrow = TheDataset.getCurrentDataSetRow( entityIndex );
738 CEntity *entity = TheEntityContainer->getEntity( datasetrow );
739 if ( ! TheDataset.getEntityId( datasetrow ).isUnknownId() ) // TODO: unknown or 0 ??
741 CFrontEndService::instance()->PrioSub.VisionProvider.displayEntityInfo( *entity, datasetrow );
742 return true;
745 log.displayNL( "There is no such an entity index" );
746 return true;
750 NLMISC_COMMAND( displayEntityInfoById, "Display the properties of an entity, by entity id (if found)", "<entityId>" )
752 if (args.size() < 1)
753 return false;
755 CEntityId eid;
756 uint64 id;
757 uint type;
758 uint creatorId;
759 uint dynamicId;
760 if (sscanf(args[0].c_str(), "(%" NL_I64 "x:%x:%x:%x)", &id, &type, &creatorId, &dynamicId) != 4)
761 return false;
762 eid.setShortId( id );
763 eid.setType( type );
764 eid.setCreatorId( creatorId );
765 eid.setDynamicId( dynamicId );
767 TEntityIndex entityIndex = TheEntityContainer->entityIdToIndex( eid );
768 if ( entityIndex.isValid() )
770 CEntity* entity = TheEntityContainer->getEntity( entityIndex );
771 if ( ! TheDataset.getEntityId( entityIndex ).isUnknownId() ) // TODO: unknown or 0 ??
773 CFrontEndService::instance()->PrioSub.VisionProvider.displayEntityInfo( *entity, entityIndex );
774 return true;
777 log.displayNL( "There is no entity with the specified id" );
778 return true;
782 NLMISC_COMMAND( displaySlotInfo, "Display info for a particular slot of a client", "<clientid> <slot>" )
784 if ( args.size() < 2 )
785 return false;
787 TClientId clientid;
788 NLMISC::fromString(args[0], clientid);
789 CLFECOMMON::TCLEntityId slot;
790 NLMISC::fromString(args[1], slot);
791 CClientHost *clienthost;
792 if ( (clientid <= MaxNbClients) && ((clienthost = CFrontEndService::instance()->sendSub()->clientIdCont()[clientid]) != NULL) )
794 clienthost->displaySlotProperties( slot, true, &log );
796 return true;
799 NLMISC_COMMAND( resetAssocCounters, "Reset assoc/disas counters", "" )
801 CFrontEndService::instance()->PrioSub.VisionProvider.resetAssocCounter();
802 return true;
805 NLMISC_COMMAND( displayAssocFreqs, "Display assoc/disas freqs", "" )
807 CFrontEndService::instance()->PrioSub.VisionProvider.displayAssocFreqs(&log);
808 return true;
811 /*NLMISC_COMMAND( verboseVision, "Turn on/off or check the state of verbose logging of vision", "" )
813 if ( args.size() == 1 )
815 if ( args[0] == string("on") || args[0] == string("1") )
816 verboseVision=true;
817 else if ( args[0] == string("off") || args[0] == string("0") )
818 verboseVision=false;
821 log.displayNL( "verboseVision is %s", verboseVision ? "on" : "off" );
822 return true;
826 NLMISC_COMMAND( displayVisionLog, "Display Tmp Debug Log", "" )
828 TmpDebugDisplayer->write( &log );
829 return true;