void MapMgr::LoadAllCells() { // eek MapCell * cellInfo; CellSpawns * spawns; for( uint32 x = 0 ; x < _sizeX ; x ++ ) { for( uint32 y = 0 ; y < _sizeY ; y ++ ) { cellInfo = GetCell( x , y ); if( !cellInfo ) { // Cell doesn't exist, create it. // There is no spoon. Err... cell. cellInfo = Create( x , y ); cellInfo->Init( x , y , _mapId , this ); sLog.outDetail( "Created cell [%u,%u] on map %d (instance %d)." , x , y , _mapId , m_instanceID ); cellInfo->SetActivity( true ); _map->CellGoneActive( x , y ); ASSERT( !cellInfo->IsLoaded() ); spawns = _map->GetSpawnsList( x , y ); if( spawns ) cellInfo->LoadObjects( spawns ); } else { // Cell exists, but is inactive if ( !cellInfo->IsActive() ) { sLog.outDetail("Activated cell [%u,%u] on map %d (instance %d).", x, y, _mapId, m_instanceID ); _map->CellGoneActive( x , y ); cellInfo->SetActivity( true ); if (!cellInfo->IsLoaded()) { //sLog.outDetail("Loading objects for Cell [%d][%d] on map %d (instance %d)...", // posX, posY, this->_mapId, m_instanceID); spawns = _map->GetSpawnsList( x , y ); if( spawns ) cellInfo->LoadObjects( spawns ); } } } } } }
void MapMgr::ChangeObjectLocation( Object *obj ) { // Items and containers are of no interest for us if( obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetMapMgr() != this ) { return; } Player* plObj; ByteBuffer * buf = 0; if( obj->GetTypeId() == TYPEID_PLAYER ) { plObj = static_cast< Player* >( obj ); } else { plObj = NULL; } Object* curObj; float fRange; /////////////////////////////////////// // Update in-range data for old objects /////////////////////////////////////// /** let's duplicate some code here :P Less branching is always good. * - Burlex */ /*#define IN_RANGE_LOOP \ for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(), iter2; \ iter != obj->GetInRangeSetEnd();) \ { \ curObj = *iter; \ iter2 = iter; \ ++iter; \ if(curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) \ fRange = 0.0f; \ else if((curObj->GetGUIDHigh() == HIGHGUID_TRANSPORTER || obj->GetGUIDHigh() == HIGHGUID_TRANSPORTER)) \ fRange = 0.0f; \ else if((curObj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && curObj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT || obj->GetGUIDHigh() == HIGHGUID_GAMEOBJECT && obj->GetUInt32Value(GAMEOBJECT_TYPE_ID) == GAMEOBJECT_TYPE_TRANSPORT)) \ fRange = 0.0f; \ else \ fRange = m_UpdateDistance; \ if (curObj->GetDistance2dSq(obj) > fRange && fRange > 0) \ #define END_IN_RANGE_LOOP } \ if(plObj) { IN_RANGE_LOOP { plObj->RemoveIfVisible(curObj); plObj->RemoveInRangeObject(iter2); if(curObj->NeedsInRangeSet()) curObj->RemoveInRangeObject(obj); if(curObj->IsPlayer()) static_cast< Player* >( curObj )->RemoveIfVisible(obj); } END_IN_RANGE_LOOP } else if(obj->NeedsInRangeSet()) { IN_RANGE_LOOP { if(curObj->NeedsInRangeSet()) curObj->RemoveInRangeObject(obj); if(curObj->IsPlayer()) static_cast< Player* >( curObj )->RemoveIfVisible(obj); obj->RemoveInRangeObject(iter2); } END_IN_RANGE_LOOP } else { IN_RANGE_LOOP { if(curObj->NeedsInRangeSet()) curObj->RemoveInRangeObject(obj); if(curObj->IsPlayer()) { static_cast< Player* >( curObj )->RemoveIfVisible(obj); obj->RemoveInRangePlayer(curObj); } } END_IN_RANGE_LOOP } #undef IN_RANGE_LOOP #undef END_IN_RANGE_LOOP*/ if(obj->HasInRangeObjects()) { for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(), iter2; iter != obj->GetInRangeSetEnd();) { curObj = *iter; iter2 = iter++; if( curObj->IsPlayer() && obj->IsPlayer() && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) fRange = 0.0f; // unlimited distance for people on same boat else if( curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER ) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) else fRange = m_UpdateDistance; // normal distance if( fRange > 0.0f && curObj->GetDistance2dSq(obj) > fRange ) { if( plObj ) plObj->RemoveIfVisible(curObj); if( curObj->IsPlayer() ) static_cast< Player* >( curObj )->RemoveIfVisible(obj); curObj->RemoveInRangeObject(obj); if( obj->GetMapMgr() != this ) { /* Something removed us. */ return; } obj->RemoveInRangeObject(iter2); } } } /////////////////////////// // Get new cell coordinates /////////////////////////// if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX || obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) { if(obj->IsPlayer()) { Player* plr = static_cast< Player* >( obj ); if(plr->GetBindMapId() != GetMapId()) { plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition()); plr->GetSession()->SendPacket(data); delete data; } } else { obj->GetPositionV()->ChangeCoords(0,0,0,0); } } uint32 cellX = GetPosX(obj->GetPositionX()); uint32 cellY = GetPosY(obj->GetPositionY()); if(cellX >= _sizeX || cellY >= _sizeY) { return; } MapCell *objCell = GetCell(cellX, cellY); MapCell * pOldCell = obj->GetMapCell(); if (!objCell) { objCell = Create(cellX,cellY); objCell->Init(cellX, cellY, _mapId, this); } // If object moved cell if (objCell != obj->GetMapCell()) { // THIS IS A HACK! // Current code, if a creature on a long waypoint path moves from an active // cell into an inactive one, it will disable itself and will never return. // This is to prevent cpu leaks. I will think of a better solution very soon :P if(!objCell->IsActive() && !plObj && obj->Active) obj->Deactivate(this); if(obj->GetMapCell()) obj->GetMapCell()->RemoveObject(obj); objCell->AddObject(obj); obj->SetMapCell(objCell); // if player we need to update cell activity // radius = 2 is used in order to update both // old and new cells if(obj->GetTypeId() == TYPEID_PLAYER) { // have to unlock/lock here to avoid a deadlock situation. UpdateCellActivity(cellX, cellY, 2); if( pOldCell != NULL ) { // only do the second check if theres -/+ 2 difference if( abs( (int)cellX - (int)pOldCell->_x ) > 2 || abs( (int)cellY - (int)pOldCell->_y ) > 2 ) { UpdateCellActivity( pOldCell->_x, pOldCell->_y, 2 ); } } } } ////////////////////////////////////// // Update in-range set for new objects ////////////////////////////////////// uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX-1); uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY-1); uint32 startX = cellX > 0 ? cellX - 1 : 0; uint32 startY = cellY > 0 ? cellY - 1 : 0; uint32 posX, posY; MapCell *cell; MapCell::ObjectSet::iterator iter; for (posX = startX; posX <= endX; ++posX ) { for (posY = startY; posY <= endY; ++posY ) { cell = GetCell(posX, posY); if (cell) UpdateInRangeSet(obj, plObj, cell, &buf); } } if(buf) delete buf; }
void MapMgr::PushObject(Object *obj) { ///////////// // Assertions ///////////// ASSERT(obj); // That object types are not map objects. TODO: add AI groups here? if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER) { // mark object as updatable and exit return; } if(obj->GetTypeId() == TYPEID_CORPSE) { m_corpses.insert(((Corpse*)obj)); } obj->ClearInRangeSet(); ASSERT(obj->GetMapId() == _mapId); if(!(obj->GetPositionX() < _maxX && obj->GetPositionX() > _minX) || !(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY)) { if(obj->IsPlayer()) { Player * plr = static_cast< Player* >( obj ); if(plr->GetBindMapId() != GetMapId()) { plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition()); plr->GetSession()->SendPacket(data); delete data; } } else { obj->GetPositionV()->ChangeCoords(0,0,0,0); } } ASSERT(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY); ASSERT(_cells); /////////////////////// // Get cell coordinates /////////////////////// uint32 x = GetPosX(obj->GetPositionX()); uint32 y = GetPosY(obj->GetPositionY()); if(x >= _sizeX || y >= _sizeY) { if(obj->IsPlayer()) { Player * plr = static_cast< Player* >( obj ); if(plr->GetBindMapId() != GetMapId()) { plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); WorldPacket * data = plr->BuildTeleportAckMsg(plr->GetPosition()); plr->GetSession()->SendPacket(data); delete data; } } else { obj->GetPositionV()->ChangeCoords(0,0,0,0); } x = GetPosX(obj->GetPositionX()); y = GetPosY(obj->GetPositionY()); } MapCell *objCell = GetCell(x,y); if (!objCell) { objCell = Create(x,y); objCell->Init(x, y, _mapId, this); } uint32 endX = (x <= _sizeX) ? x + 1 : (_sizeX-1); uint32 endY = (y <= _sizeY) ? y + 1 : (_sizeY-1); uint32 startX = x > 0 ? x - 1 : 0; uint32 startY = y > 0 ? y - 1 : 0; uint32 posX, posY; MapCell *cell; MapCell::ObjectSet::iterator iter; ByteBuffer * buf = 0; uint32 count; Player *plObj; if(obj->GetTypeId() == TYPEID_PLAYER) plObj = static_cast< Player* >( obj ); else plObj = NULL; if(plObj) { sLog.outDetail("Creating player "I64FMT" for himself.", obj->GetGUID()); ByteBuffer pbuf(10000); count = plObj->BuildCreateUpdateBlockForPlayer(&pbuf, plObj); plObj->PushCreationData(&pbuf, count); } ////////////////////// // Build in-range data ////////////////////// for (posX = startX; posX <= endX; posX++ ) { for (posY = startY; posY <= endY; posY++ ) { cell = GetCell(posX, posY); if (cell) { UpdateInRangeSet(obj, plObj, cell, &buf); } } } //Add to the cell's object list objCell->AddObject(obj); obj->SetMapCell(objCell); //Add to the mapmanager's object list if(plObj) { m_PlayerStorage[plObj->GetLowGUID()] = plObj; UpdateCellActivity(x, y, 2); } else { switch(obj->GetTypeFromGUID()) { case HIGHGUID_TYPE_PET: m_PetStorage[obj->GetUIdFromGUID()] = static_cast< Pet* >( obj ); break; case HIGHGUID_TYPE_UNIT: { ASSERT((obj->GetUIdFromGUID()) <= m_CreatureHighGuid); m_CreatureStorage[obj->GetUIdFromGUID()] = (Creature*)obj; if(((Creature*)obj)->m_spawn != NULL) { _sqlids_creatures.insert(make_pair( ((Creature*)obj)->m_spawn->id, ((Creature*)obj) ) ); } }break; case HIGHGUID_TYPE_GAMEOBJECT: { m_GOStorage[obj->GetUIdFromGUID()] = (GameObject*)obj; if(((GameObject*)obj)->m_spawn != NULL) { _sqlids_gameobjects.insert(make_pair( ((GameObject*)obj)->m_spawn->id, ((GameObject*)obj) ) ); } }break; case HIGHGUID_TYPE_DYNAMICOBJECT: m_DynamicObjectStorage[obj->GetLowGUID()] = (DynamicObject*)obj; break; } } // Handle activation of that object. if(objCell->IsActive() && obj->CanActivate()) obj->Activate(this); // Add the session to our set if it is a player. if(plObj) { Sessions.insert(plObj->GetSession()); // Change the instance ID, this will cause it to be removed from the world thread (return value 1) plObj->GetSession()->SetInstance(GetInstanceID()); /* Add the map wide objects */ if(_mapWideStaticObjects.size()) { if(!buf) buf = new ByteBuffer(300); for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr) { count = (*itr)->BuildCreateUpdateBlockForPlayer(buf, plObj); plObj->PushCreationData(buf, count); } } } if(buf) delete buf; if(plObj && InactiveMoveTime && !forced_expire) InactiveMoveTime = 0; }
void MapMgr::UpdateCellActivity(uint32 x, uint32 y, int radius) { CellSpawns * sp; uint32 endX = (x + radius) <= _sizeX ? x + radius : (_sizeX-1); uint32 endY = (y + radius) <= _sizeY ? y + radius : (_sizeY-1); uint32 startX = x - radius > 0 ? x - radius : 0; uint32 startY = y - radius > 0 ? y - radius : 0; uint32 posX, posY; MapCell *objCell; for (posX = startX; posX <= endX; posX++ ) { for (posY = startY; posY <= endY; posY++ ) { objCell = GetCell(posX, posY); if (!objCell) { if (_CellActive(posX, posY)) { objCell = Create(posX, posY); objCell->Init(posX, posY, _mapId, this); sLog.outDetail("Cell [%d,%d] on map %d (instance %d) is now active.", posX, posY, this->_mapId, m_instanceID); objCell->SetActivity(true); _map->CellGoneActive(posX, posY); ASSERT(!objCell->IsLoaded()); sLog.outDetail("Loading objects for Cell [%d][%d] on map %d (instance %d)...", posX, posY, this->_mapId, m_instanceID); sp = _map->GetSpawnsList(posX, posY); if(sp) objCell->LoadObjects(sp); } } else { //Cell is now active if (_CellActive(posX, posY) && !objCell->IsActive()) { sLog.outDetail("Cell [%d,%d] on map %d (instance %d) is now active.", posX, posY, this->_mapId, m_instanceID); _map->CellGoneActive(posX, posY); objCell->SetActivity(true); if (!objCell->IsLoaded()) { sLog.outDetail("Loading objects for Cell [%d][%d] on map %d (instance %d)...", posX, posY, this->_mapId, m_instanceID); sp = _map->GetSpawnsList(posX, posY); if(sp) objCell->LoadObjects(sp); } } //Cell is no longer active else if (!_CellActive(posX, posY) && objCell->IsActive()) { sLog.outDetail("Cell [%d,%d] on map %d (instance %d) is now idle.", posX, posY, this->_mapId, m_instanceID); _map->CellGoneIdle(posX, posY); objCell->SetActivity(false); } } } } }
void MapMgr::ChangeObjectLocation(Object* obj) { /* if ( !obj ) return; // crashfix */ ARCEMU_ASSERT(obj != NULL); // Items and containers are of no interest for us if(obj->IsItem() || obj->IsContainer() || obj->GetMapMgr() != this) { return; } Player* plObj = NULL; ByteBuffer* buf = 0; if(obj->IsPlayer()) { plObj = TO< Player* >(obj); } Object* curObj; float fRange = 0.0f; /////////////////////////////////////// // Update in-range data for old objects /////////////////////////////////////// if(obj->HasInRangeObjects()) { for(Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd();) { curObj = *iter; ++iter; if(curObj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid) fRange = 0.0f; // unlimited distance for people on same boat else if(curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER) fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; //If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it... else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId()) fRange = 0.0f; else if(curObj->IsPlayer() && TO< Player* >(curObj)->GetFarsightTarget() == obj->GetGUID()) fRange = 0.0f;//Mind Vision, Eye of Kilrogg else fRange = m_UpdateDistance; // normal distance if(fRange > 0.0f && (curObj->GetDistance2dSq(obj) > fRange)) { if(plObj != NULL) plObj->RemoveIfVisible(curObj->GetGUID()); if(curObj->IsPlayer()) TO< Player* >(curObj)->RemoveIfVisible(obj->GetGUID()); curObj->RemoveInRangeObject(obj); if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } obj->RemoveInRangeObject(curObj); } } } /////////////////////////// // Get new cell coordinates /////////////////////////// if(obj->GetMapMgr() != this) { /* Something removed us. */ return; } if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX || obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) { if(plObj != NULL) { if(plObj->GetBindMapId() != GetMapId()) { plObj->SafeTeleport(plObj->GetBindMapId(), 0, plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0); plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0); plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); plObj->SendTeleportAckMsg(plObj->GetPosition()); } } else { obj->GetPositionV()->ChangeCoords(0, 0, 0, 0); } } uint32 cellX = GetPosX(obj->GetPositionX()); uint32 cellY = GetPosY(obj->GetPositionY()); if(cellX >= _sizeX || cellY >= _sizeY) { return; } MapCell* objCell = GetCell(cellX, cellY); MapCell* pOldCell = obj->GetMapCell(); if(objCell == NULL) { objCell = Create(cellX, cellY); objCell->Init(cellX, cellY, this); } ARCEMU_ASSERT(objCell != NULL); // If object moved cell if(objCell != pOldCell) { // THIS IS A HACK! // Current code, if a creature on a long waypoint path moves from an active // cell into an inactive one, it will disable itself and will never return. // This is to prevent cpu leaks. I will think of a better solution very soon :P if(!objCell->IsActive() && !plObj && obj->IsActive()) obj->Deactivate(this); if(pOldCell != NULL) pOldCell->RemoveObject(obj); objCell->AddObject(obj); obj->SetMapCell(objCell); // if player we need to update cell activity // radius = 2 is used in order to update both // old and new cells if(obj->IsPlayer()) { // have to unlock/lock here to avoid a deadlock situation. UpdateCellActivity(cellX, cellY, 2); if(pOldCell != NULL) { // only do the second check if there's -/+ 2 difference if(abs((int)cellX - (int)pOldCell->_x) > 2 || abs((int)cellY - (int)pOldCell->_y) > 2) { UpdateCellActivity(pOldCell->_x, pOldCell->_y, 2); } } } } ////////////////////////////////////// // Update in-range set for new objects ////////////////////////////////////// uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX - 1); uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY - 1); uint32 startX = cellX > 0 ? cellX - 1 : 0; uint32 startY = cellY > 0 ? cellY - 1 : 0; uint32 posX, posY; MapCell* cell; //If the object announcing it's position is a special one, then it should do so in a much wider area - like the distance between the two transport towers in Orgrimmar, or more. - By: VLack if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_ONMOVEWIDE)) { endX = cellX + 5 <= _sizeX ? cellX + 6 : (_sizeX - 1); endY = cellY + 5 <= _sizeY ? cellY + 6 : (_sizeY - 1); startX = cellX > 5 ? cellX - 6 : 0; startY = cellY > 5 ? cellY - 6 : 0; } for(posX = startX; posX <= endX; ++posX) { for(posY = startY; posY <= endY; ++posY) { cell = GetCell(posX, posY); if(cell) UpdateInRangeSet(obj, plObj, cell, &buf); } } if(buf) delete buf; }
void MapMgr::PushObject(Object* obj) { ///////////// // Assertions ///////////// ARCEMU_ASSERT(obj != NULL); // That object types are not map objects. TODO: add AI groups here? if(obj->IsItem() || obj->IsContainer()) { // mark object as updatable and exit return; } if(obj->IsCorpse()) { m_corpses.insert(TO< Corpse* >(obj)); } obj->ClearInRangeSet(); ARCEMU_ASSERT(obj->GetMapId() == _mapId); if(!(obj->GetPositionX() < _maxX && obj->GetPositionX() > _minX) || !(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY)) { if(obj->IsPlayer()) { Player* plr = TO< Player* >(obj); if(plr->GetBindMapId() != GetMapId()) { plr->SafeTeleport(plr->GetBindMapId(), 0, plr->GetBindPositionX(), plr->GetBindPositionY(), plr->GetBindPositionZ(), 0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(), plr->GetBindPositionY(), plr->GetBindPositionZ(), 0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); plr->SendTeleportAckMsg(plr->GetPosition()); } } else { obj->GetPositionV()->ChangeCoords(0, 0, 0, 0); } } ARCEMU_ASSERT(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY); ARCEMU_ASSERT(_cells != NULL); /////////////////////// // Get cell coordinates /////////////////////// uint32 x = GetPosX(obj->GetPositionX()); uint32 y = GetPosY(obj->GetPositionY()); if(x >= _sizeX || y >= _sizeY) { if(obj->IsPlayer()) { Player* plr = TO< Player* >(obj); if(plr->GetBindMapId() != GetMapId()) { plr->SafeTeleport(plr->GetBindMapId(), 0, plr->GetBindPositionX(), plr->GetBindPositionY(), plr->GetBindPositionZ(), 0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); return; } else { obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(), plr->GetBindPositionY(), plr->GetBindPositionZ(), 0); plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); plr->SendTeleportAckMsg(plr->GetPosition()); } } else { obj->GetPositionV()->ChangeCoords(0, 0, 0, 0); } x = GetPosX(obj->GetPositionX()); y = GetPosY(obj->GetPositionY()); } MapCell* objCell = GetCell(x, y); if(objCell == NULL) { objCell = Create(x, y); objCell->Init(x, y, this); } ARCEMU_ASSERT(objCell != NULL); uint32 endX = (x <= _sizeX) ? x + 1 : (_sizeX - 1); uint32 endY = (y <= _sizeY) ? y + 1 : (_sizeY - 1); uint32 startX = x > 0 ? x - 1 : 0; uint32 startY = y > 0 ? y - 1 : 0; uint32 posX, posY; MapCell* cell; //MapCell::ObjectSet::iterator iter; ByteBuffer* buf = 0; uint32 count; Player* plObj; if(obj->IsPlayer()) plObj = TO< Player* >(obj); else plObj = NULL; if(plObj != NULL) { LOG_DETAIL("Creating player " I64FMT " for himself.", obj->GetGUID()); ByteBuffer pbuf(10000); count = plObj->BuildCreateUpdateBlockForPlayer(&pbuf, plObj); plObj->PushCreationData(&pbuf, count); } ////////////////////// // Build in-range data ////////////////////// for(posX = startX; posX <= endX; posX++) { for(posY = startY; posY <= endY; posY++) { cell = GetCell(posX, posY); if(cell) { UpdateInRangeSet(obj, plObj, cell, &buf); } } } //Add to the cell's object list objCell->AddObject(obj); obj->SetMapCell(objCell); //Add to the mapmanager's object list if(plObj != NULL) { m_PlayerStorage[plObj->GetLowGUID()] = plObj; UpdateCellActivity(x, y, 2); } else { switch(obj->GetTypeFromGUID()) { case HIGHGUID_TYPE_PET: m_PetStorage[obj->GetUIdFromGUID()] = TO< Pet* >(obj); break; case HIGHGUID_TYPE_UNIT: case HIGHGUID_TYPE_VEHICLE: { ARCEMU_ASSERT(obj->GetUIdFromGUID() <= m_CreatureHighGuid); CreatureStorage[ obj->GetUIdFromGUID() ] = TO< Creature* >(obj); if(TO_CREATURE(obj)->m_spawn != NULL) { _sqlids_creatures.insert(make_pair(TO_CREATURE(obj)->m_spawn->id, TO_CREATURE(obj))); } } break; case HIGHGUID_TYPE_GAMEOBJECT: { GOStorage[ obj->GetUIdFromGUID() ] = TO< GameObject* >(obj); if(TO_GAMEOBJECT(obj)->m_spawn != NULL) { _sqlids_gameobjects.insert(make_pair(TO_GAMEOBJECT(obj)->m_spawn->id, TO_GAMEOBJECT(obj))); } } break; case HIGHGUID_TYPE_DYNAMICOBJECT: m_DynamicObjectStorage[obj->GetLowGUID()] = (DynamicObject*)obj; break; } } // Handle activation of that object. if(objCell->IsActive() && obj->CanActivate()) obj->Activate(this); // Add the session to our set if it is a player. if(plObj != NULL) { Sessions.insert(plObj->GetSession()); // Change the instance ID, this will cause it to be removed from the world thread (return value 1) plObj->GetSession()->SetInstance(GetInstanceID()); /* Add the map wide objects */ if(_mapWideStaticObjects.size()) { uint32 globalcount = 0; if(!buf) buf = new ByteBuffer(300); for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr) { count = (*itr)->BuildCreateUpdateBlockForPlayer(buf, plObj); globalcount += count; } //VLack: It seems if we use the same buffer then it is a BAD idea to try and push created data one by one, add them at once! // If you try to add them one by one, then as the buffer already contains data, they'll end up repeating some object. // Like 6 object updates for Deeprun Tram, but the built package will contain these entries: 2AFD0, 2AFD0, 2AFD1, 2AFD0, 2AFD1, 2AFD2 if(globalcount > 0) plObj->PushCreationData(buf, globalcount); } } if(buf) delete buf; if(plObj != NULL && InactiveMoveTime && !forced_expire) InactiveMoveTime = 0; }
void MapMgr::UpdateCellActivity(uint32 x, uint32 y, uint32 radius) { CellSpawns* sp; uint32 endX = (x + radius) <= _sizeX ? x + radius : (_sizeX - 1); uint32 endY = (y + radius) <= _sizeY ? y + radius : (_sizeY - 1); uint32 startX = x > radius ? x - radius : 0; uint32 startY = y > radius ? y - radius : 0; uint32 posX, posY; MapCell* objCell; for(posX = startX; posX <= endX; posX++) { for(posY = startY; posY <= endY; posY++) { objCell = GetCell(posX, posY); if(!objCell) { if(_CellActive(posX, posY)) { objCell = Create(posX, posY); objCell->Init(posX, posY, this); LOG_DETAIL("Cell [%u,%u] on map %u (instance %u) is now active.", posX, posY, this->_mapId, m_instanceID); objCell->SetActivity(true); _map->CellGoneActive(posX, posY); _terrain->LoadTile((int32)posX / 8, (int32)posY / 8); ARCEMU_ASSERT(!objCell->IsLoaded()); LOG_DETAIL("Loading objects for Cell [%u][%u] on map %u (instance %u)...", posX, posY, this->_mapId, m_instanceID); sp = _map->GetSpawnsList(posX, posY); if(sp) objCell->LoadObjects(sp); } } else { //Cell is now active if(_CellActive(posX, posY) && !objCell->IsActive()) { LOG_DETAIL("Cell [%u,%u] on map %u (instance %u) is now active.", posX, posY, this->_mapId, m_instanceID); _map->CellGoneActive(posX, posY); _terrain->LoadTile((int32)posX / 8, (int32)posY / 8); objCell->SetActivity(true); if(!objCell->IsLoaded()) { LOG_DETAIL("Loading objects for Cell [%u][%u] on map %u (instance %u)...", posX, posY, this->_mapId, m_instanceID); sp = _map->GetSpawnsList(posX, posY); if(sp) objCell->LoadObjects(sp); } } //Cell is no longer active else if(!_CellActive(posX, posY) && objCell->IsActive()) { LOG_DETAIL("Cell [%u,%u] on map %u (instance %u) is now idle.", posX, posY, _mapId, m_instanceID); _map->CellGoneIdle(posX, posY); objCell->SetActivity(false); _terrain->UnloadTile((int32)posX / 8, (int32)posY / 8); } } } } }