| 1 | /* |
|---|
| 2 | * ArcEmu MMORPG Server |
|---|
| 3 | * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/> |
|---|
| 4 | * Copyright (C) 2008-2010 <http://www.ArcEmu.org/> |
|---|
| 5 | * |
|---|
| 6 | * This program is free software: you can redistribute it and/or modify |
|---|
| 7 | * it under the terms of the GNU Affero General Public License as published by |
|---|
| 8 | * the Free Software Foundation, either version 3 of the License, or |
|---|
| 9 | * any later version. |
|---|
| 10 | * |
|---|
| 11 | * This program is distributed in the hope that it will be useful, |
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | * GNU Affero General Public License for more details. |
|---|
| 15 | * |
|---|
| 16 | * You should have received a copy of the GNU Affero General Public License |
|---|
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 18 | * |
|---|
| 19 | */ |
|---|
| 20 | |
|---|
| 21 | // |
|---|
| 22 | // MapMgr.cpp |
|---|
| 23 | // |
|---|
| 24 | |
|---|
| 25 | #include "StdAfx.h" |
|---|
| 26 | #include "CrashHandler.h" |
|---|
| 27 | |
|---|
| 28 | #define MAP_MGR_UPDATE_PERIOD 100 |
|---|
| 29 | #define MAPMGR_INACTIVE_MOVE_TIME 30 |
|---|
| 30 | |
|---|
| 31 | #define Z_SEARCH_RANGE 2 |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | extern bool bServerShutdown; |
|---|
| 35 | |
|---|
| 36 | MapMgr::MapMgr(Map *map, uint32 mapId, uint32 instanceid) : CellHandler<MapCell>(map), _mapId(mapId), eventHolder(instanceid) |
|---|
| 37 | { |
|---|
| 38 | _shutdown = false; |
|---|
| 39 | m_instanceID = instanceid; |
|---|
| 40 | pMapInfo = WorldMapInfoStorage.LookupEntry(mapId); |
|---|
| 41 | m_UpdateDistance = pMapInfo->update_distance * pMapInfo->update_distance; |
|---|
| 42 | iInstanceMode = 0; |
|---|
| 43 | |
|---|
| 44 | // Create script interface |
|---|
| 45 | ScriptInterface = new MapScriptInterface(*this); |
|---|
| 46 | |
|---|
| 47 | // Set up storage arrays |
|---|
| 48 | CreatureStorage.resize( map->CreatureSpawnCount, NULL ); |
|---|
| 49 | GOStorage.resize( map->GameObjectSpawnCount, NULL ); |
|---|
| 50 | |
|---|
| 51 | m_GOHighGuid = m_CreatureHighGuid = 0; |
|---|
| 52 | m_DynamicObjectHighGuid= 0; |
|---|
| 53 | lastUnitUpdate = getMSTime(); |
|---|
| 54 | lastGameobjectUpdate = getMSTime(); |
|---|
| 55 | m_battleground = NULL; |
|---|
| 56 | |
|---|
| 57 | m_holder = &eventHolder; |
|---|
| 58 | m_event_Instanceid = eventHolder.GetInstanceID(); |
|---|
| 59 | forced_expire = false; |
|---|
| 60 | InactiveMoveTime = 0; |
|---|
| 61 | mLoopCounter= 0; |
|---|
| 62 | pInstance = NULL; |
|---|
| 63 | thread_kill_only = false; |
|---|
| 64 | thread_running = false; |
|---|
| 65 | |
|---|
| 66 | m_forcedcells.clear(); |
|---|
| 67 | m_PlayerStorage.clear(); |
|---|
| 68 | m_PetStorage.clear(); |
|---|
| 69 | m_DynamicObjectStorage.clear(); |
|---|
| 70 | |
|---|
| 71 | _combatProgress.clear(); |
|---|
| 72 | _mapWideStaticObjects.clear(); |
|---|
| 73 | //_worldStateSet.clear(); |
|---|
| 74 | _updates.clear(); |
|---|
| 75 | _processQueue.clear(); |
|---|
| 76 | Sessions.clear(); |
|---|
| 77 | |
|---|
| 78 | activeGameObjects.clear(); |
|---|
| 79 | activeCreatures.clear(); |
|---|
| 80 | m_corpses.clear(); |
|---|
| 81 | _sqlids_creatures.clear(); |
|---|
| 82 | _sqlids_gameobjects.clear(); |
|---|
| 83 | _reusable_guids_gameobject.clear(); |
|---|
| 84 | _reusable_guids_creature.clear(); |
|---|
| 85 | |
|---|
| 86 | mInstanceScript = NULL; |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | |
|---|
| 90 | MapMgr::~MapMgr() |
|---|
| 91 | { |
|---|
| 92 | _shutdown = true; |
|---|
| 93 | sEventMgr.RemoveEvents(this); |
|---|
| 94 | if ( ScriptInterface != NULL ) |
|---|
| 95 | { |
|---|
| 96 | delete ScriptInterface; |
|---|
| 97 | ScriptInterface = NULL; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | // Remove objects |
|---|
| 101 | if(_cells) |
|---|
| 102 | { |
|---|
| 103 | for (uint32 i = 0; i < _sizeX; i++) |
|---|
| 104 | { |
|---|
| 105 | if(_cells[i] != 0) |
|---|
| 106 | { |
|---|
| 107 | for (uint32 j = 0; j < _sizeY; j++) |
|---|
| 108 | { |
|---|
| 109 | if(_cells[i][j] != 0) |
|---|
| 110 | { |
|---|
| 111 | _cells[i][j]->_unloadpending=false; |
|---|
| 112 | _cells[i][j]->RemoveObjects(); |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | } |
|---|
| 116 | } |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr) |
|---|
| 120 | { |
|---|
| 121 | if((*itr)->IsInWorld()) |
|---|
| 122 | (*itr)->RemoveFromWorld(false); |
|---|
| 123 | delete (*itr); |
|---|
| 124 | } |
|---|
| 125 | _mapWideStaticObjects.clear(); |
|---|
| 126 | |
|---|
| 127 | GOStorage.clear(); |
|---|
| 128 | CreatureStorage.clear(); |
|---|
| 129 | |
|---|
| 130 | Corpse * pCorpse; |
|---|
| 131 | for(set<Corpse*>::iterator itr = m_corpses.begin(); itr != m_corpses.end();) |
|---|
| 132 | { |
|---|
| 133 | pCorpse = *itr; |
|---|
| 134 | ++itr; |
|---|
| 135 | |
|---|
| 136 | if(pCorpse->IsInWorld()) |
|---|
| 137 | pCorpse->RemoveFromWorld(false); |
|---|
| 138 | |
|---|
| 139 | delete pCorpse; |
|---|
| 140 | } |
|---|
| 141 | m_corpses.clear(); |
|---|
| 142 | |
|---|
| 143 | //clear worldstates |
|---|
| 144 | for (WorldStateHandlerMap::iterator itr=m_worldStates.begin(); itr!= m_worldStates.end(); ++itr) |
|---|
| 145 | delete itr->second; |
|---|
| 146 | m_worldStates.clear(); |
|---|
| 147 | |
|---|
| 148 | if ( mInstanceScript != NULL ) |
|---|
| 149 | mInstanceScript->Destroy(); |
|---|
| 150 | |
|---|
| 151 | // Empty remaining containers |
|---|
| 152 | m_PlayerStorage.clear(); |
|---|
| 153 | m_PetStorage.clear(); |
|---|
| 154 | m_DynamicObjectStorage.clear(); |
|---|
| 155 | |
|---|
| 156 | _combatProgress.clear(); |
|---|
| 157 | _updates.clear(); |
|---|
| 158 | _processQueue.clear(); |
|---|
| 159 | Sessions.clear(); |
|---|
| 160 | |
|---|
| 161 | activeCreatures.clear(); |
|---|
| 162 | activeGameObjects.clear(); |
|---|
| 163 | _sqlids_creatures.clear(); |
|---|
| 164 | _sqlids_gameobjects.clear(); |
|---|
| 165 | _reusable_guids_creature.clear(); |
|---|
| 166 | _reusable_guids_gameobject.clear(); |
|---|
| 167 | |
|---|
| 168 | if( m_battleground ) { |
|---|
| 169 | m_battleground = NULL; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | Log.Notice("MapMgr", "Instance %u shut down. (%s)" , m_instanceID, GetBaseMap()->GetName()); |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | void MapMgr::SetWorldState(uint32 zoneid, uint32 index, uint32 value) |
|---|
| 176 | { |
|---|
| 177 | //do we have a worldstate already? |
|---|
| 178 | WorldStateHandlerMap::iterator itr=m_worldStates.find(zoneid); |
|---|
| 179 | |
|---|
| 180 | if (itr != m_worldStates.end()) |
|---|
| 181 | itr->second->SetState(index, value); |
|---|
| 182 | else |
|---|
| 183 | { |
|---|
| 184 | //we got here, no state set |
|---|
| 185 | WorldStateHandler* ws=new WorldStateHandler; |
|---|
| 186 | ws->SetState(index, value); |
|---|
| 187 | m_worldStates.insert(std::make_pair<uint32, WorldStateHandler*>(zoneid, ws)); |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8); |
|---|
| 191 | data << index << value; |
|---|
| 192 | |
|---|
| 193 | //update all players in this zone |
|---|
| 194 | for (PlayerStorageMap::iterator itr=m_PlayerStorage.begin(); itr!=m_PlayerStorage.end(); ++itr) |
|---|
| 195 | if (itr->second->GetSession() != NULL && itr->second->GetZoneId() == zoneid) |
|---|
| 196 | itr->second->GetSession()->SendPacket(&data); |
|---|
| 197 | } |
|---|
| 198 | |
|---|
| 199 | void MapMgr::SendInitialStates(Player * plr) |
|---|
| 200 | { |
|---|
| 201 | std::map<uint32, WorldStateHandler*>::iterator itr=m_worldStates.find(plr->GetZoneId()); |
|---|
| 202 | |
|---|
| 203 | if ( itr == m_worldStates.end() ) |
|---|
| 204 | return; |
|---|
| 205 | |
|---|
| 206 | WorldPacket data(SMSG_INIT_WORLD_STATES, 14 + (itr->second->m_states.size() * 8)); |
|---|
| 207 | |
|---|
| 208 | data << uint32( _mapId ); |
|---|
| 209 | data << uint32( 0 ); |
|---|
| 210 | data << uint32( 0 ); |
|---|
| 211 | data << uint16( itr->second->m_states.size() ); |
|---|
| 212 | |
|---|
| 213 | for ( WorldStateMap::iterator itr2 = itr->second->m_states.begin(); itr2 != itr->second->m_states.end(); ++itr2 ){ |
|---|
| 214 | data << uint32( itr2->first ); |
|---|
| 215 | data << uint32( itr2->second ); |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | plr->SendPacket(&data); |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | uint32 MapMgr::GetTeamPlayersCount(uint32 teamId) |
|---|
| 222 | { |
|---|
| 223 | uint32 result = 0; |
|---|
| 224 | PlayerStorageMap::iterator itr = m_PlayerStorage.begin(); |
|---|
| 225 | for(; itr != m_PlayerStorage.end(); itr++) |
|---|
| 226 | { |
|---|
| 227 | Player * pPlayer = (itr->second); |
|---|
| 228 | if(pPlayer->GetTeam() == teamId) |
|---|
| 229 | result++; |
|---|
| 230 | } |
|---|
| 231 | return result; |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | |
|---|
| 235 | void MapMgr::PushObject(Object *obj) |
|---|
| 236 | { |
|---|
| 237 | ///////////// |
|---|
| 238 | // Assertions |
|---|
| 239 | ///////////// |
|---|
| 240 | Arcemu::Util::ARCEMU_ASSERT( obj != NULL ); |
|---|
| 241 | |
|---|
| 242 | // That object types are not map objects. TODO: add AI groups here? |
|---|
| 243 | if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER) |
|---|
| 244 | { |
|---|
| 245 | // mark object as updatable and exit |
|---|
| 246 | return; |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | if(obj->GetTypeId() == TYPEID_CORPSE) |
|---|
| 250 | { |
|---|
| 251 | m_corpses.insert(((Corpse*)obj)); |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | obj->ClearInRangeSet(); |
|---|
| 255 | |
|---|
| 256 | Arcemu::Util::ARCEMU_ASSERT( obj->GetMapId() == _mapId ); |
|---|
| 257 | if(!(obj->GetPositionX() < _maxX && obj->GetPositionX() > _minX) || |
|---|
| 258 | !(obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY)) |
|---|
| 259 | { |
|---|
| 260 | if(obj->IsPlayer()) |
|---|
| 261 | { |
|---|
| 262 | Player * plr = static_cast< Player* >( obj ); |
|---|
| 263 | if(plr->GetBindMapId() != GetMapId()) |
|---|
| 264 | { |
|---|
| 265 | plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); |
|---|
| 266 | plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); |
|---|
| 267 | return; |
|---|
| 268 | } |
|---|
| 269 | else |
|---|
| 270 | { |
|---|
| 271 | obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); |
|---|
| 272 | plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); |
|---|
| 273 | plr->SendTeleportAckMsg( plr->GetPosition() ); |
|---|
| 274 | } |
|---|
| 275 | } |
|---|
| 276 | else |
|---|
| 277 | { |
|---|
| 278 | obj->GetPositionV()->ChangeCoords(0,0,0,0); |
|---|
| 279 | } |
|---|
| 280 | } |
|---|
| 281 | |
|---|
| 282 | Arcemu::Util::ARCEMU_ASSERT( obj->GetPositionY() < _maxY && obj->GetPositionY() > _minY ); |
|---|
| 283 | Arcemu::Util::ARCEMU_ASSERT( _cells != NULL ); |
|---|
| 284 | |
|---|
| 285 | /////////////////////// |
|---|
| 286 | // Get cell coordinates |
|---|
| 287 | /////////////////////// |
|---|
| 288 | |
|---|
| 289 | uint32 x = GetPosX(obj->GetPositionX()); |
|---|
| 290 | uint32 y = GetPosY(obj->GetPositionY()); |
|---|
| 291 | |
|---|
| 292 | if(x >= _sizeX || y >= _sizeY) |
|---|
| 293 | { |
|---|
| 294 | if(obj->IsPlayer()) |
|---|
| 295 | { |
|---|
| 296 | Player * plr = static_cast< Player* >( obj ); |
|---|
| 297 | if(plr->GetBindMapId() != GetMapId()) |
|---|
| 298 | { |
|---|
| 299 | plr->SafeTeleport(plr->GetBindMapId(),0,plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); |
|---|
| 300 | plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); |
|---|
| 301 | return; |
|---|
| 302 | } |
|---|
| 303 | else |
|---|
| 304 | { |
|---|
| 305 | obj->GetPositionV()->ChangeCoords(plr->GetBindPositionX(),plr->GetBindPositionY(),plr->GetBindPositionZ(),0); |
|---|
| 306 | plr->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); |
|---|
| 307 | plr->SendTeleportAckMsg( plr->GetPosition() ); |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | else |
|---|
| 311 | { |
|---|
| 312 | obj->GetPositionV()->ChangeCoords(0,0,0,0); |
|---|
| 313 | } |
|---|
| 314 | |
|---|
| 315 | x = GetPosX(obj->GetPositionX()); |
|---|
| 316 | y = GetPosY(obj->GetPositionY()); |
|---|
| 317 | } |
|---|
| 318 | |
|---|
| 319 | MapCell *objCell = GetCell(x,y); |
|---|
| 320 | if ( objCell == NULL ) |
|---|
| 321 | { |
|---|
| 322 | objCell = Create(x,y); |
|---|
| 323 | objCell->Init(x, y, _mapId, this); |
|---|
| 324 | } |
|---|
| 325 | Arcemu::Util::ARCEMU_ASSERT( objCell != NULL ); |
|---|
| 326 | |
|---|
| 327 | uint32 endX = (x <= _sizeX) ? x + 1 : (_sizeX-1); |
|---|
| 328 | uint32 endY = (y <= _sizeY) ? y + 1 : (_sizeY-1); |
|---|
| 329 | uint32 startX = x > 0 ? x - 1 : 0; |
|---|
| 330 | uint32 startY = y > 0 ? y - 1 : 0; |
|---|
| 331 | uint32 posX, posY; |
|---|
| 332 | MapCell *cell; |
|---|
| 333 | //MapCell::ObjectSet::iterator iter; |
|---|
| 334 | |
|---|
| 335 | ByteBuffer * buf = 0; |
|---|
| 336 | uint32 count; |
|---|
| 337 | Player *plObj; |
|---|
| 338 | |
|---|
| 339 | if( obj->IsPlayer() ) |
|---|
| 340 | plObj = static_cast< Player* >( obj ); |
|---|
| 341 | else |
|---|
| 342 | plObj = NULL; |
|---|
| 343 | |
|---|
| 344 | if( plObj != NULL ) |
|---|
| 345 | { |
|---|
| 346 | sLog.outDetail("Creating player "I64FMT" for himself.", obj->GetGUID()); |
|---|
| 347 | ByteBuffer pbuf(10000); |
|---|
| 348 | count = plObj->BuildCreateUpdateBlockForPlayer(&pbuf, plObj); |
|---|
| 349 | plObj->PushCreationData(&pbuf, count); |
|---|
| 350 | } |
|---|
| 351 | |
|---|
| 352 | ////////////////////// |
|---|
| 353 | // Build in-range data |
|---|
| 354 | ////////////////////// |
|---|
| 355 | |
|---|
| 356 | for (posX = startX; posX <= endX; posX++ ) |
|---|
| 357 | { |
|---|
| 358 | for (posY = startY; posY <= endY; posY++ ) |
|---|
| 359 | { |
|---|
| 360 | cell = GetCell(posX, posY); |
|---|
| 361 | if (cell) |
|---|
| 362 | { |
|---|
| 363 | UpdateInRangeSet(obj, plObj, cell, &buf); |
|---|
| 364 | } |
|---|
| 365 | } |
|---|
| 366 | } |
|---|
| 367 | |
|---|
| 368 | //Add to the cell's object list |
|---|
| 369 | objCell->AddObject(obj); |
|---|
| 370 | |
|---|
| 371 | obj->SetMapCell(objCell); |
|---|
| 372 | //Add to the mapmanager's object list |
|---|
| 373 | if( plObj != NULL ) |
|---|
| 374 | { |
|---|
| 375 | m_PlayerStorage[plObj->GetLowGUID()] = plObj; |
|---|
| 376 | UpdateCellActivity(x, y, 2); |
|---|
| 377 | } |
|---|
| 378 | else |
|---|
| 379 | { |
|---|
| 380 | switch(obj->GetTypeFromGUID()) |
|---|
| 381 | { |
|---|
| 382 | case HIGHGUID_TYPE_PET: |
|---|
| 383 | m_PetStorage[obj->GetUIdFromGUID()] = static_cast< Pet* >( obj ); |
|---|
| 384 | break; |
|---|
| 385 | |
|---|
| 386 | case HIGHGUID_TYPE_UNIT: |
|---|
| 387 | { |
|---|
| 388 | Arcemu::Util::ARCEMU_ASSERT( obj->GetUIdFromGUID() <= m_CreatureHighGuid ); |
|---|
| 389 | CreatureStorage[ obj->GetUIdFromGUID() ] = static_cast< Creature* >( obj ); |
|---|
| 390 | if(((Creature*)obj)->m_spawn != NULL) |
|---|
| 391 | { |
|---|
| 392 | _sqlids_creatures.insert(make_pair( ((Creature*)obj)->m_spawn->id, ((Creature*)obj) ) ); |
|---|
| 393 | } |
|---|
| 394 | }break; |
|---|
| 395 | |
|---|
| 396 | case HIGHGUID_TYPE_GAMEOBJECT: |
|---|
| 397 | { |
|---|
| 398 | GOStorage[ obj->GetUIdFromGUID() ] = static_cast< GameObject* >( obj ); |
|---|
| 399 | if(((GameObject*)obj)->m_spawn != NULL) |
|---|
| 400 | { |
|---|
| 401 | _sqlids_gameobjects.insert(make_pair( ((GameObject*)obj)->m_spawn->id, ((GameObject*)obj) ) ); |
|---|
| 402 | } |
|---|
| 403 | }break; |
|---|
| 404 | |
|---|
| 405 | case HIGHGUID_TYPE_DYNAMICOBJECT: |
|---|
| 406 | m_DynamicObjectStorage[obj->GetLowGUID()] = (DynamicObject*)obj; |
|---|
| 407 | break; |
|---|
| 408 | } |
|---|
| 409 | } |
|---|
| 410 | |
|---|
| 411 | // Handle activation of that object. |
|---|
| 412 | if(objCell->IsActive() && obj->CanActivate()) |
|---|
| 413 | obj->Activate(this); |
|---|
| 414 | |
|---|
| 415 | // Add the session to our set if it is a player. |
|---|
| 416 | if( plObj != NULL ) |
|---|
| 417 | { |
|---|
| 418 | Sessions.insert(plObj->GetSession()); |
|---|
| 419 | |
|---|
| 420 | // Change the instance ID, this will cause it to be removed from the world thread (return value 1) |
|---|
| 421 | plObj->GetSession()->SetInstance(GetInstanceID()); |
|---|
| 422 | |
|---|
| 423 | /* Add the map wide objects */ |
|---|
| 424 | if(_mapWideStaticObjects.size()) |
|---|
| 425 | { |
|---|
| 426 | uint32 globalcount= 0; |
|---|
| 427 | if(!buf) |
|---|
| 428 | buf = new ByteBuffer(300); |
|---|
| 429 | |
|---|
| 430 | for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr) |
|---|
| 431 | { |
|---|
| 432 | count = (*itr)->BuildCreateUpdateBlockForPlayer(buf, plObj); |
|---|
| 433 | globalcount += count; |
|---|
| 434 | } |
|---|
| 435 | //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! |
|---|
| 436 | // If you try to add them one by one, then as the buffer already contains data, they'll end up repeating some object. |
|---|
| 437 | // Like 6 object updates for Deeprun Tram, but the built package will contain these entries: 2AFD0, 2AFD0, 2AFD1, 2AFD0, 2AFD1, 2AFD2 |
|---|
| 438 | if( globalcount>0 ) plObj->PushCreationData(buf, globalcount); |
|---|
| 439 | } |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | if(buf) |
|---|
| 443 | delete buf; |
|---|
| 444 | |
|---|
| 445 | if( plObj != NULL && InactiveMoveTime && !forced_expire) |
|---|
| 446 | InactiveMoveTime = 0; |
|---|
| 447 | } |
|---|
| 448 | |
|---|
| 449 | |
|---|
| 450 | void MapMgr::PushStaticObject(Object *obj) |
|---|
| 451 | { |
|---|
| 452 | _mapWideStaticObjects.insert(obj); |
|---|
| 453 | |
|---|
| 454 | switch(obj->GetTypeFromGUID()) |
|---|
| 455 | { |
|---|
| 456 | case HIGHGUID_TYPE_UNIT: |
|---|
| 457 | CreatureStorage[ obj->GetUIdFromGUID() ] = static_cast< Creature* >( obj ); |
|---|
| 458 | break; |
|---|
| 459 | |
|---|
| 460 | case HIGHGUID_TYPE_GAMEOBJECT: |
|---|
| 461 | GOStorage[ obj->GetUIdFromGUID() ] = static_cast< GameObject* >( obj ); |
|---|
| 462 | break; |
|---|
| 463 | |
|---|
| 464 | default: |
|---|
| 465 | // maybe add a warning, shouldn't be needed |
|---|
| 466 | break; |
|---|
| 467 | } |
|---|
| 468 | } |
|---|
| 469 | |
|---|
| 470 | #define OPTIONAL_IN_RANGE_SETS |
|---|
| 471 | |
|---|
| 472 | void MapMgr::RemoveObject(Object *obj, bool free_guid) |
|---|
| 473 | { |
|---|
| 474 | ///////////// |
|---|
| 475 | // Assertions |
|---|
| 476 | ///////////// |
|---|
| 477 | |
|---|
| 478 | Arcemu::Util::ARCEMU_ASSERT( obj != NULL ); |
|---|
| 479 | Arcemu::Util::ARCEMU_ASSERT( obj->GetMapId() == _mapId); |
|---|
| 480 | //Arcemu::Util::ARCEMU_ASSERT( obj->GetPositionX() > _minX && obj->GetPositionX() < _maxX); |
|---|
| 481 | //Arcemu::Util::ARCEMU_ASSERT( obj->GetPositionY() > _minY && obj->GetPositionY() < _maxY); |
|---|
| 482 | Arcemu::Util::ARCEMU_ASSERT( _cells != NULL ); |
|---|
| 483 | |
|---|
| 484 | if (obj->IsActive()) |
|---|
| 485 | obj->Deactivate(this); |
|---|
| 486 | |
|---|
| 487 | //there is a very small chance that on double player ports on same update player is added to multiple insertpools but not removed |
|---|
| 488 | //one clear example was the double port proc when exploiting double resurrect |
|---|
| 489 | m_objectinsertlock.Acquire(); |
|---|
| 490 | m_objectinsertpool.erase( obj ); |
|---|
| 491 | m_objectinsertlock.Release(); |
|---|
| 492 | |
|---|
| 493 | _updates.erase( obj ); |
|---|
| 494 | obj->ClearUpdateMask(); |
|---|
| 495 | Player* plObj = (obj->GetTypeId() == TYPEID_PLAYER) ? static_cast< Player* >( obj ) : 0; |
|---|
| 496 | |
|---|
| 497 | /////////////////////////////////////// |
|---|
| 498 | // Remove object from all needed places |
|---|
| 499 | /////////////////////////////////////// |
|---|
| 500 | |
|---|
| 501 | switch(obj->GetTypeFromGUID()) |
|---|
| 502 | { |
|---|
| 503 | case HIGHGUID_TYPE_UNIT: |
|---|
| 504 | Arcemu::Util::ARCEMU_ASSERT( obj->GetUIdFromGUID() <= m_CreatureHighGuid); |
|---|
| 505 | CreatureStorage[ obj->GetUIdFromGUID() ] = NULL; |
|---|
| 506 | if(((Creature*)obj)->m_spawn != NULL) |
|---|
| 507 | { |
|---|
| 508 | _sqlids_creatures.erase(((Creature*)obj)->m_spawn->id); |
|---|
| 509 | } |
|---|
| 510 | |
|---|
| 511 | if(free_guid) |
|---|
| 512 | _reusable_guids_creature.push_back(obj->GetUIdFromGUID()); |
|---|
| 513 | |
|---|
| 514 | break; |
|---|
| 515 | |
|---|
| 516 | case HIGHGUID_TYPE_PET: |
|---|
| 517 | m_PetStorage.erase(obj->GetUIdFromGUID()); |
|---|
| 518 | break; |
|---|
| 519 | |
|---|
| 520 | case HIGHGUID_TYPE_DYNAMICOBJECT: |
|---|
| 521 | m_DynamicObjectStorage.erase(obj->GetLowGUID()); |
|---|
| 522 | break; |
|---|
| 523 | |
|---|
| 524 | case HIGHGUID_TYPE_GAMEOBJECT: |
|---|
| 525 | Arcemu::Util::ARCEMU_ASSERT( obj->GetUIdFromGUID() <= m_GOHighGuid ); |
|---|
| 526 | GOStorage[ obj->GetUIdFromGUID() ] = NULL; |
|---|
| 527 | if(((GameObject*)obj)->m_spawn != NULL) |
|---|
| 528 | { |
|---|
| 529 | _sqlids_gameobjects.erase(((GameObject*)obj)->m_spawn->id); |
|---|
| 530 | } |
|---|
| 531 | |
|---|
| 532 | if(free_guid) |
|---|
| 533 | _reusable_guids_gameobject.push_back(obj->GetUIdFromGUID()); |
|---|
| 534 | |
|---|
| 535 | break; |
|---|
| 536 | } |
|---|
| 537 | |
|---|
| 538 | // That object types are not map objects. TODO: add AI groups here? |
|---|
| 539 | if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetTypeId()==10) |
|---|
| 540 | { |
|---|
| 541 | return; |
|---|
| 542 | } |
|---|
| 543 | |
|---|
| 544 | if(obj->GetTypeId() == TYPEID_CORPSE) |
|---|
| 545 | { |
|---|
| 546 | m_corpses.erase(((Corpse*)obj)); |
|---|
| 547 | } |
|---|
| 548 | |
|---|
| 549 | if(!obj->GetMapCell()) |
|---|
| 550 | { |
|---|
| 551 | /* set the map cell correctly */ |
|---|
| 552 | if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minY || |
|---|
| 553 | obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) |
|---|
| 554 | { |
|---|
| 555 | // do nothing |
|---|
| 556 | } |
|---|
| 557 | else |
|---|
| 558 | { |
|---|
| 559 | obj->SetMapCell(this->GetCellByCoords(obj->GetPositionX(), obj->GetPositionY())); |
|---|
| 560 | } |
|---|
| 561 | } |
|---|
| 562 | |
|---|
| 563 | if(obj->GetMapCell()) |
|---|
| 564 | { |
|---|
| 565 | Arcemu::Util::ARCEMU_ASSERT( obj->GetMapCell() != NULL ); |
|---|
| 566 | |
|---|
| 567 | // Remove object from cell |
|---|
| 568 | obj->GetMapCell()->RemoveObject(obj); |
|---|
| 569 | |
|---|
| 570 | // Unset object's cell |
|---|
| 571 | obj->SetMapCell(NULL); |
|---|
| 572 | } |
|---|
| 573 | |
|---|
| 574 | // Clear any updates pending |
|---|
| 575 | if(obj->GetTypeId() == TYPEID_PLAYER) |
|---|
| 576 | { |
|---|
| 577 | _processQueue.erase( static_cast< Player* >( obj ) ); |
|---|
| 578 | static_cast< Player* >( obj )->ClearAllPendingUpdates(); |
|---|
| 579 | } |
|---|
| 580 | |
|---|
| 581 | obj->RemoveSelfFromInrangeSets(); |
|---|
| 582 | |
|---|
| 583 | // Clear object's in-range set |
|---|
| 584 | obj->ClearInRangeSet(); |
|---|
| 585 | |
|---|
| 586 | // If it's a player - update his nearby cells |
|---|
| 587 | if(!_shutdown && obj->GetTypeId() == TYPEID_PLAYER) |
|---|
| 588 | { |
|---|
| 589 | // get x/y |
|---|
| 590 | if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minY || |
|---|
| 591 | obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) |
|---|
| 592 | { |
|---|
| 593 | // do nothing |
|---|
| 594 | } |
|---|
| 595 | else |
|---|
| 596 | { |
|---|
| 597 | uint32 x = GetPosX(obj->GetPositionX()); |
|---|
| 598 | uint32 y = GetPosY(obj->GetPositionY()); |
|---|
| 599 | UpdateCellActivity(x, y, 2); |
|---|
| 600 | } |
|---|
| 601 | m_PlayerStorage.erase( static_cast< Player* >( obj )->GetLowGUID() ); |
|---|
| 602 | } |
|---|
| 603 | |
|---|
| 604 | // Remove the session from our set if it is a player. |
|---|
| 605 | if(plObj) |
|---|
| 606 | { |
|---|
| 607 | for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr) |
|---|
| 608 | { |
|---|
| 609 | plObj->PushOutOfRange((*itr)->GetNewGUID()); |
|---|
| 610 | } |
|---|
| 611 | |
|---|
| 612 | // Setting an instance ID here will trigger the session to be removed |
|---|
| 613 | // by MapMgr::run(). :) |
|---|
| 614 | plObj->GetSession()->SetInstance(0); |
|---|
| 615 | |
|---|
| 616 | // Add it to the global session set. |
|---|
| 617 | // Don't "re-add" to session if it is being deleted. |
|---|
| 618 | if(!plObj->GetSession()->bDeleted) |
|---|
| 619 | sWorld.AddGlobalSession(plObj->GetSession()); |
|---|
| 620 | } |
|---|
| 621 | |
|---|
| 622 | if(!HasPlayers()) |
|---|
| 623 | { |
|---|
| 624 | if(this->pInstance != NULL && this->pInstance->m_persistent) |
|---|
| 625 | this->pInstance->m_creatorGroup = 0; |
|---|
| 626 | if(!InactiveMoveTime && !forced_expire && GetMapInfo()->type != INSTANCE_NULL) |
|---|
| 627 | { |
|---|
| 628 | InactiveMoveTime = UNIXTIME + (MAPMGR_INACTIVE_MOVE_TIME * 60); |
|---|
| 629 | Log.Debug("MapMgr", "Instance %u is now idle. (%s)", m_instanceID, GetBaseMap()->GetName()); |
|---|
| 630 | } |
|---|
| 631 | } |
|---|
| 632 | } |
|---|
| 633 | |
|---|
| 634 | void MapMgr::ChangeObjectLocation( Object *obj ) |
|---|
| 635 | { |
|---|
| 636 | /* |
|---|
| 637 | if ( !obj ) return; // crashfix |
|---|
| 638 | */ |
|---|
| 639 | |
|---|
| 640 | Arcemu::Util::ARCEMU_ASSERT( obj != NULL ); |
|---|
| 641 | |
|---|
| 642 | // Items and containers are of no interest for us |
|---|
| 643 | if( obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetMapMgr() != this ) |
|---|
| 644 | { |
|---|
| 645 | return; |
|---|
| 646 | } |
|---|
| 647 | |
|---|
| 648 | Player *plObj = NULL; |
|---|
| 649 | ByteBuffer * buf = 0; |
|---|
| 650 | |
|---|
| 651 | if( obj->IsPlayer() ) |
|---|
| 652 | { |
|---|
| 653 | plObj = static_cast< Player* >( obj ); |
|---|
| 654 | } |
|---|
| 655 | |
|---|
| 656 | Object* curObj; |
|---|
| 657 | float fRange = 0.0f; |
|---|
| 658 | |
|---|
| 659 | /////////////////////////////////////// |
|---|
| 660 | // Update in-range data for old objects |
|---|
| 661 | /////////////////////////////////////// |
|---|
| 662 | |
|---|
| 663 | if( obj->HasInRangeObjects() ) |
|---|
| 664 | { |
|---|
| 665 | for( Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd(); ) |
|---|
| 666 | { |
|---|
| 667 | curObj = *iter; |
|---|
| 668 | ++iter; |
|---|
| 669 | |
|---|
| 670 | if( curObj->IsPlayer() && plObj != NULL && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) |
|---|
| 671 | fRange = 0.0f; // unlimited distance for people on same boat |
|---|
| 672 | else if( curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER ) |
|---|
| 673 | fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) |
|---|
| 674 | //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack |
|---|
| 675 | else if( obj->GetTypeId() == TYPEID_GAMEOBJECT && (static_cast<GameObject*>(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId() ) |
|---|
| 676 | fRange = 0.0f; |
|---|
| 677 | //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... |
|---|
| 678 | else if( plObj && curObj->GetTypeId() == TYPEID_GAMEOBJECT && (static_cast<GameObject*>(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId() ) |
|---|
| 679 | fRange = 0.0f; |
|---|
| 680 | else if( curObj->IsPlayer() && static_cast< Player* >( curObj )->GetFarsightTarget() == obj->GetGUID()) |
|---|
| 681 | fRange = 0.0f;//Mind Vision, Eye of Kilrogg |
|---|
| 682 | else |
|---|
| 683 | fRange = m_UpdateDistance; // normal distance |
|---|
| 684 | |
|---|
| 685 | if( fRange > 0.0f && ( curObj->GetDistance2dSq(obj) > fRange ) ) |
|---|
| 686 | { |
|---|
| 687 | if( plObj != NULL ) |
|---|
| 688 | plObj->RemoveIfVisible( curObj ); |
|---|
| 689 | |
|---|
| 690 | if( curObj->IsPlayer() ) |
|---|
| 691 | static_cast< Player* >( curObj )->RemoveIfVisible( obj ); |
|---|
| 692 | |
|---|
| 693 | curObj->RemoveInRangeObject( obj ); |
|---|
| 694 | |
|---|
| 695 | if( obj->GetMapMgr() != this ) |
|---|
| 696 | { |
|---|
| 697 | /* Something removed us. */ |
|---|
| 698 | return; |
|---|
| 699 | } |
|---|
| 700 | obj->RemoveInRangeObject( curObj ); |
|---|
| 701 | } |
|---|
| 702 | } |
|---|
| 703 | } |
|---|
| 704 | |
|---|
| 705 | /////////////////////////// |
|---|
| 706 | // Get new cell coordinates |
|---|
| 707 | /////////////////////////// |
|---|
| 708 | if(obj->GetMapMgr() != this) |
|---|
| 709 | { |
|---|
| 710 | /* Something removed us. */ |
|---|
| 711 | return; |
|---|
| 712 | } |
|---|
| 713 | |
|---|
| 714 | if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX || |
|---|
| 715 | obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY) |
|---|
| 716 | { |
|---|
| 717 | if( plObj != NULL ) |
|---|
| 718 | { |
|---|
| 719 | if( plObj->GetBindMapId() != GetMapId()) |
|---|
| 720 | { |
|---|
| 721 | plObj->SafeTeleport( plObj->GetBindMapId(), 0, plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0 ); |
|---|
| 722 | plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); |
|---|
| 723 | return; |
|---|
| 724 | } |
|---|
| 725 | else |
|---|
| 726 | { |
|---|
| 727 | obj->GetPositionV()->ChangeCoords( plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0 ); |
|---|
| 728 | plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries."); |
|---|
| 729 | plObj->SendTeleportAckMsg( plObj->GetPosition()); |
|---|
| 730 | } |
|---|
| 731 | } |
|---|
| 732 | else |
|---|
| 733 | { |
|---|
| 734 | obj->GetPositionV()->ChangeCoords(0,0,0,0); |
|---|
| 735 | } |
|---|
| 736 | } |
|---|
| 737 | |
|---|
| 738 | uint32 cellX = GetPosX(obj->GetPositionX()); |
|---|
| 739 | uint32 cellY = GetPosY(obj->GetPositionY()); |
|---|
| 740 | |
|---|
| 741 | if(cellX >= _sizeX || cellY >= _sizeY) |
|---|
| 742 | { |
|---|
| 743 | return; |
|---|
| 744 | } |
|---|
| 745 | |
|---|
| 746 | MapCell *objCell = GetCell(cellX, cellY); |
|---|
| 747 | MapCell * pOldCell = obj->GetMapCell(); |
|---|
| 748 | if ( objCell == NULL ) |
|---|
| 749 | { |
|---|
| 750 | objCell = Create(cellX,cellY); |
|---|
| 751 | objCell->Init(cellX, cellY, _mapId, this); |
|---|
| 752 | } |
|---|
| 753 | |
|---|
| 754 | Arcemu::Util::ARCEMU_ASSERT( objCell != NULL ); |
|---|
| 755 | |
|---|
| 756 | // If object moved cell |
|---|
| 757 | if (objCell != obj->GetMapCell()) |
|---|
| 758 | { |
|---|
| 759 | // THIS IS A HACK! |
|---|
| 760 | // Current code, if a creature on a long waypoint path moves from an active |
|---|
| 761 | // cell into an inactive one, it will disable itself and will never return. |
|---|
| 762 | // This is to prevent cpu leaks. I will think of a better solution very soon :P |
|---|
| 763 | |
|---|
| 764 | if(!objCell->IsActive() && !plObj && obj->IsActive()) |
|---|
| 765 | obj->Deactivate(this); |
|---|
| 766 | |
|---|
| 767 | if(obj->GetMapCell()) |
|---|
| 768 | obj->GetMapCell()->RemoveObject(obj); |
|---|
| 769 | |
|---|
| 770 | objCell->AddObject(obj); |
|---|
| 771 | obj->SetMapCell(objCell); |
|---|
| 772 | |
|---|
| 773 | // if player we need to update cell activity |
|---|
| 774 | // radius = 2 is used in order to update both |
|---|
| 775 | // old and new cells |
|---|
| 776 | if(obj->GetTypeId() == TYPEID_PLAYER) |
|---|
| 777 | { |
|---|
| 778 | // have to unlock/lock here to avoid a deadlock situation. |
|---|
| 779 | UpdateCellActivity(cellX, cellY, 2); |
|---|
| 780 | if( pOldCell != NULL ) |
|---|
| 781 | { |
|---|
| 782 | // only do the second check if there's -/+ 2 difference |
|---|
| 783 | if( abs( (int)cellX - (int)pOldCell->_x ) > 2 || |
|---|
| 784 | abs( (int)cellY - (int)pOldCell->_y ) > 2 ) |
|---|
| 785 | { |
|---|
| 786 | UpdateCellActivity( pOldCell->_x, pOldCell->_y, 2 ); |
|---|
| 787 | } |
|---|
| 788 | } |
|---|
| 789 | } |
|---|
| 790 | } |
|---|
| 791 | |
|---|
| 792 | |
|---|
| 793 | ////////////////////////////////////// |
|---|
| 794 | // Update in-range set for new objects |
|---|
| 795 | ////////////////////////////////////// |
|---|
| 796 | |
|---|
| 797 | uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX-1); |
|---|
| 798 | uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY-1); |
|---|
| 799 | uint32 startX = cellX > 0 ? cellX - 1 : 0; |
|---|
| 800 | uint32 startY = cellY > 0 ? cellY - 1 : 0; |
|---|
| 801 | uint32 posX, posY; |
|---|
| 802 | MapCell *cell; |
|---|
| 803 | |
|---|
| 804 | //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 |
|---|
| 805 | if( obj->GetTypeId() == TYPEID_GAMEOBJECT && (static_cast<GameObject*>(obj)->GetOverrides() & GAMEOBJECT_ONMOVEWIDE) ) { |
|---|
| 806 | endX = cellX + 5 <= _sizeX ? cellX + 6 : ( _sizeX - 1 ); |
|---|
| 807 | endY = cellY + 5 <= _sizeY ? cellY + 6 : ( _sizeY - 1 ); |
|---|
| 808 | startX = cellX - 5 > 0 ? cellX - 6 : 0; |
|---|
| 809 | startY = cellY - 5 > 0 ? cellY - 6 : 0; |
|---|
| 810 | } |
|---|
| 811 | |
|---|
| 812 | for (posX = startX; posX <= endX; ++posX ) |
|---|
| 813 | { |
|---|
| 814 | for (posY = startY; posY <= endY; ++posY ) |
|---|
| 815 | { |
|---|
| 816 | cell = GetCell(posX, posY); |
|---|
| 817 | if (cell) |
|---|
| 818 | UpdateInRangeSet(obj, plObj, cell, &buf); |
|---|
| 819 | } |
|---|
| 820 | } |
|---|
| 821 | |
|---|
| 822 | if(buf) |
|---|
| 823 | delete buf; |
|---|
| 824 | } |
|---|
| 825 | |
|---|
| 826 | void MapMgr::UpdateInRangeSet( Object *obj, Player *plObj, MapCell* cell, ByteBuffer ** buf ) |
|---|
| 827 | { |
|---|
| 828 | #define CHECK_BUF if(!*buf) *buf = new ByteBuffer(2500) |
|---|
| 829 | |
|---|
| 830 | if( cell == NULL ) |
|---|
| 831 | return; |
|---|
| 832 | |
|---|
| 833 | Object* curObj; |
|---|
| 834 | Player* plObj2; |
|---|
| 835 | int count; |
|---|
| 836 | ObjectSet::iterator itr; |
|---|
| 837 | float fRange; |
|---|
| 838 | bool cansee, isvisible; |
|---|
| 839 | |
|---|
| 840 | ObjectSet::iterator iter = cell->Begin(); |
|---|
| 841 | while( iter != cell->End() ) |
|---|
| 842 | { |
|---|
| 843 | curObj = *iter; |
|---|
| 844 | ++iter; |
|---|
| 845 | |
|---|
| 846 | if( curObj == NULL ) |
|---|
| 847 | continue; |
|---|
| 848 | |
|---|
| 849 | if( curObj->IsPlayer() && obj->IsPlayer() && plObj != NULL && plObj->m_TransporterGUID && plObj->m_TransporterGUID == static_cast< Player* >( curObj )->m_TransporterGUID ) |
|---|
| 850 | fRange = 0.0f; // unlimited distance for people on same boat |
|---|
| 851 | else if( curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER ) |
|---|
| 852 | fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.) |
|---|
| 853 | |
|---|
| 854 | //If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack |
|---|
| 855 | else if( obj->GetTypeId() == TYPEID_GAMEOBJECT && (static_cast<GameObject*>(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId() ) |
|---|
| 856 | fRange = 0.0f; |
|---|
| 857 | //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, and add it whenever possible... |
|---|
| 858 | else if( plObj && curObj->GetTypeId() == TYPEID_GAMEOBJECT && (static_cast<GameObject*>(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId() ) |
|---|
| 859 | fRange = 0.0f; |
|---|
| 860 | else |
|---|
| 861 | fRange = m_UpdateDistance; // normal distance |
|---|
| 862 | |
|---|
| 863 | if ( curObj != obj && ( curObj->GetDistance2dSq( obj ) <= fRange || fRange == 0.0f ) ) |
|---|
| 864 | { |
|---|
| 865 | if( !obj->IsInRangeSet( curObj ) ) |
|---|
| 866 | { |
|---|
| 867 | // Object in range, add to set |
|---|
| 868 | obj->AddInRangeObject( curObj ); |
|---|
| 869 | curObj->AddInRangeObject( obj ); |
|---|
| 870 | |
|---|
| 871 | if( curObj->IsPlayer() ) |
|---|
| 872 | { |
|---|
| 873 | plObj2 = static_cast< Player* >( curObj ); |
|---|
| 874 | |
|---|
| 875 | if( plObj2->CanSee( obj ) && !plObj2->IsVisible( obj ) ) |
|---|
| 876 | { |
|---|
| 877 | CHECK_BUF; |
|---|
| 878 | count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); |
|---|
| 879 | plObj2->PushCreationData(*buf, count); |
|---|
| 880 | plObj2->AddVisibleObject(obj); |
|---|
| 881 | (*buf)->clear(); |
|---|
| 882 | } |
|---|
| 883 | } |
|---|
| 884 | |
|---|
| 885 | if( plObj != NULL ) |
|---|
| 886 | { |
|---|
| 887 | if( plObj->CanSee( curObj ) && !plObj->IsVisible( curObj ) ) |
|---|
| 888 | { |
|---|
| 889 | CHECK_BUF; |
|---|
| 890 | count = curObj->BuildCreateUpdateBlockForPlayer( *buf, plObj ); |
|---|
| 891 | plObj->PushCreationData( *buf, count ); |
|---|
| 892 | plObj->AddVisibleObject( curObj ); |
|---|
| 893 | (*buf)->clear(); |
|---|
| 894 | } |
|---|
| 895 | } |
|---|
| 896 | } |
|---|
| 897 | else |
|---|
| 898 | { |
|---|
| 899 | // Check visibility |
|---|
| 900 | if( curObj->IsPlayer() ) |
|---|
| 901 | { |
|---|
| 902 | plObj2 = static_cast< Player* >( curObj ); |
|---|
| 903 | cansee = plObj2->CanSee(obj); |
|---|
| 904 | isvisible = plObj2->GetVisibility(obj, &itr); |
|---|
| 905 | if(!cansee && isvisible) |
|---|
| 906 | { |
|---|
| 907 | plObj2->PushOutOfRange(obj->GetNewGUID()); |
|---|
| 908 | plObj2->RemoveVisibleObject(itr); |
|---|
| 909 | } |
|---|
| 910 | else if(cansee && !isvisible) |
|---|
| 911 | { |
|---|
| 912 | CHECK_BUF; |
|---|
| 913 | count = obj->BuildCreateUpdateBlockForPlayer(*buf, plObj2); |
|---|
| 914 | plObj2->PushCreationData(*buf, count); |
|---|
| 915 | plObj2->AddVisibleObject(obj); |
|---|
| 916 | (*buf)->clear(); |
|---|
| 917 | } |
|---|
| 918 | } |
|---|
| 919 | |
|---|
| 920 | if( plObj != NULL ) |
|---|
| 921 | { |
|---|
| 922 | cansee = plObj->CanSee( curObj ); |
|---|
| 923 | isvisible = plObj->GetVisibility( curObj, &itr ); |
|---|
| 924 | if(!cansee && isvisible) |
|---|
| 925 | { |
|---|
| 926 | plObj->PushOutOfRange( curObj->GetNewGUID() ); |
|---|
| 927 | plObj->RemoveVisibleObject( itr ); |
|---|
| 928 | } |
|---|
| 929 | else if(cansee && !isvisible) |
|---|
| 930 | { |
|---|
| 931 | CHECK_BUF; |
|---|
| 932 | count = curObj->BuildCreateUpdateBlockForPlayer( *buf, plObj ); |
|---|
| 933 | plObj->PushCreationData( *buf, count ); |
|---|
| 934 | plObj->AddVisibleObject( curObj ); |
|---|
| 935 | (*buf)->clear(); |
|---|
| 936 | } |
|---|
| 937 | } |
|---|
| 938 | } |
|---|
| 939 | } |
|---|
| 940 | } |
|---|
| 941 | } |
|---|
| 942 | |
|---|
| 943 | void MapMgr::_UpdateObjects() |
|---|
| 944 | { |
|---|
| 945 | if(!_updates.size() && !_processQueue.size()) |
|---|
| 946 | return; |
|---|
| 947 | |
|---|
| 948 | Object *pObj; |
|---|
| 949 | Player *pOwner; |
|---|
| 950 | std::set< Object* >::iterator it_start, it_end, itr; |
|---|
| 951 | Player * lplr; |
|---|
| 952 | ByteBuffer update(2500); |
|---|
| 953 | uint32 count = 0; |
|---|
| 954 | |
|---|
| 955 | m_updateMutex.Acquire(); |
|---|
| 956 | UpdateQueue::iterator iter = _updates.begin(); |
|---|
| 957 | PUpdateQueue::iterator it, eit; |
|---|
| 958 | |
|---|
| 959 | for(; iter != _updates.end();) |
|---|
| 960 | { |
|---|
| 961 | pObj = *iter; |
|---|
| 962 | ++iter; |
|---|
| 963 | if(!pObj) continue; |
|---|
| 964 | |
|---|
| 965 | if(pObj->GetTypeId() == TYPEID_ITEM || pObj->GetTypeId() == TYPEID_CONTAINER) |
|---|
| 966 | { |
|---|
| 967 | // our update is only sent to the owner here. |
|---|
| 968 | pOwner = static_cast< Item* >(pObj)->GetOwner(); |
|---|
| 969 | if( pOwner != NULL ) |
|---|
| 970 | { |
|---|
| 971 | count = static_cast< Item* >( pObj )->BuildValuesUpdateBlockForPlayer( &update, pOwner ); |
|---|
| 972 | // send update to owner |
|---|
| 973 | if( count ) |
|---|
| 974 | { |
|---|
| 975 | pOwner->PushUpdateData( &update, count ); |
|---|
| 976 | update.clear(); |
|---|
| 977 | } |
|---|
| 978 | } |
|---|
| 979 | } |
|---|
| 980 | else |
|---|
| 981 | { |
|---|
| 982 | if( pObj->IsInWorld() ) |
|---|
| 983 | { |
|---|
| 984 | // players have to receive their own updates ;) |
|---|
| 985 | if( pObj->GetTypeId() == TYPEID_PLAYER ) |
|---|
| 986 | { |
|---|
| 987 | // need to be different! ;) |
|---|
| 988 | count = pObj->BuildValuesUpdateBlockForPlayer( &update, static_cast< Player* >( pObj ) ); |
|---|
| 989 | if( count ) |
|---|
| 990 | { |
|---|
| 991 | static_cast< Player* >( pObj )->PushUpdateData( &update, count ); |
|---|
| 992 | update.clear(); |
|---|
| 993 | } |
|---|
| 994 | } |
|---|
| 995 | |
|---|
| 996 | if( pObj->IsUnit() && pObj->HasUpdateField( UNIT_FIELD_HEALTH ) ) |
|---|
| 997 | static_cast< Unit* >( pObj )->EventHealthChangeSinceLastUpdate(); |
|---|
| 998 | |
|---|
| 999 | // build the update |
|---|
| 1000 | count = pObj->BuildValuesUpdateBlockForPlayer( &update, static_cast< Player* >( NULL ) ); |
|---|
| 1001 | |
|---|
| 1002 | if( count ) |
|---|
| 1003 | { |
|---|
| 1004 | it_start = pObj->GetInRangePlayerSetBegin(); |
|---|
| 1005 | it_end = pObj->GetInRangePlayerSetEnd(); |
|---|
| 1006 | |
|---|
| 1007 | for(itr = it_start; itr != it_end;) |
|---|
| 1008 | { |
|---|
| 1009 | lplr = static_cast< Player* >( *itr ); |
|---|
| 1010 | ++itr; |
|---|
| 1011 | // Make sure that the target player can see us. |
|---|
| 1012 | if( lplr->GetTypeId() == TYPEID_PLAYER && lplr->IsVisible( pObj ) ) |
|---|
| 1013 | lplr->PushUpdateData( &update, count ); |
|---|
| 1014 | } |
|---|
| 1015 | update.clear(); |
|---|
| 1016 | } |
|---|
| 1017 | } |
|---|
| 1018 | } |
|---|
| 1019 | pObj->ClearUpdateMask(); |
|---|
| 1020 | } |
|---|
| 1021 | _updates.clear(); |
|---|
| 1022 | m_updateMutex.Release(); |
|---|
| 1023 | |
|---|
| 1024 | // generate pending a9packets and send to clients. |
|---|
| 1025 | Player *plyr; |
|---|
| 1026 | for(it = _processQueue.begin(); it != _processQueue.end();) |
|---|
| 1027 | { |
|---|
| 1028 | plyr = *it; |
|---|
| 1029 | eit = it; |
|---|
| 1030 | ++it; |
|---|
| 1031 | _processQueue.erase(eit); |
|---|
| 1032 | if(plyr->GetMapMgr() == this) |
|---|
| 1033 | plyr->ProcessPendingUpdates(); |
|---|
| 1034 | } |
|---|
| 1035 | } |
|---|
| 1036 | void MapMgr::LoadAllCells() |
|---|
| 1037 | { |
|---|
| 1038 | // eek |
|---|
| 1039 | MapCell * cellInfo; |
|---|
| 1040 | CellSpawns * spawns; |
|---|
| 1041 | |
|---|
| 1042 | for( uint32 x = 0 ; x < _sizeX ; x ++ ) |
|---|
| 1043 | { |
|---|
| 1044 | for( uint32 y = 0 ; y < _sizeY ; y ++ ) |
|---|
| 1045 | { |
|---|
| 1046 | cellInfo = GetCell( x , y ); |
|---|
| 1047 | |
|---|
| 1048 | if( !cellInfo ) |
|---|
| 1049 | { |
|---|
| 1050 | // Cell doesn't exist, create it. |
|---|
| 1051 | // There is no spoon. Err... cell. |
|---|
| 1052 | cellInfo = Create( x , y ); |
|---|
| 1053 | cellInfo->Init( x , y , _mapId , this ); |
|---|
| 1054 | sLog.outDetail( "Created cell [%u,%u] on map %u (instance %u)." , x , y , _mapId , m_instanceID ); |
|---|
| 1055 | cellInfo->SetActivity( true ); |
|---|
| 1056 | _map->CellGoneActive( x , y ); |
|---|
| 1057 | Arcemu::Util::ARCEMU_ASSERT( !cellInfo->IsLoaded() ); |
|---|
| 1058 | |
|---|
| 1059 | spawns = _map->GetSpawnsList( x , y ); |
|---|
| 1060 | if( spawns ) |
|---|
| 1061 | cellInfo->LoadObjects( spawns ); |
|---|
| 1062 | } |
|---|
| 1063 | else |
|---|
| 1064 | { |
|---|
| 1065 | // Cell exists, but is inactive |
|---|
| 1066 | if ( !cellInfo->IsActive() ) |
|---|
| 1067 | { |
|---|
| 1068 | sLog.outDetail("Activated cell [%u,%u] on map %u (instance %u).", x, y, _mapId, m_instanceID ); |
|---|
| 1069 | _map->CellGoneActive( x , y ); |
|---|
| 1070 | cellInfo->SetActivity( true ); |
|---|
| 1071 | |
|---|
| 1072 | if (!cellInfo->IsLoaded()) |
|---|
| 1073 | { |
|---|
| 1074 | //sLog.outDetail("Loading objects for Cell [%u][%u] on map %u (instance %u)...", |
|---|
| 1075 | // posX, posY, this->_mapId, m_instanceID); |
|---|
| 1076 | spawns = _map->GetSpawnsList( x , y ); |
|---|
| 1077 | if( spawns ) |
|---|
| 1078 | cellInfo->LoadObjects( spawns ); |
|---|
| 1079 | } |
|---|
| 1080 | } |
|---|
| 1081 | } |
|---|
| 1082 | } |
|---|
| 1083 | } |
|---|
| 1084 | } |
|---|
| 1085 | |
|---|
| 1086 | void MapMgr::UpdateCellActivity(uint32 x, uint32 y, int radius) |
|---|
| 1087 | { |
|---|
| 1088 | CellSpawns * sp; |
|---|
| 1089 | uint32 endX = (x + radius) <= _sizeX ? x + radius : (_sizeX-1); |
|---|
| 1090 | uint32 endY = (y + radius) <= _sizeY ? y + radius : (_sizeY-1); |
|---|
| 1091 | uint32 startX = x - radius > 0 ? x - radius : 0; |
|---|
| 1092 | uint32 startY = y - radius > 0 ? y - radius : 0; |
|---|
| 1093 | uint32 posX, posY; |
|---|
| 1094 | |
|---|
| 1095 | MapCell *objCell; |
|---|
| 1096 | |
|---|
| 1097 | for (posX = startX; posX <= endX; posX++ ) |
|---|
| 1098 | { |
|---|
| 1099 | for (posY = startY; posY <= endY; posY++ ) |
|---|
| 1100 | { |
|---|
| 1101 | objCell = GetCell(posX, posY); |
|---|
| 1102 | |
|---|
| 1103 | if (!objCell) |
|---|
| 1104 | { |
|---|
| 1105 | if (_CellActive(posX, posY)) |
|---|
| 1106 | { |
|---|
| 1107 | objCell = Create(posX, posY); |
|---|
| 1108 | objCell->Init(posX, posY, _mapId, this); |
|---|
| 1109 | |
|---|
| 1110 | sLog.outDetail("Cell [%u,%u] on map %u (instance %u) is now active.", |
|---|
| 1111 | posX, posY, this->_mapId, m_instanceID); |
|---|
| 1112 | objCell->SetActivity(true); |
|---|
| 1113 | _map->CellGoneActive(posX, posY); |
|---|
| 1114 | |
|---|
| 1115 | Arcemu::Util::ARCEMU_ASSERT( !objCell->IsLoaded()); |
|---|
| 1116 | |
|---|
| 1117 | sLog.outDetail("Loading objects for Cell [%u][%u] on map %u (instance %u)...", |
|---|
| 1118 | posX, posY, this->_mapId, m_instanceID); |
|---|
| 1119 | |
|---|
| 1120 | sp = _map->GetSpawnsList(posX, posY); |
|---|
| 1121 | if(sp) objCell->LoadObjects(sp); |
|---|
| 1122 | } |
|---|
| 1123 | } |
|---|
| 1124 | else |
|---|
| 1125 | { |
|---|
| 1126 | //Cell is now active |
|---|
| 1127 | if (_CellActive(posX, posY) && !objCell->IsActive()) |
|---|
| 1128 | { |
|---|
| 1129 | sLog.outDetail("Cell [%u,%u] on map %u (instance %u) is now active.", |
|---|
| 1130 | posX, posY, this->_mapId, m_instanceID); |
|---|
| 1131 | _map->CellGoneActive(posX, posY); |
|---|
| 1132 | objCell->SetActivity(true); |
|---|
| 1133 | |
|---|
| 1134 | if (!objCell->IsLoaded()) |
|---|
| 1135 | { |
|---|
| 1136 | sLog.outDetail("Loading objects for Cell [%u][%u] on map %u (instance %u)...", |
|---|
| 1137 | posX, posY, this->_mapId, m_instanceID); |
|---|
| 1138 | sp = _map->GetSpawnsList(posX, posY); |
|---|
| 1139 | if(sp) objCell->LoadObjects(sp); |
|---|
| 1140 | } |
|---|
| 1141 | } |
|---|
| 1142 | //Cell is no longer active |
|---|
| 1143 | else if (!_CellActive(posX, posY) && objCell->IsActive()) |
|---|
| 1144 | { |
|---|
| 1145 | sLog.outDetail("Cell [%u,%u] on map %u (instance %u) is now idle.", |
|---|
| 1146 | posX, posY, this->_mapId, m_instanceID); |
|---|
| 1147 | _map->CellGoneIdle(posX, posY); |
|---|
| 1148 | objCell->SetActivity(false); |
|---|
| 1149 | } |
|---|
| 1150 | } |
|---|
| 1151 | } |
|---|
| 1152 | } |
|---|
| 1153 | |
|---|
| 1154 | } |
|---|
| 1155 | |
|---|
| 1156 | bool MapMgr::_CellActive(uint32 x, uint32 y) |
|---|
| 1157 | { |
|---|
| 1158 | uint32 endX = ((x+1) <= _sizeX) ? x + 1 : (_sizeX-1); |
|---|
| 1159 | uint32 endY = ((y+1) <= _sizeY) ? y + 1 : (_sizeY-1); |
|---|
| 1160 | uint32 startX = x > 0 ? x - 1 : 0; |
|---|
| 1161 | uint32 startY = y > 0 ? y - 1 : 0; |
|---|
| 1162 | uint32 posX, posY; |
|---|
| 1163 | |
|---|
| 1164 | MapCell *objCell; |
|---|
| 1165 | |
|---|
| 1166 | for (posX = startX; posX <= endX; posX++ ) |
|---|
| 1167 | { |
|---|
| 1168 | for (posY = startY; posY <= endY; posY++ ) |
|---|
| 1169 | { |
|---|
| 1170 | objCell = GetCell(posX, posY); |
|---|
| 1171 | |
|---|
| 1172 | if (objCell) |
|---|
| 1173 | { |
|---|
| 1174 | if ( objCell->HasPlayers() || m_forcedcells.find( objCell ) != m_forcedcells.end() ) |
|---|
| 1175 | { |
|---|
| 1176 | return true; |
|---|
| 1177 | } |
|---|
| 1178 | } |
|---|
| 1179 | } |
|---|
| 1180 | } |
|---|
| 1181 | |
|---|
| 1182 | return false; |
|---|
| 1183 | } |
|---|
| 1184 | |
|---|
| 1185 | void MapMgr::ObjectUpdated(Object *obj) |
|---|
| 1186 | { |
|---|
| 1187 | // set our fields to dirty |
|---|
| 1188 | // stupid fucked up code in places.. i hate doing this but i've got to :< |
|---|
| 1189 | // - burlex |
|---|
| 1190 | m_updateMutex.Acquire(); |
|---|
| 1191 | _updates.insert(obj); |
|---|
| 1192 | m_updateMutex.Release(); |
|---|
| 1193 | } |
|---|
| 1194 | |
|---|
| 1195 | void MapMgr::PushToProcessed(Player* plr) |
|---|
| 1196 | { |
|---|
| 1197 | _processQueue.insert(plr); |
|---|
| 1198 | } |
|---|
| 1199 | |
|---|
| 1200 | |
|---|
| 1201 | void MapMgr::ChangeFarsightLocation(Player *plr, DynamicObject *farsight) |
|---|
| 1202 | { |
|---|
| 1203 | if(farsight == 0) |
|---|
| 1204 | { |
|---|
| 1205 | // We're clearing. |
|---|
| 1206 | for(ObjectSet::iterator itr = plr->m_visibleFarsightObjects.begin(); itr != plr->m_visibleFarsightObjects.end(); |
|---|
| 1207 | ++itr) |
|---|
| 1208 | { |
|---|
| 1209 | if(plr->IsVisible((*itr)) && !plr->CanSee((*itr))) |
|---|
| 1210 | { |
|---|
| 1211 | // Send destroy |
|---|
| 1212 | plr->PushOutOfRange((*itr)->GetNewGUID()); |
|---|
| 1213 | } |
|---|
| 1214 | } |
|---|
| 1215 | plr->m_visibleFarsightObjects.clear(); |
|---|
| 1216 | } |
|---|
| 1217 | else |
|---|
| 1218 | { |
|---|
| 1219 | uint32 cellX = GetPosX(farsight->GetPositionX()); |
|---|
| 1220 | uint32 cellY = GetPosY(farsight->GetPositionY()); |
|---|
| 1221 | uint32 endX = (cellX <= _sizeX) ? cellX + 1 : (_sizeX-1); |
|---|
| 1222 | uint32 endY = (cellY <= _sizeY) ? cellY + 1 : (_sizeY-1); |
|---|
| 1223 | uint32 startX = cellX > 0 ? cellX - 1 : 0; |
|---|
| 1224 | uint32 startY = cellY > 0 ? cellY - 1 : 0; |
|---|
| 1225 | uint32 posX, posY; |
|---|
| 1226 | MapCell *cell; |
|---|
| 1227 | Object *obj; |
|---|
| 1228 | MapCell::ObjectSet::iterator iter, iend; |
|---|
| 1229 | uint32 count; |
|---|
| 1230 | for (posX = startX; posX <= endX; ++posX ) |
|---|
| 1231 | { |
|---|
| 1232 | for (posY = startY; posY <= endY; ++posY ) |
|---|
| 1233 | { |
|---|
| 1234 | cell = GetCell(posX, posY); |
|---|
| 1235 | if (cell) |
|---|
| 1236 | { |
|---|
| 1237 | iter = cell->Begin(); |
|---|
| 1238 | iend = cell->End(); |
|---|
| 1239 | for(; iter != iend; ++iter) |
|---|
| 1240 | { |
|---|
| 1241 | obj = (*iter); |
|---|
| 1242 | if(!plr->IsVisible(obj) && plr->CanSee(obj) && farsight->GetDistance2dSq(obj) <= m_UpdateDistance) |
|---|
| 1243 | { |
|---|
| 1244 | ByteBuffer buf; |
|---|
| 1245 | count = obj->BuildCreateUpdateBlockForPlayer(&buf, plr); |
|---|
| 1246 | plr->PushCreationData(&buf, count); |
|---|
| 1247 | plr->m_visibleFarsightObjects.insert(obj); |
|---|
| 1248 | } |
|---|
| 1249 | } |
|---|
| 1250 | } |
|---|
| 1251 | } |
|---|
| 1252 | } |
|---|
| 1253 | } |
|---|
| 1254 | } |
|---|
| 1255 | |
|---|
| 1256 | bool MapMgr::run() |
|---|
| 1257 | { |
|---|
| 1258 | bool rv = true; |
|---|
| 1259 | |
|---|
| 1260 | THREAD_TRY_EXECUTION |
|---|
| 1261 | rv = Do(); |
|---|
| 1262 | THREAD_HANDLE_CRASH |
|---|
| 1263 | |
|---|
| 1264 | return rv; |
|---|
| 1265 | } |
|---|
| 1266 | |
|---|
| 1267 | bool MapMgr::Do() |
|---|
| 1268 | { |
|---|
| 1269 | #ifdef WIN32 |
|---|
| 1270 | threadid = GetCurrentThreadId(); |
|---|
| 1271 | #endif |
|---|
| 1272 | thread_running = true; |
|---|
| 1273 | ThreadState = THREADSTATE_BUSY; |
|---|
| 1274 | SetThreadName("Map mgr - M%u|I%u",this->_mapId ,this->m_instanceID); |
|---|
| 1275 | ObjectSet::iterator i; |
|---|
| 1276 | uint32 last_exec=getMSTime(); |
|---|
| 1277 | |
|---|
| 1278 | // Create Instance script |
|---|
| 1279 | LoadInstanceScript(); |
|---|
| 1280 | |
|---|
| 1281 | /* create static objects */ |
|---|
| 1282 | for(GOSpawnList::iterator itr = _map->staticSpawns.GOSpawns.begin(); itr != _map->staticSpawns.GOSpawns.end(); ++itr) |
|---|
| 1283 | { |
|---|
| 1284 | GameObject * obj = CreateGameObject((*itr)->entry); |
|---|
| 1285 | obj->Load((*itr)); |
|---|
| 1286 | _mapWideStaticObjects.insert(obj); |
|---|
| 1287 | } |
|---|
| 1288 | |
|---|
| 1289 | // Call script OnLoad virtual procedure |
|---|
| 1290 | CALL_INSTANCE_SCRIPT_EVENT( this, OnLoad )(); |
|---|
| 1291 | |
|---|
| 1292 | for(CreatureSpawnList::iterator itr = _map->staticSpawns.CreatureSpawns.begin(); itr != _map->staticSpawns.CreatureSpawns.end(); ++itr) |
|---|
| 1293 | { |
|---|
| 1294 | Creature * obj = CreateCreature((*itr)->entry); |
|---|
| 1295 | obj->Load(*itr, 0, pMapInfo); |
|---|
| 1296 | _mapWideStaticObjects.insert(obj); |
|---|
| 1297 | } |
|---|
| 1298 | |
|---|
| 1299 | /* add static objects */ |
|---|
| 1300 | for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr) |
|---|
| 1301 | PushStaticObject(*itr); |
|---|
| 1302 | |
|---|
| 1303 | /* load corpses */ |
|---|
| 1304 | objmgr.LoadCorpses(this); |
|---|
| 1305 | |
|---|
| 1306 | // always declare local variables outside of the loop! |
|---|
| 1307 | // otherwise there's a lot of sub esp; going on. |
|---|
| 1308 | |
|---|
| 1309 | uint32 exec_time, exec_start; |
|---|
| 1310 | #ifdef WIN32 |
|---|
| 1311 | HANDLE hThread = GetCurrentThread(); |
|---|
| 1312 | #endif |
|---|
| 1313 | while((ThreadState != THREADSTATE_TERMINATE) && !_shutdown) |
|---|
| 1314 | { |
|---|
| 1315 | exec_start = getMSTime(); |
|---|
| 1316 | |
|---|
| 1317 | ///////////////////////////////////////////// first push to world new objects //////////////////////////////////////////// |
|---|
| 1318 | |
|---|
| 1319 | m_objectinsertlock.Acquire(); |
|---|
| 1320 | |
|---|
| 1321 | if(m_objectinsertpool.size()) |
|---|
| 1322 | { |
|---|
| 1323 | for( i = m_objectinsertpool.begin(); i != m_objectinsertpool.end(); ++i ) |
|---|
| 1324 | { |
|---|
| 1325 | Object *o = *i; |
|---|
| 1326 | |
|---|
| 1327 | o->PushToWorld( this ); |
|---|
| 1328 | } |
|---|
| 1329 | |
|---|
| 1330 | m_objectinsertpool.clear(); |
|---|
| 1331 | } |
|---|
| 1332 | |
|---|
| 1333 | m_objectinsertlock.Release(); |
|---|
| 1334 | |
|---|
| 1335 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|---|
| 1336 | |
|---|
| 1337 | //Now update sessions of this map + objects |
|---|
| 1338 | _PerformObjectDuties(); |
|---|
| 1339 | |
|---|
| 1340 | last_exec = getMSTime(); |
|---|
| 1341 | exec_time=last_exec-exec_start; |
|---|
| 1342 | if(exec_time<MAP_MGR_UPDATE_PERIOD) |
|---|
| 1343 | { |
|---|
| 1344 | /* |
|---|
| 1345 | The common place I see this is waiting for a Win32 thread to exit. I used to come up with all sorts of goofy, |
|---|
| 1346 | elaborate event-based systems to do this myself until I discovered that thread handles are waitable. Just use |
|---|
| 1347 | WaitForSingleObject() on the thread handle and you're done. No risking race conditions with the thread exit code. |
|---|
| 1348 | I think pthreads has pthread_join() for this too. |
|---|
| 1349 | |
|---|
| 1350 | - http://www.virtualdub.org/blog/pivot/entry.php?id=62 |
|---|
| 1351 | */ |
|---|
| 1352 | |
|---|
| 1353 | #ifdef WIN32 |
|---|
| 1354 | WaitForSingleObject(hThread, MAP_MGR_UPDATE_PERIOD-exec_time); |
|---|
| 1355 | #else |
|---|
| 1356 | Sleep(MAP_MGR_UPDATE_PERIOD-exec_time); |
|---|
| 1357 | #endif |
|---|
| 1358 | } |
|---|
| 1359 | |
|---|
| 1360 | ////////////////////////////////////////////////////////////////////////// |
|---|
| 1361 | // Check if we have to die :P |
|---|
| 1362 | ////////////////////////////////////////////////////////////////////////// |
|---|
| 1363 | if(InactiveMoveTime && UNIXTIME >= InactiveMoveTime) |
|---|
| 1364 | break; |
|---|
| 1365 | } |
|---|
| 1366 | |
|---|
| 1367 | // Clear the instance's reference to us. |
|---|
| 1368 | if(m_battleground) |
|---|
| 1369 | { |
|---|
| 1370 | BattlegroundManager.DeleteBattleground(m_battleground); |
|---|
| 1371 | sInstanceMgr.DeleteBattlegroundInstance( GetMapId(), GetInstanceID() ); |
|---|
| 1372 | } |
|---|
| 1373 | |
|---|
| 1374 | if(pInstance) |
|---|
| 1375 | { |
|---|
| 1376 | // check for a non-raid instance, these expire after 10 minutes. |
|---|
| 1377 | if(GetMapInfo()->type == INSTANCE_NONRAID || pInstance->m_isBattleground) |
|---|
| 1378 | { |
|---|
| 1379 | pInstance->m_mapMgr = NULL; |
|---|
| 1380 | sInstanceMgr._DeleteInstance(pInstance, true); |
|---|
| 1381 | pInstance = NULL; |
|---|
| 1382 | } |
|---|
| 1383 | else |
|---|
| 1384 | { |
|---|
| 1385 | // just null out the pointer |
|---|
| 1386 | pInstance->m_mapMgr= NULL; |
|---|
| 1387 | } |
|---|
| 1388 | } |
|---|
| 1389 | else if(GetMapInfo()->type == INSTANCE_NULL) |
|---|
| 1390 | sInstanceMgr.m_singleMaps[GetMapId()] = NULL; |
|---|
| 1391 | |
|---|
| 1392 | // Teleport any left-over players out. |
|---|
| 1393 | TeleportPlayers(); |
|---|
| 1394 | |
|---|
| 1395 | thread_running = false; |
|---|
| 1396 | if(thread_kill_only) |
|---|
| 1397 | return false; |
|---|
| 1398 | |
|---|
| 1399 | // delete ourselves |
|---|
| 1400 | delete this; |
|---|
| 1401 | |
|---|
| 1402 | // already deleted, so the threadpool doesn't have to. |
|---|
| 1403 | return false; |
|---|
| 1404 | } |
|---|
| 1405 | |
|---|
| 1406 | void MapMgr::BeginInstanceExpireCountdown() |
|---|
| 1407 | { |
|---|
| 1408 | WorldPacket data(SMSG_RAID_GROUP_ONLY, 8); |
|---|
| 1409 | PlayerStorageMap::iterator itr; |
|---|
| 1410 | |
|---|
| 1411 | // so players getting removed don't overwrite us |
|---|
| 1412 | forced_expire = true; |
|---|
| 1413 | |
|---|
| 1414 | // send our sexy packet |
|---|
| 1415 | data << uint32(60000) << uint32(1); |
|---|
| 1416 | for(itr = m_PlayerStorage.begin(); itr != m_PlayerStorage.end(); ++itr) |
|---|
| 1417 | { |
|---|
| 1418 | if(!itr->second->raidgrouponlysent) |
|---|
| 1419 | itr->second->GetSession()->SendPacket(&data); |
|---|
| 1420 | } |
|---|
| 1421 | |
|---|
| 1422 | // set our expire time to 60 seconds. |
|---|
| 1423 | InactiveMoveTime = UNIXTIME + 60; |
|---|
| 1424 | } |
|---|
| 1425 | |
|---|
| 1426 | void MapMgr::AddObject(Object *obj) |
|---|
| 1427 | { |
|---|
| 1428 | m_objectinsertlock.Acquire();//<<<<<<<<<<<< |
|---|
| 1429 | m_objectinsertpool.insert(obj); |
|---|
| 1430 | m_objectinsertlock.Release();//>>>>>>>>>>>> |
|---|
| 1431 | } |
|---|
| 1432 | |
|---|
| 1433 | |
|---|
| 1434 | Unit* MapMgr::GetUnit(const uint64 & guid) |
|---|
| 1435 | { |
|---|
| 1436 | if ( guid == 0 ) |
|---|
| 1437 | return NULL; |
|---|
| 1438 | |
|---|
| 1439 | switch(GET_TYPE_FROM_GUID(guid)) |
|---|
| 1440 | { |
|---|
| 1441 | case HIGHGUID_TYPE_UNIT: |
|---|
| 1442 | return GetCreature( GET_LOWGUID_PART(guid) ); |
|---|
| 1443 | break; |
|---|
| 1444 | |
|---|
| 1445 | case HIGHGUID_TYPE_PLAYER: |
|---|
| 1446 | return GetPlayer( (uint32)guid ); |
|---|
| 1447 | break; |
|---|
| 1448 | |
|---|
| 1449 | case HIGHGUID_TYPE_PET: |
|---|
| 1450 | return GetPet( GET_LOWGUID_PART( guid ) ); |
|---|
| 1451 | break; |
|---|
| 1452 | } |
|---|
| 1453 | |
|---|
| 1454 | return NULL; |
|---|
| 1455 | } |
|---|
| 1456 | |
|---|
| 1457 | Object* MapMgr::_GetObject(const uint64 & guid) |
|---|
| 1458 | { |
|---|
| 1459 | if (!guid) |
|---|
| 1460 | return NULL; |
|---|
| 1461 | |
|---|
| 1462 | switch(GET_TYPE_FROM_GUID(guid)) |
|---|
| 1463 | { |
|---|
| 1464 | case HIGHGUID_TYPE_GAMEOBJECT: |
|---|
| 1465 | return GetGameObject(GET_LOWGUID_PART(guid)); |
|---|
| 1466 | break; |
|---|
| 1467 | case HIGHGUID_TYPE_UNIT: |
|---|
| 1468 | return GetCreature(GET_LOWGUID_PART(guid)); |
|---|
| 1469 | break; |
|---|
| 1470 | case HIGHGUID_TYPE_DYNAMICOBJECT: |
|---|
| 1471 | return GetDynamicObject((uint32)guid); |
|---|
| 1472 | break; |
|---|
| 1473 | case HIGHGUID_TYPE_TRANSPORTER: |
|---|
| 1474 | return objmgr.GetTransporter(Arcemu::Util::GUID_LOPART( guid )); |
|---|
| 1475 | break; |
|---|
| 1476 | default: |
|---|
| 1477 | return GetUnit(guid); |
|---|
| 1478 | break; |
|---|
| 1479 | } |
|---|
| 1480 | } |
|---|
| 1481 | |
|---|
| 1482 | void MapMgr::_PerformObjectDuties() |
|---|
| 1483 | { |
|---|
| 1484 | ++mLoopCounter; |
|---|
| 1485 | uint32 mstime = getMSTime(); |
|---|
| 1486 | uint32 difftime = mstime - lastUnitUpdate; |
|---|
| 1487 | if(difftime > 500) |
|---|
| 1488 | difftime = 500; |
|---|
| 1489 | |
|---|
| 1490 | // Update any events. |
|---|
| 1491 | // we make update of events before objects so in case there are 0 timediff events they do not get deleted after update but on next server update loop |
|---|
| 1492 | eventHolder.Update(difftime); |
|---|
| 1493 | |
|---|
| 1494 | // Update creatures. |
|---|
| 1495 | { |
|---|
| 1496 | CreatureSet creatures(activeCreatures); |
|---|
| 1497 | CreatureSet::iterator itr = creatures.begin(); |
|---|
| 1498 | Creature * ptr; |
|---|
| 1499 | Pet * ptr2; |
|---|
| 1500 | |
|---|
| 1501 | for(; itr != creatures.end();) |
|---|
| 1502 | { |
|---|
| 1503 | ptr = *itr; |
|---|
| 1504 | ++itr; |
|---|
| 1505 | if( activeCreatures.find(ptr) != activeCreatures.end())//required by owners despawning creatures and deleting *(++itr) |
|---|
| 1506 | ptr->Update(difftime); |
|---|
| 1507 | } |
|---|
| 1508 | |
|---|
| 1509 | PetStorageMap::iterator it2 = m_PetStorage.begin(); |
|---|
| 1510 | for(; it2 != m_PetStorage.end();) |
|---|
| 1511 | { |
|---|
| 1512 | ptr2 = it2->second; |
|---|
| 1513 | ++it2; |
|---|
| 1514 | if(ptr2 != NULL) |
|---|
| 1515 | ptr2->Update(difftime); |
|---|
| 1516 | } |
|---|
| 1517 | } |
|---|
| 1518 | |
|---|
| 1519 | // Update players. |
|---|
| 1520 | { |
|---|
| 1521 | PlayerStorageMap::iterator itr = m_PlayerStorage.begin(); |
|---|
| 1522 | Player* ptr; |
|---|
| 1523 | for(; itr != m_PlayerStorage.end(); ) |
|---|
| 1524 | { |
|---|
| 1525 | ptr = static_cast< Player* >( itr->second ); |
|---|
| 1526 | ++itr; |
|---|
| 1527 | if( ptr != NULL ) |
|---|
| 1528 | ptr->Update( difftime ); |
|---|
| 1529 | } |
|---|
| 1530 | |
|---|
| 1531 | lastUnitUpdate = mstime; |
|---|
| 1532 | } |
|---|
| 1533 | |
|---|
| 1534 | // Dynamic objects |
|---|
| 1535 | // |
|---|
| 1536 | // We take the pointer, increment, and update in this order because during the update the DynamicObject might get deleted, |
|---|
| 1537 | // rendering the iterator unincrementable. Which causes a crash! |
|---|
| 1538 | { |
|---|
| 1539 | for( DynamicObjectStorageMap::iterator itr = m_DynamicObjectStorage.begin(); itr != m_DynamicObjectStorage.end(); ){ |
|---|
| 1540 | |
|---|
| 1541 | DynamicObject *o = itr->second; |
|---|
| 1542 | ++itr; |
|---|
| 1543 | |
|---|
| 1544 | o->UpdateTargets(); |
|---|
| 1545 | } |
|---|
| 1546 | } |
|---|
| 1547 | |
|---|
| 1548 | // Update gameobjects (not on every loop, however) |
|---|
| 1549 | if( mLoopCounter % 2 ) |
|---|
| 1550 | { |
|---|
| 1551 | difftime = mstime - lastGameobjectUpdate; |
|---|
| 1552 | |
|---|
| 1553 | GameObjectSet::iterator itr = activeGameObjects.begin(); |
|---|
| 1554 | GameObject * ptr; |
|---|
| 1555 | for(; itr != activeGameObjects.end(); ) |
|---|
| 1556 | { |
|---|
| 1557 | ptr = *itr; |
|---|
| 1558 | ++itr; |
|---|
| 1559 | if(ptr != NULL) |
|---|
| 1560 | ptr->Update( difftime ); |
|---|
| 1561 | } |
|---|
| 1562 | |
|---|
| 1563 | lastGameobjectUpdate = mstime; |
|---|
| 1564 | } |
|---|
| 1565 | |
|---|
| 1566 | // Sessions are updated every loop. |
|---|
| 1567 | { |
|---|
| 1568 | int result; |
|---|
| 1569 | WorldSession * session; |
|---|
| 1570 | SessionSet::iterator itr = Sessions.begin(); |
|---|
| 1571 | SessionSet::iterator it2; |
|---|
| 1572 | |
|---|
| 1573 | for(; itr != Sessions.end();) |
|---|
| 1574 | { |
|---|
| 1575 | session = (*itr); |
|---|
| 1576 | it2 = itr; |
|---|
| 1577 | ++itr; |
|---|
| 1578 | |
|---|
| 1579 | if(session->GetInstance() != m_instanceID) |
|---|
| 1580 | { |
|---|
| 1581 | Sessions.erase(it2); |
|---|
| 1582 | continue; |
|---|
| 1583 | } |
|---|
| 1584 | |
|---|
| 1585 | // Don't update players not on our map. |
|---|
| 1586 | // If we abort in the handler, it means we will "lose" packets, or not process this. |
|---|
| 1587 | // .. and that could be disastrous to our client :P |
|---|
| 1588 | if(session->GetPlayer() && (session->GetPlayer()->GetMapMgr() != this && session->GetPlayer()->GetMapMgr() != 0)) |
|---|
| 1589 | { |
|---|
| 1590 | continue; |
|---|
| 1591 | } |
|---|
| 1592 | |
|---|
| 1593 | if((result = session->Update(m_instanceID)) != 0) |
|---|
| 1594 | { |
|---|
| 1595 | if(result == 1) |
|---|
| 1596 | { |
|---|
| 1597 | // complete deletion |
|---|
| 1598 | sWorld.DeleteSession(session); |
|---|
| 1599 | } |
|---|
| 1600 | Sessions.erase(it2); |
|---|
| 1601 | } |
|---|
| 1602 | } |
|---|
| 1603 | } |
|---|
| 1604 | |
|---|
| 1605 | // Finally, A9 Building/Distribution |
|---|
| 1606 | _UpdateObjects(); |
|---|
| 1607 | } |
|---|
| 1608 | |
|---|
| 1609 | void MapMgr::EventCorpseDespawn(uint64 guid) |
|---|
| 1610 | { |
|---|
| 1611 | Corpse * pCorpse = objmgr.GetCorpse((uint32)guid); |
|---|
| 1612 | if(pCorpse == NULL) // Already Deleted |
|---|
| 1613 | return; |
|---|
| 1614 | |
|---|
| 1615 | if(pCorpse->GetMapMgr() != this) |
|---|
| 1616 | return; |
|---|
| 1617 | |
|---|
| 1618 | pCorpse->Despawn(); |
|---|
| 1619 | delete pCorpse; |
|---|
| 1620 | } |
|---|
| 1621 | |
|---|
| 1622 | void MapMgr::TeleportPlayers() |
|---|
| 1623 | { |
|---|
| 1624 | PlayerStorageMap::iterator itr = m_PlayerStorage.begin(); |
|---|
| 1625 | if(!bServerShutdown) |
|---|
| 1626 | { |
|---|
| 1627 | for(; itr != m_PlayerStorage.end();) |
|---|
| 1628 | { |
|---|
| 1629 | Player *p = itr->second; |
|---|
| 1630 | ++itr; |
|---|
| 1631 | p->EjectFromInstance(); |
|---|
| 1632 | } |
|---|
| 1633 | } |
|---|
| 1634 | else |
|---|
| 1635 | { |
|---|
| 1636 | for(; itr != m_PlayerStorage.end();) |
|---|
| 1637 | { |
|---|
| 1638 | Player *p = itr->second; |
|---|
| 1639 | ++itr; |
|---|
| 1640 | if(p->GetSession()) |
|---|
| 1641 | p->GetSession()->LogoutPlayer(false); |
|---|
| 1642 | else |
|---|
| 1643 | delete p; |
|---|
| 1644 | } |
|---|
| 1645 | } |
|---|
| 1646 | } |
|---|
| 1647 | |
|---|
| 1648 | void MapMgr::UnloadCell(uint32 x,uint32 y) |
|---|
| 1649 | { |
|---|
| 1650 | MapCell * c = GetCell(x,y); |
|---|
| 1651 | if(c == NULL || c->HasPlayers() || _CellActive(x,y) || !c->IsUnloadPending()) return; |
|---|
| 1652 | |
|---|
| 1653 | sLog.outDetail("Unloading Cell [%u][%u] on map %u (instance %u)...", |
|---|
| 1654 | x,y,_mapId,m_instanceID); |
|---|
| 1655 | |
|---|
| 1656 | c->Unload(); |
|---|
| 1657 | } |
|---|
| 1658 | |
|---|
| 1659 | void MapMgr::EventRespawnCreature(Creature * c, MapCell * p) |
|---|
| 1660 | { |
|---|
| 1661 | ObjectSet::iterator itr = p->_respawnObjects.find((Object*)c); |
|---|
| 1662 | if(itr != p->_respawnObjects.end()) |
|---|
| 1663 | { |
|---|
| 1664 | c->m_respawnCell= NULL; |
|---|
| 1665 | p->_respawnObjects.erase(itr); |
|---|
| 1666 | c->OnRespawn(this); |
|---|
| 1667 | } |
|---|
| 1668 | } |
|---|
| 1669 | |
|---|
| 1670 | void MapMgr::EventRespawnGameObject(GameObject * o, MapCell * c) |
|---|
| 1671 | { |
|---|
| 1672 | ObjectSet::iterator itr = c->_respawnObjects.find((Object*)o); |
|---|
| 1673 | if(itr != c->_respawnObjects.end()) |
|---|
| 1674 | { |
|---|
| 1675 | o->m_respawnCell= NULL; |
|---|
| 1676 | c->_respawnObjects.erase(itr); |
|---|
| 1677 | o->Spawn(this); |
|---|
| 1678 | } |
|---|
| 1679 | } |
|---|
| 1680 | |
|---|
| 1681 | void MapMgr::SendChatMessageToCellPlayers(Object * obj, WorldPacket * packet, uint32 cell_radius, uint32 langpos, int32 lang, WorldSession * originator) |
|---|
| 1682 | { |
|---|
| 1683 | uint32 cellX = GetPosX(obj->GetPositionX()); |
|---|
| 1684 | uint32 cellY = GetPosY(obj->GetPositionY()); |
|---|
| 1685 | uint32 endX = ((cellX+cell_radius) <= _sizeX) ? cellX + cell_radius : (_sizeX-1); |
|---|
| 1686 | uint32 endY = ((cellY+cell_radius) <= _sizeY) ? cellY + cell_radius : (_sizeY-1); |
|---|
| 1687 | uint32 startX = (cellX-cell_radius) > 0 ? cellX - cell_radius : 0; |
|---|
| 1688 | uint32 startY = (cellY-cell_radius) > 0 ? cellY - cell_radius : 0; |
|---|
| 1689 | |
|---|
| 1690 | uint32 posX, posY; |
|---|
| 1691 | MapCell *cell; |
|---|
| 1692 | MapCell::ObjectSet::iterator iter, iend; |
|---|
| 1693 | for (posX = startX; posX <= endX; ++posX ) |
|---|
| 1694 | { |
|---|
| 1695 | for (posY = startY; posY <= endY; ++posY ) |
|---|
| 1696 | { |
|---|
| 1697 | cell = GetCell(posX, posY); |
|---|
| 1698 | if (cell && cell->HasPlayers() ) |
|---|
| 1699 | { |
|---|
| 1700 | iter = cell->Begin(); |
|---|
| 1701 | iend = cell->End(); |
|---|
| 1702 | for(; iter != iend; ++iter) |
|---|
| 1703 | { |
|---|
| 1704 | if((*iter)->IsPlayer()) |
|---|
| 1705 | { |
|---|
| 1706 | //static_cast< Player* >(*iter)->GetSession()->SendPacket(packet); |
|---|
| 1707 | if ( static_cast< Player* >(*iter)->GetPhase() & obj->GetPhase() ) |
|---|
| 1708 | static_cast< Player* >(*iter)->GetSession()->SendChatPacket(packet, langpos, lang, originator); |
|---|
| 1709 | } |
|---|
| 1710 | } |
|---|
| 1711 | } |
|---|
| 1712 | } |
|---|
| 1713 | } |
|---|
| 1714 | } |
|---|
| 1715 | |
|---|
| 1716 | Creature * MapMgr::GetSqlIdCreature(uint32 sqlid) |
|---|
| 1717 | { |
|---|
| 1718 | CreatureSqlIdMap::iterator itr = _sqlids_creatures.find(sqlid); |
|---|
| 1719 | return (itr == _sqlids_creatures.end()) ? NULL : itr->second; |
|---|
| 1720 | } |
|---|
| 1721 | |
|---|
| 1722 | GameObject * MapMgr::GetSqlIdGameObject(uint32 sqlid) |
|---|
| 1723 | { |
|---|
| 1724 | GameObjectSqlIdMap::iterator itr = _sqlids_gameobjects.find(sqlid); |
|---|
| 1725 | return (itr == _sqlids_gameobjects.end()) ? NULL : itr->second; |
|---|
| 1726 | } |
|---|
| 1727 | |
|---|
| 1728 | Creature * MapMgr::CreateCreature(uint32 entry, bool isVehicle) |
|---|
| 1729 | { |
|---|
| 1730 | uint64 newguid = (uint64)HIGHGUID_TYPE_UNIT << 32; |
|---|
| 1731 | char * pHighGuid = (char*)&newguid; |
|---|
| 1732 | char * pEntry = (char*)&entry; |
|---|
| 1733 | pHighGuid[3] |= pEntry[0]; |
|---|
| 1734 | pHighGuid[4] |= pEntry[1]; |
|---|
| 1735 | pHighGuid[5] |= pEntry[2]; |
|---|
| 1736 | pHighGuid[6] |= pEntry[3]; |
|---|
| 1737 | |
|---|
| 1738 | if (isVehicle) |
|---|
| 1739 | sLog.outDebug("CreateCreature: IsVehicle = true"); |
|---|
| 1740 | |
|---|
| 1741 | if(_reusable_guids_creature.size()) |
|---|
| 1742 | { |
|---|
| 1743 | uint32 guid = _reusable_guids_creature.front(); |
|---|
| 1744 | _reusable_guids_creature.pop_front(); |
|---|
| 1745 | |
|---|
| 1746 | newguid |= guid; |
|---|
| 1747 | if (isVehicle) |
|---|
| 1748 | return new Vehicle(newguid); |
|---|
| 1749 | else |
|---|
| 1750 | return new Creature(newguid); |
|---|
| 1751 | } |
|---|
| 1752 | |
|---|
| 1753 | if( ++m_CreatureHighGuid >= CreatureStorage.size() ) |
|---|
| 1754 | { |
|---|
| 1755 | // Reallocate array with larger size. |
|---|
| 1756 | uint32 newsize = CreatureStorage.size() + RESERVE_EXPAND_SIZE; |
|---|
| 1757 | CreatureStorage.resize( newsize, NULL ); |
|---|
| 1758 | } |
|---|
| 1759 | |
|---|
| 1760 | newguid |= m_CreatureHighGuid; |
|---|
| 1761 | if (isVehicle) |
|---|
| 1762 | return new Vehicle(newguid); |
|---|
| 1763 | else |
|---|
| 1764 | return new Creature(newguid); |
|---|
| 1765 | } |
|---|
| 1766 | |
|---|
| 1767 | // Spawns the object too, without which you can not interact with the object |
|---|
| 1768 | GameObject * MapMgr::CreateAndSpawnGameObject(uint32 entryID, float x, float y, float z, float o, float scale) |
|---|
| 1769 | { |
|---|
| 1770 | GameObjectInfo* goi = GameObjectNameStorage.LookupEntry(entryID); |
|---|
| 1771 | if(!goi) |
|---|
| 1772 | { |
|---|
| 1773 | sLog.outDebug("Error looking up entry in CreateAndSpawnGameObject"); |
|---|
| 1774 | return NULL; |
|---|
| 1775 | } |
|---|
| 1776 | |
|---|
| 1777 | sLog.outDebug("CreateAndSpawnGameObject: By Entry '%u'", entryID); |
|---|
| 1778 | |
|---|
| 1779 | GameObject *go = CreateGameObject(entryID); |
|---|
| 1780 | |
|---|
| 1781 | //Player *chr = m_session->GetPlayer(); |
|---|
| 1782 | uint32 mapid = GetMapId(); |
|---|
| 1783 | // Setup game object |
|---|
| 1784 | go->SetInstanceID(GetInstanceID()); |
|---|
| 1785 | go->CreateFromProto(entryID,mapid,x,y,z,o); |
|---|
| 1786 | go->SetScale( scale); |
|---|
| 1787 | go->InitAI(); |
|---|
| 1788 | go->PushToWorld(this); |
|---|
| 1789 | |
|---|
| 1790 | // Create spawn instance |
|---|
| 1791 | GOSpawn * gs = new GOSpawn; |
|---|
| 1792 | gs->entry = go->GetEntry(); |
|---|
| 1793 | gs->facing = go->GetOrientation(); |
|---|
| 1794 | gs->faction = go->GetFaction(); |
|---|
| 1795 | gs->flags = go->GetUInt32Value(GAMEOBJECT_FLAGS); |
|---|
| 1796 | gs->id = objmgr.GenerateGameObjectSpawnID(); |
|---|
| 1797 | // gs->o = go->GetFloatValue(GAMEOBJECT_ROTATION); |
|---|
| 1798 | gs->o1 = go->GetParentRotation(0); |
|---|
| 1799 | gs->o2 = go->GetParentRotation(2); |
|---|
| 1800 | gs->o3 = go->GetParentRotation(3); |
|---|
| 1801 | gs->scale = go->GetScale(); |
|---|
| 1802 | gs->x = go->GetPositionX(); |
|---|
| 1803 | gs->y = go->GetPositionY(); |
|---|
| 1804 | gs->z = go->GetPositionZ(); |
|---|
| 1805 | gs->state = go->GetByte(GAMEOBJECT_BYTES_1, 0); |
|---|
| 1806 | //gs->stateNpcLink = 0; |
|---|
| 1807 | |
|---|
| 1808 | uint32 cx = GetPosX(x); |
|---|
| 1809 | uint32 cy = GetPosY(y); |
|---|
| 1810 | |
|---|
| 1811 | GetBaseMap()->GetSpawnsListAndCreate(cx,cy)->GOSpawns.push_back(gs); |
|---|
| 1812 | go->m_spawn = gs; |
|---|
| 1813 | |
|---|
| 1814 | MapCell * mCell = GetCell( cx, cy ); |
|---|
| 1815 | |
|---|
| 1816 | if( mCell != NULL ) |
|---|
| 1817 | mCell->SetLoaded(); |
|---|
| 1818 | |
|---|
| 1819 | return go; |
|---|
| 1820 | } |
|---|
| 1821 | |
|---|
| 1822 | GameObject * MapMgr::CreateGameObject(uint32 entry) |
|---|
| 1823 | { |
|---|
| 1824 | if( _reusable_guids_gameobject.size() > GO_GUID_RECYCLE_INTERVAL ) |
|---|
| 1825 | { |
|---|
| 1826 | uint32 guid = _reusable_guids_gameobject.front(); |
|---|
| 1827 | _reusable_guids_gameobject.pop_front(); |
|---|
| 1828 | return new GameObject((uint64)HIGHGUID_TYPE_GAMEOBJECT<<32 | guid); |
|---|
| 1829 | } |
|---|
| 1830 | |
|---|
| 1831 | if(++m_GOHighGuid >= GOStorage.size() ) |
|---|
| 1832 | { |
|---|
| 1833 | // Reallocate array with larger size. |
|---|
| 1834 | uint32 newsize = GOStorage.size() + RESERVE_EXPAND_SIZE; |
|---|
| 1835 | GOStorage.resize( newsize, NULL ); |
|---|
| 1836 | } |
|---|
| 1837 | return new GameObject((uint64)HIGHGUID_TYPE_GAMEOBJECT<<32 | m_GOHighGuid); |
|---|
| 1838 | } |
|---|
| 1839 | |
|---|
| 1840 | DynamicObject * MapMgr::CreateDynamicObject() |
|---|
| 1841 | { |
|---|
| 1842 | return new DynamicObject(HIGHGUID_TYPE_DYNAMICOBJECT,(++m_DynamicObjectHighGuid)); |
|---|
| 1843 | } |
|---|
| 1844 | |
|---|
| 1845 | void MapMgr::AddForcedCell( MapCell * c ) |
|---|
| 1846 | { |
|---|
| 1847 | m_forcedcells.insert( c ); |
|---|
| 1848 | UpdateCellActivity( c->GetPositionX(), c->GetPositionY(), 1 ); |
|---|
| 1849 | } |
|---|
| 1850 | void MapMgr::RemoveForcedCell(MapCell* c) |
|---|
| 1851 | { |
|---|
| 1852 | m_forcedcells.erase( c ); |
|---|
| 1853 | UpdateCellActivity( c->GetPositionX(), c->GetPositionY(), 1 ); |
|---|
| 1854 | } |
|---|
| 1855 | |
|---|
| 1856 | float MapMgr::GetFirstZWithCPZ( float x, float y, float z ) |
|---|
| 1857 | { |
|---|
| 1858 | if( !sWorld.Collision ) |
|---|
| 1859 | return NO_WMO_HEIGHT; |
|---|
| 1860 | |
|---|
| 1861 | float posZ = NO_WMO_HEIGHT; |
|---|
| 1862 | for( int i = Z_SEARCH_RANGE; i >= -Z_SEARCH_RANGE; i-- ) |
|---|
| 1863 | { |
|---|
| 1864 | //if ( i== 0 && !IsUnderground(x,y,z) ) return GetBaseMap()->GetLandHeight(x, y); |
|---|
| 1865 | posZ = CollideInterface.GetHeight( GetMapId(), x, y, z + ( float )i ); |
|---|
| 1866 | if( posZ != NO_WMO_HEIGHT ) |
|---|
| 1867 | break; |
|---|
| 1868 | } |
|---|
| 1869 | return posZ; |
|---|
| 1870 | } |
|---|
| 1871 | |
|---|
| 1872 | void MapMgr::SendPvPCaptureMessage(int32 ZoneMask, uint32 ZoneId, const char * Message, ...) |
|---|
| 1873 | { |
|---|
| 1874 | va_list ap; |
|---|
| 1875 | va_start(ap, Message); |
|---|
| 1876 | |
|---|
| 1877 | WorldPacket data(SMSG_DEFENSE_MESSAGE, 208); |
|---|
| 1878 | char msgbuf[200]; |
|---|
| 1879 | vsnprintf(msgbuf, 200, Message, ap); |
|---|
| 1880 | va_end(ap); |
|---|
| 1881 | |
|---|
| 1882 | data << ZoneId; |
|---|
| 1883 | data << uint32(strlen(msgbuf)+1); |
|---|
| 1884 | data << msgbuf; |
|---|
| 1885 | |
|---|
| 1886 | PlayerStorageMap::iterator itr = m_PlayerStorage.begin(); |
|---|
| 1887 | for(; itr != m_PlayerStorage.end();) |
|---|
| 1888 | { |
|---|
| 1889 | Player *plr = itr->second; |
|---|
| 1890 | ++itr; |
|---|
| 1891 | |
|---|
| 1892 | if( ( ZoneMask != ZONE_MASK_ALL && plr->GetZoneId() != (uint32)ZoneMask) ) |
|---|
| 1893 | continue; |
|---|
| 1894 | |
|---|
| 1895 | plr->GetSession()->SendPacket(&data); |
|---|
| 1896 | } |
|---|
| 1897 | } |
|---|
| 1898 | |
|---|
| 1899 | void MapMgr::LoadInstanceScript() |
|---|
| 1900 | { |
|---|
| 1901 | mInstanceScript = sScriptMgr.CreateScriptClassForInstance( _mapId, this ); |
|---|
| 1902 | }; |
|---|
| 1903 | |
|---|
| 1904 | void MapMgr::CallScriptUpdate() |
|---|
| 1905 | { |
|---|
| 1906 | Arcemu::Util::ARCEMU_ASSERT( mInstanceScript != NULL ); |
|---|
| 1907 | mInstanceScript->UpdateEvent(); |
|---|
| 1908 | }; |
|---|