1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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"
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"
46 #include "server_share/r2_variables.h"
49 #include "gpm_service.h"
50 #include "world_position_manager.h"
51 #include "vision_delta_manager.h"
52 #include "client_messages.h"
56 # ifndef NL_COMP_MINGW
60 #endif // NL_OS_WINDOWS
62 // force admin module to link in
63 extern void admin_modules_forceLink();
66 admin_modules_forceLink();
71 using namespace NLMISC
;
72 using namespace NLNET
;
74 CGlobalPositionManagerService
*pCGPMS
= NULL
;
76 NLLIGO::CLigoConfig LigoConfig
;
80 * Get var from config file
83 bool getVarFromConfigFile(CConfigFile
&cf
, const string
&name
, sint32
&variable
, sint32 defaultValue
= 0)
85 CConfigFile::CVar
*ptr
= cf
.getVarPtr(name
);
87 variable
= ((success
= (ptr
!= NULL
)) ? ptr
->asInt() : defaultValue
);
91 bool getVarFromConfigFile(CConfigFile
&cf
, const string
&name
, uint32
&variable
, uint32 defaultValue
= 0)
93 CConfigFile::CVar
*ptr
= cf
.getVarPtr(name
);
95 variable
= ((success
= (ptr
!= NULL
)) ? ptr
->asInt() : defaultValue
);
99 bool getVarFromConfigFile(CConfigFile
&cf
, const string
&name
, bool &variable
, bool defaultValue
= false)
101 CConfigFile::CVar
*ptr
= cf
.getVarPtr(name
);
103 variable
= ((success
= (ptr
!= NULL
)) ? (ptr
->asInt() != 0) : defaultValue
);
107 bool getVarFromConfigFile(CConfigFile
&cf
, const string
&name
, float &variable
, float defaultValue
= 0.0f
)
109 CConfigFile::CVar
*ptr
= cf
.getVarPtr(name
);
111 variable
= ((success
= (ptr
!= NULL
)) ? ptr
->asFloat() : defaultValue
);
115 bool getVarFromConfigFile(CConfigFile
&cf
, const string
&name
, double &variable
, double defaultValue
= 0)
117 CConfigFile::CVar
*ptr
= cf
.getVarPtr(name
);
119 variable
= ((success
= (ptr
!= NULL
)) ? ptr
->asDouble() : defaultValue
);
123 bool getVarFromConfigFile(CConfigFile
&cf
, const string
&name
, string
&variable
, const string
&defaultValue
= string(""))
125 CConfigFile::CVar
*ptr
= cf
.getVarPtr(name
);
127 variable
= ((success
= (ptr
!= NULL
)) ? ptr
->asString() : defaultValue
);
131 #define GET_VAR_FROM_CF(var, def) getVarFromConfigFile(ConfigFile, #var, var, def);
133 /*-----------------------------------------------------------------*\
135 \*-----------------------------------------------------------------*/
136 void cbConnection( const std::string
&serviceName
, NLNET::TServiceId serviceId
, void *arg
)
141 TGameCycle TickStopGameCycle
= 0;
143 /*-----------------------------------------------------------------*\
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 );
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
170 // CUsedContinent::TUsedContinentCont continents = CUsedContinent::instance().getContinents();
172 // vector< string > continentsNames;
173 // for (uint i=0; i<continents.size(); ++i)
175 // continentsNames.push_back(continents[i].ContinentName);
177 ///* CConfigFile::CVar& cvUsedContinents = pCGPMS->ConfigFile.getVar("UsedContinents");
178 // for ( uint i = 0; (sint)i<cvUsedContinents.size(); ++i)
180 // if (cvUsedContinents.asString(i) != "")
182 // continentsNames.push_back(cvUsedContinents.asString(i));
186 // CMessage msgout("USED_CONTINENTS");
187 // msgout.serialCont( continentsNames ),
188 // CUnifiedNetwork::getInstance()->send( "EGS", msgout );
190 // catch(const EUnknownVar &)
192 // nlwarning("<cbEGSConnection> UsedContinents not found, no continent used");
195 // send ESG all IA creatures
196 //CWorldPositionManager::sendAgentsToEGS();
198 } // cbEGSConnection //
200 /*-----------------------------------------------------------------*\
202 \*-----------------------------------------------------------------*/
203 void cbEVSConnection( const std::string
&serviceName
, NLNET::TServiceId serviceId
, void *arg
)
208 /*-----------------------------------------------------------------*\
210 \*-----------------------------------------------------------------*/
211 void cbEVSDisconnection( const std::string
&serviceName
, NLNET::TServiceId serviceId
, void *arg
)
217 /*--------------------------------------------------------------*\
219 \*--------------------------------------------------------------*/
222 // update World Position Manager time
223 if( !TickStopGameCycle
)
225 if (!IsRingShard
) { CWorldPositionManager::setCurrentTick( CTickEventHandler::getGameCycle() ); }
227 nlinfo( "Sync -> %u", CTickEventHandler::getGameCycle() );
235 string
crashCallback()
237 return CWorldPositionManager::getPlayersPosHistory();
242 /****************************************************************\
243 ************** callback table for input message ****************
244 \****************************************************************/
245 TUnifiedCallbackItem CbArray
[] =
247 { "CB_UNUSED", NULL
}
254 void cbMirrorIsReady( CMirror
*mirror
)
256 pCGPMS
->initMirror();
260 /****************************************************************\
262 \****************************************************************/
264 void CGlobalPositionManagerService::init()
266 setVersion (RYZOM_PRODUCT_VERSION
);
268 // keep pointer on class
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
;
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);
308 // World Position Manager init
311 CWorldPositionManager::init(WorldMapSizeX
, WorldMapSizeY
, VisionDistance
, PrimitiveMaxSize
, (uint8
)NbWorldImages
, LoadPacsPrims
, LoadPacsCol
);
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");
326 for (sint i=0; i<v->size()/2; ++i)
329 s1 = v->asString(i*2);
330 s2 = v->asString(i*2+1);
337 // todo: r2 GPMS doesn't read pacs for now - this will have to be fixed later
343 CUsedContinent::TUsedContinentCont continents
= CUsedContinent::instance().getContinents();
344 // CConfigFile::CVar& cvUsedContinents = ConfigFile.getVar("UsedContinents");
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");
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
);
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
;
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 /****************************************************************\
431 \****************************************************************/
433 bool CGlobalPositionManagerService::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);
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
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
);
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();
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
);
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
);
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();
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
);
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;
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 /****************************************************************\
673 \****************************************************************/
674 void CGlobalPositionManagerService::gpmsUpdate()
676 if ( ! pCGPMS
->Mirror
.mirrorIsReady() )
681 // process vision update for non-ring shards
684 // also update internal clock (increase tick counter by one)
685 H_TIME(PositionManagerUpdate
, CWorldPositionManager::update(););
688 for (i
=0; i
<pCGPMS
->Tracked
.size(); ++i
)
689 CWorldPositionManager::displayEntity(CWorldPositionManager::getEntityIndex(pCGPMS
->Tracked
[i
]));
692 // process vision update for ring shards
695 H_AUTO(ringVisionUpdate
);
696 pCGPMS
->RingVisionUniverse
->update();
697 pCGPMS
->RingVisionDeltaManager
->update();
703 /****************************************************************\
705 \****************************************************************/
706 void CGlobalPositionManagerService::release()
708 CMessages::release();
712 CWorldPositionManager::release();
715 CGpmSheets::release();
722 NLNET_SERVICE_MAIN( CGlobalPositionManagerService
, "GPMS", "gpm_service", 0, CbArray
, "", "" );