Add infos into target window
[ryzomcore.git] / ryzom / server / src / gpm_service / gpm_service.cpp
blob90ca5dee59cf370f60065e13e186410a7e9bc4a8
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdpch.h"
23 // misc
24 #include "nel/misc/command.h"
25 #include "nel/misc/vector_2d.h"
26 #include "nel/misc/vectord.h"
27 #include "nel/misc/hierarchical_timer.h"
28 #include "nel/misc/path.h"
29 #include "nel/misc/sheet_id.h"
31 #include "nel/ligo/primitive.h"
32 #include "nel/ligo/ligo_config.h"
34 // game share
35 #include "game_share/tick_event_handler.h"
36 #include "game_share/ryzom_version.h"
37 #include "game_share/mirrored_data_set.h"
38 #include "game_share/ryzom_mirror_properties.h"
39 #include "game_share/mode_and_behaviour.h"
40 #include "game_share/synchronised_message.h"
41 #include "server_share/used_continent.h"
42 #include "server_share/pet_interface_msg.h"
43 #include "game_share/utils.h"
45 // r2 share
46 #include "server_share/r2_variables.h"
48 // local
49 #include "gpm_service.h"
50 #include "world_position_manager.h"
51 #include "vision_delta_manager.h"
52 #include "client_messages.h"
53 #include "sheets.h"
55 #ifdef NL_OS_WINDOWS
56 # ifndef NL_COMP_MINGW
57 # define NOMINMAX
58 # endif
59 # include <windows.h>
60 #endif // NL_OS_WINDOWS
62 // force admin module to link in
63 extern void admin_modules_forceLink();
64 void foo()
66 admin_modules_forceLink();
70 using namespace std;
71 using namespace NLMISC;
72 using namespace NLNET;
74 CGlobalPositionManagerService *pCGPMS= NULL;
76 NLLIGO::CLigoConfig LigoConfig;
80 * Get var from config file
82 // Sint version
83 bool getVarFromConfigFile(CConfigFile &cf, const string &name, sint32 &variable, sint32 defaultValue = 0)
85 CConfigFile::CVar *ptr = cf.getVarPtr(name);
86 bool success;
87 variable = ((success = (ptr != NULL)) ? ptr->asInt() : defaultValue);
88 return success;
90 // Uint version
91 bool getVarFromConfigFile(CConfigFile &cf, const string &name, uint32 &variable, uint32 defaultValue = 0)
93 CConfigFile::CVar *ptr = cf.getVarPtr(name);
94 bool success;
95 variable = ((success = (ptr != NULL)) ? ptr->asInt() : defaultValue);
96 return success;
98 // Bool version
99 bool getVarFromConfigFile(CConfigFile &cf, const string &name, bool &variable, bool defaultValue = false)
101 CConfigFile::CVar *ptr = cf.getVarPtr(name);
102 bool success;
103 variable = ((success = (ptr != NULL)) ? (ptr->asInt() != 0) : defaultValue);
104 return success;
106 // Float version
107 bool getVarFromConfigFile(CConfigFile &cf, const string &name, float &variable, float defaultValue = 0.0f)
109 CConfigFile::CVar *ptr = cf.getVarPtr(name);
110 bool success;
111 variable = ((success = (ptr != NULL)) ? ptr->asFloat() : defaultValue);
112 return success;
114 // Double version
115 bool getVarFromConfigFile(CConfigFile &cf, const string &name, double &variable, double defaultValue = 0)
117 CConfigFile::CVar *ptr = cf.getVarPtr(name);
118 bool success;
119 variable = ((success = (ptr != NULL)) ? ptr->asDouble() : defaultValue);
120 return success;
122 // String version
123 bool getVarFromConfigFile(CConfigFile &cf, const string &name, string &variable, const string &defaultValue = string(""))
125 CConfigFile::CVar *ptr = cf.getVarPtr(name);
126 bool success;
127 variable = ((success = (ptr != NULL)) ? ptr->asString() : defaultValue);
128 return success;
131 #define GET_VAR_FROM_CF(var, def) getVarFromConfigFile(ConfigFile, #var, var, def);
133 /*-----------------------------------------------------------------*\
134 cbConnection
135 \*-----------------------------------------------------------------*/
136 void cbConnection( const std::string &serviceName, NLNET::TServiceId serviceId, void *arg )
138 } // cbConnection //
141 TGameCycle TickStopGameCycle = 0;
143 /*-----------------------------------------------------------------*\
144 cbDisconnection
145 \*-----------------------------------------------------------------*/
146 void cbDisconnection( const std::string &serviceName, NLNET::TServiceId serviceId, void *arg )
148 if( serviceName == string("TICKS") )
150 TickStopGameCycle = CTickEventHandler::getGameCycle();
151 nlinfo( "tick stop -> %u", TickStopGameCycle );
154 // remove all entities created by this service
155 //CWorldPositionManager::removeAiVisionEntitiesForService( serviceId );
156 if (!IsRingShard)
158 CWorldPositionManager::triggerUnsubscribe(serviceId);
161 } // cbDisconnection //
164 void cbEGSConnection( const std::string &serviceName, NLNET::TServiceId serviceId, void *arg )
166 // The follwoing code commented out by Sadge because no refference could be found to reception of this message
167 // // transmit the names of the used continents to the EGS
168 // try
169 // {
170 // CUsedContinent::TUsedContinentCont continents = CUsedContinent::instance().getContinents();
172 // vector< string > continentsNames;
173 // for (uint i=0; i<continents.size(); ++i)
174 // {
175 // continentsNames.push_back(continents[i].ContinentName);
176 // }
177 ///* CConfigFile::CVar& cvUsedContinents = pCGPMS->ConfigFile.getVar("UsedContinents");
178 // for ( uint i = 0; (sint)i<cvUsedContinents.size(); ++i)
179 // {
180 // if (cvUsedContinents.asString(i) != "")
181 // {
182 // continentsNames.push_back(cvUsedContinents.asString(i));
183 // }
184 // }
185 //*/
186 // CMessage msgout("USED_CONTINENTS");
187 // msgout.serialCont( continentsNames ),
188 // CUnifiedNetwork::getInstance()->send( "EGS", msgout );
189 // }
190 // catch(const EUnknownVar &)
191 // {
192 // nlwarning("<cbEGSConnection> UsedContinents not found, no continent used");
193 // }
195 // send ESG all IA creatures
196 //CWorldPositionManager::sendAgentsToEGS();
198 } // cbEGSConnection //
200 /*-----------------------------------------------------------------*\
201 EVSConnection
202 \*-----------------------------------------------------------------*/
203 void cbEVSConnection( const std::string &serviceName, NLNET::TServiceId serviceId, void *arg )
205 EVSUp = true;
208 /*-----------------------------------------------------------------*\
209 EVSDisconnection
210 \*-----------------------------------------------------------------*/
211 void cbEVSDisconnection( const std::string &serviceName, NLNET::TServiceId serviceId, void *arg )
213 EVSUp = false;
217 /*--------------------------------------------------------------*\
218 cbSync()
219 \*--------------------------------------------------------------*/
220 void cbSync()
222 // update World Position Manager time
223 if( !TickStopGameCycle )
225 if (!IsRingShard) { CWorldPositionManager::setCurrentTick( CTickEventHandler::getGameCycle() ); }
227 nlinfo( "Sync -> %u", CTickEventHandler::getGameCycle() );
228 } // cbSync //
233 * Crash Callback
235 string crashCallback()
237 return CWorldPositionManager::getPlayersPosHistory();
242 /****************************************************************\
243 ************** callback table for input message ****************
244 \****************************************************************/
245 TUnifiedCallbackItem CbArray[] =
247 { "CB_UNUSED", NULL }
252 * Initialisation 2
254 void cbMirrorIsReady( CMirror *mirror )
256 pCGPMS->initMirror();
260 /****************************************************************\
261 init()
262 \****************************************************************/
263 // init the service
264 void CGlobalPositionManagerService::init()
266 setVersion (RYZOM_PRODUCT_VERSION);
268 // keep pointer on class
269 pCGPMS = this;
271 // set update time out
272 setUpdateTimeout(100);
274 CUnifiedNetwork::getInstance()->setServiceUpCallback( string("*"), cbConnection, 0);
275 CUnifiedNetwork::getInstance()->setServiceUpCallback( "EGS", cbEGSConnection, 0);
276 CUnifiedNetwork::getInstance()->setServiceUpCallback( "EVS", cbEVSConnection, 0);
278 CUnifiedNetwork::getInstance()->setServiceDownCallback( string("*"), cbDisconnection, 0);
279 CUnifiedNetwork::getInstance()->setServiceDownCallback( "EVS", cbEVSDisconnection, 0);
282 uint32 WorldMapSizeX;
283 uint32 WorldMapSizeY;
284 uint32 VisionDistance;
285 uint32 PrimitiveMaxSize;
286 uint32 NbWorldImages;
287 bool LoadPacsPrims;
288 bool LoadPacsCol;
290 // init the class transport system
291 TRANSPORT_CLASS_REGISTER (CGPMPlayerPrivilegeInst);
293 GET_VAR_FROM_CF(CheckPlayerSpeed, true);
294 GET_VAR_FROM_CF(Verbose, false);
296 GET_VAR_FROM_CF(WorldMapSizeX, 2100);
297 GET_VAR_FROM_CF(WorldMapSizeY, 2970);
298 GET_VAR_FROM_CF(VisionDistance, 250000);
299 GET_VAR_FROM_CF(PrimitiveMaxSize, 8);
300 GET_VAR_FROM_CF(NbWorldImages, 31);
302 GET_VAR_FROM_CF(LoadPacsCol, false);
303 GET_VAR_FROM_CF(LoadPacsPrims, true);
306 CGpmSheets::init();
308 // World Position Manager init
309 if (!IsRingShard)
311 CWorldPositionManager::init(WorldMapSizeX, WorldMapSizeY, VisionDistance, PrimitiveMaxSize, (uint8)NbWorldImages, LoadPacsPrims, LoadPacsCol);
314 // Init ligo
315 if (!LigoConfig.readPrimitiveClass ("world_editor_classes.xml", false))
317 // Should be in R:\leveldesign\world_editor_files
318 nlerror ("Can't load ligo primitive config file world_editor_classes.xml");
320 /* // read the continent name translator
321 map<string, string> translator;
323 CConfigFile::CVar *v = IService::getInstance()->ConfigFile.getVarPtr("ContinentNameTranslator");
324 if (v)
326 for (sint i=0; i<v->size()/2; ++i)
328 string s1, s2;
329 s1 = v->asString(i*2);
330 s2 = v->asString(i*2+1);
331 translator[s1] = s2;
337 // todo: r2 GPMS doesn't read pacs for now - this will have to be fixed later
338 if (!IsRingShard)
340 // init continents
343 CUsedContinent::TUsedContinentCont continents = CUsedContinent::instance().getContinents();
344 // CConfigFile::CVar& cvUsedContinents = ConfigFile.getVar("UsedContinents");
345 // uint i;
346 // for (i=0; (sint)i<cvUsedContinents.size(); ++i)
347 // if (cvUsedContinents.asString(i) != "")
348 for (uint i=0; i<continents.size(); ++i)
350 string name = continents[i].ContinentName;
351 name = CUsedContinent::instance().getPhysicalContinentName(name);
352 // if (translator.find(name) != translator.end())
353 // name = translator[name];
354 // CWorldPositionManager::loadContinent(cvUsedContinents.asString(i), cvUsedContinents.asString(i), i);
355 CWorldPositionManager::loadContinent(name, continents[i].ContinentName, continents[i].ContinentInstance);
358 catch(const EUnknownVar &)
360 nlwarning("<CGlobalPositionManagerService::init> UsedContinents not found, no continent used");
364 NLLIGO::Register();
366 CMessages::init();
367 CClientMessages::init();
370 if (!IsRingShard) { CWorldPositionManager::initPatatManager(); }
372 // Init the mirror system
373 vector<string> datasetNames;
374 datasetNames.push_back( "fe_temp" );
375 Mirror.init( datasetNames, cbMirrorIsReady, gpmsUpdate, cbSync );
376 Mirror.setServiceMirrorUpCallback( "EGS", cbEGSConnection, 0);
378 setCrashCallback(crashCallback);
380 if (IsRingShard)
382 // setup the R2 Vision object and move checker object
383 pCGPMS->RingVisionDeltaManager=new CVisionDeltaManager;
384 pCGPMS->RingVisionUniverse= new R2_VISION::CUniverse;
385 pCGPMS->RingVisionUniverse->registerVisionDeltaManager(RingVisionDeltaManager);
386 pCGPMS->MoveChecker= new CMoveChecker;
389 } // init //
393 * Init after the mirror init
395 void CGlobalPositionManagerService::initMirror()
398 // Allow to add a few entities manually (using the command addEntity)
399 Mirror.declareEntityTypeOwner( RYZOMID::player, 10 );
400 Mirror.declareEntityTypeOwner( RYZOMID::npc, 500 );
403 DataSet = &(Mirror.getDataSet("fe_temp"));
404 DataSet->declareProperty( "X", PSOReadWrite | PSONotifyChanges, "X" ); // group notification on X
405 DataSet->declareProperty( "Y", PSOReadWrite | PSONotifyChanges, "X" ); // group notification on X
406 DataSet->declareProperty( "Z", PSOReadWrite | PSONotifyChanges, "X" ); // group notification on X
407 DataSet->declareProperty( "Theta", PSOReadWrite | PSONotifyChanges, "X" ); // group notification on X
408 DataSet->declareProperty( "AIInstance", PSOReadOnly | PSONotifyChanges );
409 DataSet->declareProperty( "WhoSeesMe", PSOReadOnly | PSONotifyChanges );
410 DataSet->declareProperty( "LocalX", PSOReadWrite );
411 DataSet->declareProperty( "LocalY", PSOReadWrite );
412 DataSet->declareProperty( "LocalZ", PSOReadWrite );
413 DataSet->declareProperty( "TickPos", PSOReadWrite );
414 DataSet->declareProperty( "Sheet", PSOReadWrite );
415 DataSet->declareProperty( "Mode", PSOReadOnly /*| PSONotifyChanges*/ );
416 DataSet->declareProperty( "Behaviour", PSOReadOnly );
417 DataSet->declareProperty( "Cell", PSOReadWrite );
418 DataSet->declareProperty( "VisionCounter", PSOReadWrite );
419 DataSet->declareProperty( "CurrentRunSpeed", PSOReadOnly );
420 DataSet->declareProperty( "CurrentWalkSpeed", PSOReadOnly );
421 DataSet->declareProperty( "RiderEntity", PSOReadOnly );
422 DataSet->declareProperty( "Fuel", PSOReadOnly );
423 initRyzomVisualPropertyIndices( *DataSet );
425 Mirror.setNotificationCallback( IsRingShard? CGlobalPositionManagerService::ringShardProcessMirrorUpdates: CGlobalPositionManagerService::processMirrorUpdates );
429 /****************************************************************\
430 update()
431 \****************************************************************/
432 // main loop
433 bool CGlobalPositionManagerService::update()
435 return true;
436 } // update //
439 void CGlobalPositionManagerService::_checkAddCharacterToRingAIInstance(sint32 aiInstance)
441 TCharactersPerAIInstance::iterator it= _CharactersPerAIInstance.find(aiInstance);
442 if (it==_CharactersPerAIInstance.end())
444 // this is the first character to be added to this instance so initialise it
445 _CharactersPerAIInstance[aiInstance]=1;
446 nlinfo("Creating new AIInstance in ring vision universe: %d",aiInstance);
447 pCGPMS->RingVisionUniverse->createInstance(aiInstance,0);
449 else
451 ++it->second;
452 nldebug("Increasing number of entities in aiInstance %d to %d",aiInstance,it->second);
456 void CGlobalPositionManagerService::_checkRemoveCharacterFromRingAIInstance(sint32 aiInstance)
458 TCharactersPerAIInstance::iterator it= _CharactersPerAIInstance.find(aiInstance);
459 BOMB_IF(it==_CharactersPerAIInstance.end(),NLMISC::toString("BUG: Can't find ai instance %d to remove character from",aiInstance),return);
461 // decrement count of characters in ai instance and remove the instance if its empty
462 --it->second;
463 if (it->second<1)
465 // this was the last character in the instance so delete it
466 nlinfo("removing AIInstance because last character has just left: %d",aiInstance);
467 _CharactersPerAIInstance.erase(it);
468 pCGPMS->RingVisionUniverse->removeInstance(aiInstance);
470 else
472 nldebug("Decreasing number of entities in aiInstance %d to %d",aiInstance,it->second);
476 void CGlobalPositionManagerService::ringShardProcessMirrorUpdates()
478 // Process entities added to mirror
479 TheDataset.beginAddedEntities();
480 TDataSetRow entityIndex = TheDataset.getNextAddedEntity();
481 while ( entityIndex != LAST_CHANGED )
483 // lookup stats for the entity in the mirror
484 const NLMISC::CEntityId &eid= TheDataset.getEntityId( entityIndex );
485 CMirrorPropValueRO<sint32> aiInstance ( TheDataset, entityIndex, DSPropertyAI_INSTANCE );
486 CMirrorPropValueRO<sint32> x ( TheDataset, entityIndex, DSPropertyPOSX );
487 CMirrorPropValueRO<sint32> y ( TheDataset, entityIndex, DSPropertyPOSY );
488 CMirrorPropValueRO<TYPE_WHO_SEES_ME> whoSeesMe ( TheDataset, entityIndex, DSPropertyWHO_SEES_ME );
489 R2_VISION::TInvisibilityLevel invisibility= (R2_VISION::TInvisibilityLevel)(whoSeesMe&((1<<R2_VISION::NUM_WHOSEESME_BITS)-1));
491 // increment count of number of characters in AIInstance, instanciating new instance if required
492 pCGPMS->_checkAddCharacterToRingAIInstance(aiInstance);
494 // if we have a player then set them up in the move checker
495 if (eid.getType()==RYZOMID::player)
497 pCGPMS->MoveChecker->teleport(entityIndex, x, y, CTickEventHandler::getGameCycle());
500 // add entity to the ring vision universe object
501 pCGPMS->RingVisionUniverse->addEntity(entityIndex,aiInstance,x,y,invisibility,eid.getType()==RYZOMID::player);
502 entityIndex = TheDataset.getNextAddedEntity();
504 TheDataset.endAddedEntities();
506 // Process entities removed from mirror
507 TheDataset.beginRemovedEntities();
508 CEntityId *id;
509 entityIndex = TheDataset.getNextRemovedEntity( &id );
510 while ( entityIndex != LAST_CHANGED )
512 // check that the character being removed exists in the r2VisionUniverse and get hold of their AIInstance
513 const R2_VISION::SUniverseEntity* theEntity= pCGPMS->RingVisionUniverse->getEntity(entityIndex);
514 BOMB_IF(theEntity==NULL,"Failed to identify the character that the mirror tells us is being removed",continue);
515 uint32 aiInstance= theEntity->AIInstance;
517 // remove entity from the ring vision universe object
518 pCGPMS->RingVisionUniverse->removeEntity(entityIndex);
520 // decrement the count of characters in the given instance and remove it if need be
521 pCGPMS->_checkRemoveCharacterFromRingAIInstance(aiInstance);
523 // prepare to iterate...
524 entityIndex = TheDataset.getNextRemovedEntity( &id );
526 TheDataset.endRemovedEntities();
528 // Process properties changed and notified in the mirror
529 TPropertyIndex propIndex;
530 TheDataset.beginChangedValues();
531 TheDataset.getNextChangedValue( entityIndex, propIndex );
532 while ( entityIndex != LAST_CHANGED )
534 if (propIndex == DSPropertyAI_INSTANCE)
536 // lookup stats for the entity in the mirror
537 sint32 aiInstance= CMirrorPropValueRO<sint32>( TheDataset, entityIndex, DSPropertyAI_INSTANCE );
538 sint32 x= CMirrorPropValueRO<sint32>( TheDataset, entityIndex, DSPropertyPOSX );
539 sint32 y= CMirrorPropValueRO<sint32>( TheDataset, entityIndex, DSPropertyPOSY );
540 CMirrorPropValueRO<TYPE_WHO_SEES_ME> whoSeesMe ( TheDataset, entityIndex, DSPropertyWHO_SEES_ME );
541 R2_VISION::TInvisibilityLevel invisibility= (R2_VISION::TInvisibilityLevel)(whoSeesMe&((1<<R2_VISION::NUM_WHOSEESME_BITS)-1));
543 // if we have a player then remove them from the move checker
544 if (TheDataset.getEntityId(entityIndex).getType()==RYZOMID::player)
546 pCGPMS->MoveChecker->teleport(entityIndex, x, y, CTickEventHandler::getGameCycle());
549 // check that the character being teleported exists in the r2VisionUniverse and get hold of their old AIInstance
550 const R2_VISION::SUniverseEntity* theEntity= pCGPMS->RingVisionUniverse->getEntity(entityIndex);
551 BOMB_IF(theEntity==NULL, "Failed to identify the character that the mirror tells us is being removed",
552 TheDataset.getNextChangedValue( entityIndex, propIndex ); continue);
553 sint32 oldAiInstance= theEntity->AIInstance;
555 // check whether this is a real teleportation or just a move
556 if (oldAiInstance==aiInstance)
558 // the aiInstance hasn't changed so just perform a move
559 // note: this happens systematicaly on appearance of a new entity - the ai instance is
560 // setup once via code that manages appearance of new entities in mirror and it's setup
561 // again here... the coordinates are probably the same too but since I can't guarantee
562 // it I prefer to let the code do its stuff
563 pCGPMS->RingVisionUniverse->setEntityPosition(entityIndex,x,y);
565 else
567 // make sure the instance we're teleporting to exists
568 pCGPMS->_checkAddCharacterToRingAIInstance(aiInstance);
570 // teleport entity within the ring vision universe
571 pCGPMS->RingVisionUniverse->teleportEntity(entityIndex,aiInstance,x,y,invisibility);
573 // if this was the last entity in their old instance then get rid of the instance
574 pCGPMS->_checkRemoveCharacterFromRingAIInstance(oldAiInstance);
577 else if (propIndex == DSPropertyPOSX)
579 // lookup stats for the entity in the mirror
580 CMirrorPropValueRO<sint32> x ( TheDataset, entityIndex, DSPropertyPOSX );
581 CMirrorPropValueRO<sint32> y ( TheDataset, entityIndex, DSPropertyPOSY );
583 // update the cell
584 CMirrorPropValue1DS<TYPE_CELL> cell ( TheDataset, entityIndex, DSPropertyCELL );
585 uint32 cx = (uint16) ( + x()/CWorldPositionManager::getCellSize() );
586 uint32 cy = (uint16) ( - y()/CWorldPositionManager::getCellSize() );
588 cell = (cx<<16) + cy;
590 // move entity within the ring vision universe
591 pCGPMS->RingVisionUniverse->setEntityPosition(entityIndex,x,y);
593 else if (propIndex == DSPropertyWHO_SEES_ME)
595 // lookup stats for the entity in the mirror
596 CMirrorPropValueRO<TYPE_WHO_SEES_ME> whoSeesMe ( TheDataset, entityIndex, DSPropertyWHO_SEES_ME );
598 uint32 visibilityValue= ((uint32)whoSeesMe==0)? R2_VISION::WHOSEESME_INVISIBLE_DM: ((uint32)(whoSeesMe+1)==0)? R2_VISION::WHOSEESME_VISIBLE_MOB: (uint32)whoSeesMe;
600 // apply the change to the entity
601 pCGPMS->RingVisionUniverse->setEntityInvisibilityInfo(entityIndex, visibilityValue);
603 TheDataset.getNextChangedValue( entityIndex, propIndex );
605 TheDataset.endChangedValues();
608 void CGlobalPositionManagerService::processMirrorUpdates()
610 // Process entities added to mirror
611 TheDataset.beginAddedEntities();
612 TDataSetRow entityIndex = TheDataset.getNextAddedEntity();
613 while ( entityIndex != LAST_CHANGED )
615 //nldebug( "%u: OnAddEntity %d", CTickEventHandler::getGameCycle(), entityIndex );
616 CWorldPositionManager::onAddEntity( entityIndex );
617 entityIndex = TheDataset.getNextAddedEntity();
619 TheDataset.endAddedEntities();
621 // Process entities removed from mirror
622 TheDataset.beginRemovedEntities();
623 CEntityId *id;
624 entityIndex = TheDataset.getNextRemovedEntity( &id );
625 while ( entityIndex != LAST_CHANGED )
627 //nldebug( "%u: OnRemoveEntity %d", CTickEventHandler::getGameCycle(), entityIndex );
628 CWorldPositionManager::onRemoveEntity(entityIndex);
629 entityIndex = TheDataset.getNextRemovedEntity( &id );
631 TheDataset.endRemovedEntities();
633 // Process properties changed and notified in the mirror
634 TPropertyIndex propIndex;
635 TheDataset.beginChangedValues();
636 TheDataset.getNextChangedValue( entityIndex, propIndex );
637 while ( entityIndex != LAST_CHANGED )
639 //nldebug( "%u: OnPosChange %d", CTickEventHandler::getGameCycle(), entityIndex );
640 //nlassert( propIndex == DSPropertyPOSX ); // (X, Y, Z, Theta) use "group notification" with prop X (and are the only ones with notification)
642 if (propIndex == DSPropertyPOSX)
644 // TEMP: while we don't handle all by entity indices, we need to test if the entityId has been notified (added)
645 CWorldEntity *entity = CWorldPositionManager::getEntityPtr(entityIndex);
646 if (entity)
648 if (entity->getType() == CWorldEntity::Player && entity->CheckMotion)
650 // this is a player and has to check motion
651 // then reset the player position according to the mirror pos
652 H_AUTO(gpmsUpdateResetServerPosition);
653 CWorldPositionManager::resetPrimitive(entity);
654 entity->PosInitialised = true;
656 else
658 H_AUTO(gpmsUpdateServerPosition);
659 //nlinfo("Update %s pos: %d,%d,%d - %d", entity->Id.toString().c_str(), entity->X(), entity->Y(), entity->Z(), entity->X.getWriterServiceId());
660 CWorldPositionManager::updateEntityPosition(entity);
664 //nldebug( "Pos changed from mirror E%d", entityIndex );
665 TheDataset.getNextChangedValue( entityIndex, propIndex );
667 TheDataset.endChangedValues();
671 /****************************************************************\
672 gpmsUpdate()
673 \****************************************************************/
674 void CGlobalPositionManagerService::gpmsUpdate()
676 if ( ! pCGPMS->Mirror.mirrorIsReady() )
677 return;
679 H_AUTO(gpmsUpdate);
681 // process vision update for non-ring shards
682 if (!IsRingShard)
684 // also update internal clock (increase tick counter by one)
685 H_TIME(PositionManagerUpdate, CWorldPositionManager::update(););
687 uint i;
688 for (i=0; i<pCGPMS->Tracked.size(); ++i)
689 CWorldPositionManager::displayEntity(CWorldPositionManager::getEntityIndex(pCGPMS->Tracked[i]));
692 // process vision update for ring shards
693 if (IsRingShard)
695 H_AUTO(ringVisionUpdate);
696 pCGPMS->RingVisionUniverse->update();
697 pCGPMS->RingVisionDeltaManager->update();
700 } // gpmsUpdate //
703 /****************************************************************\
704 release()
705 \****************************************************************/
706 void CGlobalPositionManagerService::release()
708 CMessages::release();
710 if (!IsRingShard)
712 CWorldPositionManager::release();
715 CGpmSheets::release();
717 }// release //
722 NLNET_SERVICE_MAIN( CGlobalPositionManagerService, "GPMS", "gpm_service", 0, CbArray, "", "" );