TrinityCore
Map.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Map.h"
19#include "Battleground.h"
20#include "BattlegroundMgr.h"
21#include "BattlegroundScript.h"
22#include "CellImpl.h"
23#include "CharacterPackets.h"
24#include "Containers.h"
25#include "Conversation.h"
26#include "DB2Stores.h"
27#include "DatabaseEnv.h"
28#include "DynamicTree.h"
29#include "GameObjectModel.h"
30#include "GameTime.h"
31#include "GridNotifiers.h"
32#include "GridNotifiersImpl.h"
33#include "GridStates.h"
34#include "Group.h"
35#include "InstanceLockMgr.h"
36#include "InstancePackets.h"
37#include "InstanceScenario.h"
38#include "InstanceScript.h"
39#include "Log.h"
40#include "MapManager.h"
41#include "Metric.h"
42#include "MiscPackets.h"
43#include "MotionMaster.h"
44#include "ObjectAccessor.h"
45#include "ObjectGridLoader.h"
46#include "ObjectMgr.h"
47#include "Pet.h"
48#include "PhasingHandler.h"
49#include "PoolMgr.h"
50#include "ScriptMgr.h"
51#include "SpellAuras.h"
52#include "TerrainMgr.h"
53#include "Transport.h"
54#include "VMapFactory.h"
55#include "VMapManager2.h"
56#include "Vehicle.h"
57#include "Vignette.h"
58#include "VignettePackets.h"
59#include "Weather.h"
60#include "WeatherMgr.h"
61#include "World.h"
62#include "WorldSession.h"
63#include "WorldStateMgr.h"
64#include "WorldStatePackets.h"
65#include <boost/heap/fibonacci_heap.hpp>
66#include <sstream>
67
68#define DEFAULT_GRID_EXPIRY 300
69#define MAX_GRID_LOAD_TIME 50
70#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld->getRate(RATE_CREATURE_AGGRO))
71
73
74ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), DefaultWeather(nullptr), WeatherId(WEATHER_STATE_FINE),
75 Intensity(0.0f) { }
76
78
80struct RespawnListContainer : boost::heap::fibonacci_heap<RespawnInfoWithHandle*, boost::heap::compare<CompareRespawnInfo>>
81{
82};
83
85{
86 explicit RespawnInfoWithHandle(RespawnInfo const& other) : RespawnInfo(other) { }
87
88 RespawnListContainer::handle_type handle;
89};
90
92{
93 // Delete all waiting spawns, else there will be a memory leak
94 // This doesn't delete from database.
96
97 while (!i_worldObjects.empty())
98 {
99 WorldObject* obj = *i_worldObjects.begin();
101 //ASSERT(obj->GetTypeId() == TYPEID_CORPSE);
102 obj->RemoveFromWorld();
103 obj->ResetMap();
104 }
105
106 if (!m_scriptSchedule.empty())
107 sMapMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
108
109 m_terrain->UnloadMMapInstance(GetId(), GetInstanceId());
110}
111
113{
114 for (uint32 cellX = 0; cellX < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellX++)
115 for (uint32 cellY = 0; cellY < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellY++)
117}
118
120{
125}
126
128{
133}
134
135Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode) :
136_creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false), _areaTriggersToMoveLock(false),
137i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
138m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
139m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD),
140m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()),
141i_gridExpiry(expiry), m_terrain(sTerrainMgr.LoadTerrain(id)), m_forceEnabledNavMeshFilterFlags(0), m_forceDisabledNavMeshFilterFlags(0),
142i_scriptLock(false), _respawnTimes(std::make_unique<RespawnListContainer>()), _respawnCheckTimer(0), _vignetteUpdateTimer(5200, 5200)
143{
144 for (uint32 x = 0; x < MAX_NUMBER_OF_GRIDS; ++x)
145 {
146 for (uint32 y = 0; y < MAX_NUMBER_OF_GRIDS; ++y)
147 {
148 //z code
149 setNGrid(nullptr, x, y);
150 }
151 }
152
153 _zonePlayerCountMap.clear();
154
155 //lets initialize visibility distance for map
157
159
160 GetGuidSequenceGenerator(HighGuid::Transport).Set(sObjectMgr->GetGenerator<HighGuid::Transport>().GetNextAfterMaxUsed());
161
162 _poolData = sPoolMgr->InitPoolsForMap(this);
163
164 sTransportMgr->CreateTransportsForMap(this);
165
166 m_terrain->LoadMMapInstance(GetId(), GetInstanceId());
167
168 _worldStateValues = sWorldStateMgr->GetInitialWorldStatesForMap(this);
169}
170
172{
173 //init visibility for continents
176}
177
178// Template specialization of utility methods
179template<class T>
180void Map::AddToGrid(T* obj, Cell const& cell)
181{
182 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
183 if (obj->IsStoredInWorldObjectGridContainer())
184 grid->GetGridType(cell.CellX(), cell.CellY()).template AddWorldObject<T>(obj);
185 else
186 grid->GetGridType(cell.CellX(), cell.CellY()).template AddGridObject<T>(obj);
187}
188
189template<>
190void Map::AddToGrid(Creature* obj, Cell const& cell)
191{
192 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
194 grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj);
195 else
196 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
197
198 obj->SetCurrentCell(cell);
199}
200
201template<>
202void Map::AddToGrid(GameObject* obj, Cell const& cell)
203{
204 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
205 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
206
207 obj->SetCurrentCell(cell);
208}
209
210template<>
211void Map::AddToGrid(DynamicObject* obj, Cell const& cell)
212{
213 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
215 grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj);
216 else
217 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
218
219 obj->SetCurrentCell(cell);
220}
221
222template<>
223void Map::AddToGrid(AreaTrigger* obj, Cell const& cell)
224{
225 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
226 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
227
228 obj->SetCurrentCell(cell);
229}
230
231template<>
232void Map::AddToGrid(Corpse* obj, Cell const& cell)
233{
234 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
235 // Corpses are a special object type - they can be added to grid via a call to AddToMap
236 // or loaded through ObjectGridLoader.
237 // Both corpses loaded from database and these freshly generated by Player::CreateCoprse are added to _corpsesByCell
238 // ObjectGridLoader loads all corpses from _corpsesByCell even if they were already added to grid before it was loaded
239 // so we need to explicitly check it here (Map::AddToGrid is only called from Player::BuildPlayerRepop, not from ObjectGridLoader)
240 // to avoid failing an assertion in GridObject::AddToGrid
241 if (grid->isGridObjectDataLoaded())
242 {
244 grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj);
245 else
246 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
247 }
248}
249
250template<class T>
251void Map::SwitchGridContainers(T* /*obj*/, bool /*on*/) { }
252
253template<>
255{
258 if (!p.IsCoordValid())
259 {
260 TC_LOG_ERROR("maps", "Map::SwitchGridContainers: Object {} has invalid coordinates X:{} Y:{} grid cell [{}:{}]", obj->GetGUID().ToString(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord);
261 return;
262 }
263
264 Cell cell(p);
266 return;
267
268 if (sLog->ShouldLog("maps", LOG_LEVEL_DEBUG))
269 {
270 // Extract bitfield values
271 uint32 const grid_x = cell.data.Part.grid_x;
272 uint32 const grid_y = cell.data.Part.grid_y;
273
274 TC_LOG_DEBUG("maps", "Switch object {} from grid[{}, {}] {}", obj->GetGUID().ToString(), grid_x, grid_y, on);
275 }
276
277 NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
278 ASSERT(ngrid != nullptr);
279
280 GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
281
282 obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
283
284 if (on)
285 {
286 grid.AddWorldObject(obj);
287 AddWorldObject(obj);
288 }
289 else
290 {
291 grid.AddGridObject(obj);
293 }
294
295 obj->m_isTempWorldObject = on;
296}
297
298template<class T>
300{
301 // Note: In case resurrectable corpse and pet its removed from global lists in own destructor
302 delete obj;
303}
304
305template<>
307{
309 RemoveUpdateObject(player);
310 delete player;
311}
312
313//Create NGrid so the object can be added to it
314//But object data is not loaded here
316{
317 if (!getNGrid(p.x_coord, p.y_coord))
318 {
319 TC_LOG_DEBUG("maps", "Creating grid[{}, {}] for map {} instance {}", p.x_coord, p.y_coord, GetId(), i_InstanceId);
320
322 setNGrid(ngrid, p.x_coord, p.y_coord);
323
324 // build a linkage between this map and NGridType
325 buildNGridLinkage(ngrid);
326
328
329 //z coord
330 int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord;
331 int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord;
332
333 m_terrain->LoadMapAndVMap(gx, gy);
334 }
335}
336
337//Load NGrid and make it active
339{
340 EnsureGridLoaded(cell);
341 NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
342 ASSERT(grid != nullptr);
343
344 if (object->IsPlayer())
345 GetMultiPersonalPhaseTracker().LoadGrid(object->GetPhaseShift(), *grid, this, cell);
346
347 // refresh grid state & timer
348 if (grid->GetGridState() != GRID_STATE_ACTIVE)
349 {
350 TC_LOG_DEBUG("maps", "Active object {} triggers loading of grid [{}, {}] on map {}", object->GetGUID().ToString(), cell.GridX(), cell.GridY(), GetId());
351 ResetGridExpiry(*grid, 0.1f);
353 }
354}
355
356//Create NGrid and load the object data in it
358{
359 EnsureGridCreated(GridCoord(cell.GridX(), cell.GridY()));
360 NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
361
362 ASSERT(grid != nullptr);
363 if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
364 {
365 TC_LOG_DEBUG("maps", "Loading grid[{}, {}] for map {} instance {}", cell.GridX(), cell.GridY(), GetId(), i_InstanceId);
366
367 setGridObjectDataLoaded(true, cell.GridX(), cell.GridY());
368
369 LoadGridObjects(grid, cell);
370
371 Balance();
372 return true;
373 }
374
375 return false;
376}
377
378void Map::LoadGridObjects(NGridType* grid, Cell const& cell)
379{
380 ObjectGridLoader loader(*grid, this, cell);
381 loader.LoadN();
382}
383
385{
386 // First make sure this grid is loaded
387 float gX = ((float(x) - 0.5f - CENTER_GRID_ID) * SIZE_OF_GRIDS) + (CENTER_GRID_OFFSET * 2);
388 float gY = ((float(y) - 0.5f - CENTER_GRID_ID) * SIZE_OF_GRIDS) + (CENTER_GRID_OFFSET * 2);
389 Cell cell = Cell(gX, gY);
390 EnsureGridLoaded(cell);
391
392 // Mark as don't unload
393 NGridType* grid = getNGrid(x, y);
394 grid->setUnloadExplicitLock(true);
395}
396
398{
399 // If grid is loaded, clear unload lock
400 if (IsGridLoaded(GridCoord(x, y)))
401 {
402 NGridType* grid = getNGrid(x, y);
403 grid->setUnloadExplicitLock(false);
404 }
405}
406
407void Map::LoadGrid(float x, float y)
408{
409 EnsureGridLoaded(Cell(x, y));
410}
411
412void Map::LoadGridForActiveObject(float x, float y, WorldObject const* object)
413{
415}
416
417bool Map::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
418{
419 CellCoord cellCoord = Trinity::ComputeCellCoord(player->GetPositionX(), player->GetPositionY());
420 if (!cellCoord.IsCoordValid())
421 {
422 TC_LOG_ERROR("maps", "Map::Add: Player {} has invalid coordinates X:{} Y:{} grid cell [{}:{}]", player->GetGUID().ToString(), player->GetPositionX(), player->GetPositionY(), cellCoord.x_coord, cellCoord.y_coord);
423 return false;
424 }
425
426 Cell cell(cellCoord);
428 AddToGrid(player, cell);
429
430 // Check if we are adding to correct map
431 ASSERT (player->GetMap() == this);
432 player->SetMap(this);
433 player->AddToWorld();
434
435 if (initPlayer)
436 SendInitSelf(player);
437
438 SendInitTransports(player);
439
440 if (initPlayer)
441 player->m_clientGUIDs.clear();
442
443 player->UpdateObjectVisibility(false);
445
446 if (Instanceable())
448
449 if (player->IsAlive())
450 ConvertCorpseToBones(player->GetGUID());
451
452 sScriptMgr->OnPlayerEnterMap(this, player);
453 return true;
454}
455
457{
458 Cell cell(player->GetPositionX(), player->GetPositionY());
459 GetMultiPersonalPhaseTracker().OnOwnerPhaseChanged(player, getNGrid(cell.GridX(), cell.GridY()), this, cell);
460}
461
463{
464 if (int32 const* value = Trinity::Containers::MapGetValuePtr(_worldStateValues, worldStateId))
465 return *value;
466
467 return 0;
468}
469
470void Map::SetWorldStateValue(int32 worldStateId, int32 value, bool hidden)
471{
472 auto [itr, inserted] = _worldStateValues.try_emplace(worldStateId, 0);
473 int32 oldValue = itr->second;
474 if (oldValue == value && !inserted)
475 return;
476
477 itr->second = value;
478
479 WorldStateTemplate const* worldStateTemplate = sWorldStateMgr->GetWorldStateTemplate(worldStateId);
480 if (worldStateTemplate)
481 sScriptMgr->OnWorldStateValueChange(worldStateTemplate, oldValue, value, this);
482
483 // Broadcast update to all players on the map
485 updateWorldState.VariableID = worldStateId;
486 updateWorldState.Value = value;
487 updateWorldState.Hidden = hidden;
488 updateWorldState.Write();
489
490 for (MapReference const& mapReference : m_mapRefManager)
491 {
492 if (worldStateTemplate && !worldStateTemplate->AreaIds.empty())
493 {
494 bool isInAllowedArea = std::any_of(worldStateTemplate->AreaIds.begin(), worldStateTemplate->AreaIds.end(),
495 [playerAreaId = mapReference.GetSource()->GetAreaId()](uint32 requiredAreaId) { return DB2Manager::IsInArea(playerAreaId, requiredAreaId); });
496 if (!isInAllowedArea)
497 continue;
498 }
499
500 mapReference.GetSource()->SendDirectMessage(updateWorldState.GetRawPacket());
501 }
502}
503
505{
506 _infiniteAOIVignettes.push_back(vignette);
507
509 vignette->FillPacket(vignetteUpdate.Added);
510 vignetteUpdate.Write();
511
512 for (MapReference const& ref : m_mapRefManager)
513 if (Vignettes::CanSee(ref.GetSource(), *vignette))
514 ref.GetSource()->SendDirectMessage(vignetteUpdate.GetRawPacket());
515}
516
518{
519 if (!std::erase(_infiniteAOIVignettes, vignette))
520 return;
521
523 vignetteUpdate.Removed.push_back(vignette->Guid);
524 vignetteUpdate.Write();
525
526 if (vignette->Data->GetFlags().HasFlag(VignetteFlags::ZoneInfiniteAOI))
527 {
528 for (MapReference const& ref : m_mapRefManager)
529 if (ref.GetSource()->GetZoneId() == vignette->ZoneID)
530 ref.GetSource()->SendDirectMessage(vignetteUpdate.GetRawPacket());
531 }
532 else
533 SendToPlayers(vignetteUpdate.GetRawPacket());
534}
535
536template<class T>
537void Map::InitializeObject(T* /*obj*/) { }
538
539template<>
541{
543}
544
545template<>
547{
549}
550
551template<class T>
552bool Map::AddToMap(T* obj)
553{
555 if (obj->IsInWorld())
556 {
557 ASSERT(obj->IsInGrid());
558 obj->UpdateObjectVisibility(true);
559 return true;
560 }
561
562 CellCoord cellCoord = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
563 //It will create many problems (including crashes) if an object is not added to grid after creation
564 //The correct way to fix it is to make AddToMap return false and delete the object if it is not added to grid
565 //But now AddToMap is used in too many places, I will just see how many ASSERT failures it will cause
566 ASSERT(cellCoord.IsCoordValid());
567 if (!cellCoord.IsCoordValid())
568 {
569 TC_LOG_ERROR("maps", "Map::Add: Object {} has invalid coordinates X:{} Y:{} grid cell [{}:{}]", obj->GetGUID().ToString(), obj->GetPositionX(), obj->GetPositionY(), cellCoord.x_coord, cellCoord.y_coord);
570 return false; //Should delete object
571 }
572
573 if (IsAlwaysActive())
574 obj->setActive(true);
575
576 Cell cell(cellCoord);
577 if (obj->isActiveObject())
579 else
580 EnsureGridCreated(GridCoord(cell.GridX(), cell.GridY()));
581 AddToGrid(obj, cell);
582 TC_LOG_DEBUG("maps", "Object {} enters grid[{}, {}]", obj->GetGUID().ToString(), cell.GridX(), cell.GridY());
583
584 //Must already be set before AddToMap. Usually during obj->Create.
585 //obj->SetMap(this);
586 obj->AddToWorld();
587
588 InitializeObject(obj);
589
590 if (obj->isActiveObject())
591 AddToActive(obj);
592
593 //something, such as vehicle, needs to be update immediately
594 //also, trigger needs to cast spell, if not update, cannot see visual
595 obj->SetIsNewObject(true);
596 obj->UpdateObjectVisibilityOnCreate();
597 obj->SetIsNewObject(false);
598 return true;
599}
600
601template<>
603{
604 //TODO: Needs clean up. An object should not be added to map twice.
605 if (obj->IsInWorld())
606 return true;
607
609 if (!cellCoord.IsCoordValid())
610 {
611 TC_LOG_ERROR("maps", "Map::Add: Object {} has invalid coordinates X:{} Y:{} grid cell [{}:{}]", obj->GetGUID().ToString(), obj->GetPositionX(), obj->GetPositionY(), cellCoord.x_coord, cellCoord.y_coord);
612 return false; //Should delete object
613 }
614
615 _transports.insert(obj);
616
617 if (obj->GetExpectedMapId() == GetId())
618 {
619 obj->AddToWorld();
620
621 // Broadcast creation to players
622 for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
623 {
624 if (itr->GetSource()->GetTransport() != obj && itr->GetSource()->InSamePhase(obj))
625 {
626 UpdateData data(GetId());
627 obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
628 itr->GetSource()->m_visibleTransports.insert(obj->GetGUID());
629 WorldPacket packet;
630 data.BuildPacket(&packet);
631 itr->GetSource()->SendDirectMessage(&packet);
632 }
633 }
634 }
635
636 return true;
637}
638
639bool Map::IsGridLoaded(GridCoord const& p) const
640{
642}
643
645{
646 // Check for valid position
647 if (!obj->IsPositionValid())
648 return;
649
650 // Update mobs/objects in ALL visible cells around object!
652
653 for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
654 {
655 for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
656 {
657 // marked cells are those that have been visited
658 // don't visit the same cell twice
659 uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
660 if (isCellMarked(cell_id))
661 continue;
662
663 markCell(cell_id);
664 CellCoord pair(x, y);
665 Cell cell(pair);
666 cell.SetNoCreate();
667 Visit(cell, gridVisitor);
668 Visit(cell, worldVisitor);
669 }
670 }
671}
672
674{
675 // Nothing to do if no change
676 if (oldZone == newZone)
677 return;
678
679 if (oldZone != MAP_INVALID_ZONE)
680 {
681 uint32& oldZoneCount = _zonePlayerCountMap[oldZone];
682 ASSERT(oldZoneCount, "A player left zone %u (went to %u) - but there were no players in the zone!", oldZone, newZone);
683 --oldZoneCount;
684 }
685 ++_zonePlayerCountMap[newZone];
686}
687
688void Map::Update(uint32 t_diff)
689{
690 _dynamicTree.update(t_diff);
693 {
694 Player* player = m_mapRefIter->GetSource();
695 if (player && player->IsInWorld())
696 {
697 //player->Update(t_diff);
698 WorldSession* session = player->GetSession();
699 MapSessionFilter updater(session);
700 session->Update(t_diff, updater);
701 }
702 }
703
705 if (_respawnCheckTimer <= t_diff)
706 {
710 }
711 else
712 _respawnCheckTimer -= t_diff;
713
716
717 Trinity::ObjectUpdater updater(t_diff);
718 // for creature
720 // for pets
722
723 // the player iterator is stored in the map object
724 // to make sure calls to Map::Remove don't invalidate it
726 {
727 Player* player = m_mapRefIter->GetSource();
728
729 if (!player || !player->IsInWorld())
730 continue;
731
732 // update players at tick
733 player->Update(t_diff);
734
735 VisitNearbyCellsOf(player, grid_object_update, world_object_update);
736
737 // If player is using far sight or mind vision, visit that object too
738 if (WorldObject* viewPoint = player->GetViewpoint())
739 VisitNearbyCellsOf(viewPoint, grid_object_update, world_object_update);
740
741 // Handle updates for creatures in combat with player and are more than 60 yards away
742 if (player->IsInCombat())
743 {
744 std::vector<Unit*> toVisit;
745 for (auto const& pair : player->GetCombatManager().GetPvECombatRefs())
746 if (Creature* unit = pair.second->GetOther(player)->ToCreature())
747 if (unit->GetMapId() == player->GetMapId() && !unit->IsWithinDistInMap(player, GetVisibilityRange(), false))
748 toVisit.push_back(unit);
749 for (Unit* unit : toVisit)
750 VisitNearbyCellsOf(unit, grid_object_update, world_object_update);
751 }
752
753 { // Update any creatures that own auras the player has applications of
754 std::unordered_set<Unit*> toVisit;
755 for (std::pair<uint32, AuraApplication*> pair : player->GetAppliedAuras())
756 {
757 if (Unit* caster = pair.second->GetBase()->GetCaster())
758 if (caster->GetTypeId() != TYPEID_PLAYER && !caster->IsWithinDistInMap(player, GetVisibilityRange(), false))
759 toVisit.insert(caster);
760 }
761 for (Unit* unit : toVisit)
762 VisitNearbyCellsOf(unit, grid_object_update, world_object_update);
763 }
764
765 { // Update player's summons
766 std::vector<Unit*> toVisit;
767
768 // Totems
769 for (ObjectGuid const& summonGuid : player->m_SummonSlot)
770 if (!summonGuid.IsEmpty())
771 if (Creature* unit = GetCreature(summonGuid))
772 if (unit->GetMapId() == player->GetMapId() && !unit->IsWithinDistInMap(player, GetVisibilityRange(), false))
773 toVisit.push_back(unit);
774
775 for (Unit* unit : toVisit)
776 VisitNearbyCellsOf(unit, grid_object_update, world_object_update);
777 }
778 }
779
780 // non-player active objects, increasing iterator in the loop in case of object removal
782 {
785
786 if (!obj || !obj->IsInWorld())
787 continue;
788
789 VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
790 }
791
793 {
796 obj->Update(t_diff);
797 }
798
799 if (_vignetteUpdateTimer.Update(t_diff))
800 {
802 {
803 if (vignette->NeedUpdate)
804 {
806 vignette->FillPacket(vignetteUpdate.Updated);
807 vignetteUpdate.Write();
808 for (MapReference const& ref : m_mapRefManager)
809 if (Vignettes::CanSee(ref.GetSource(), *vignette))
810 ref.GetSource()->SendDirectMessage(vignetteUpdate.GetRawPacket());
811
812 vignette->NeedUpdate = false;
813 }
814 }
815 }
816
818
820 if (!m_scriptSchedule.empty())
821 {
822 i_scriptLock = true;
824 i_scriptLock = false;
825 }
826
829 {
830 for (auto&& zoneInfo : _zoneDynamicInfo)
831 if (zoneInfo.second.DefaultWeather && !zoneInfo.second.DefaultWeather->Update(_weatherUpdateTimer.GetInterval()))
832 zoneInfo.second.DefaultWeather.reset();
833
835 }
836
837 // update phase shift objects
838 GetMultiPersonalPhaseTracker().Update(this, t_diff);
839
843
844 if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty())
846
847 sScriptMgr->OnMapUpdate(this, t_diff);
848
849 TC_METRIC_VALUE("map_creatures", uint64(GetObjectsStore().Size<Creature>()),
850 TC_METRIC_TAG("map_id", std::to_string(GetId())),
851 TC_METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
852
853 TC_METRIC_VALUE("map_gameobjects", uint64(GetObjectsStore().Size<GameObject>()),
854 TC_METRIC_TAG("map_id", std::to_string(GetId())),
855 TC_METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
856}
857
859{
860 template<class T>inline void resetNotify(GridRefManager<T> &m)
861 {
862 for (typename GridRefManager<T>::iterator iter=m.begin(); iter != m.end(); ++iter)
863 iter->GetSource()->ResetAllNotifies();
864 }
865 template<class T> void Visit(GridRefManager<T> &) { }
866 void Visit(CreatureMapType &m) { resetNotify<Creature>(m);}
867 void Visit(PlayerMapType &m) { resetNotify<Player>(m);}
868};
869
871{
873 {
874 NGridType *grid = i->GetSource();
875
876 if (grid->GetGridState() != GRID_STATE_ACTIVE)
877 continue;
878
880 if (!grid->getGridInfoRef()->getRelocationTimer().TPassed())
881 continue;
882
883 uint32 gx = grid->getX(), gy = grid->getY();
884
886 CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
887
888 for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x)
889 {
890 for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y)
891 {
892 uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
893 if (!isCellMarked(cell_id))
894 continue;
895
896 CellCoord pair(x, y);
897 Cell cell(pair);
898 cell.SetNoCreate();
899
900 Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, MAX_VISIBILITY_DISTANCE);
903 Visit(cell, grid_object_relocation);
904 Visit(cell, world_object_relocation);
905 }
906 }
907 }
908
909 ResetNotifier reset;
913 {
914 NGridType *grid = i->GetSource();
915
916 if (grid->GetGridState() != GRID_STATE_ACTIVE)
917 continue;
918
919 if (!grid->getGridInfoRef()->getRelocationTimer().TPassed())
920 continue;
921
923
924 uint32 gx = grid->getX(), gy = grid->getY();
925
927 CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
928
929 for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x)
930 {
931 for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y)
932 {
933 uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
934 if (!isCellMarked(cell_id))
935 continue;
936
937 CellCoord pair(x, y);
938 Cell cell(pair);
939 cell.SetNoCreate();
940 Visit(cell, grid_notifier);
941 Visit(cell, world_notifier);
942 }
943 }
944 }
945}
946
947void Map::RemovePlayerFromMap(Player* player, bool remove)
948{
949 // Before leaving map, update zone/area for stats
950 player->UpdateZone(MAP_INVALID_ZONE, 0);
951 sScriptMgr->OnPlayerLeaveMap(this, player);
952
954
955 player->CombatStop();
956
957 bool const inWorld = player->IsInWorld();
958 player->RemoveFromWorld();
959 SendRemoveTransports(player);
960
961 if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers()
963
964 if (player->IsInGrid())
965 player->RemoveFromGrid();
966 else
967 ASSERT(remove); //maybe deleted in logoutplayer when player is not in a map
968
969 if (remove)
970 DeleteFromWorld(player);
971}
972
973template<class T>
974void Map::RemoveFromMap(T *obj, bool remove)
975{
976 bool const inWorld = obj->IsInWorld() && obj->GetTypeId() >= TYPEID_UNIT && obj->GetTypeId() <= TYPEID_GAMEOBJECT;
977 obj->RemoveFromWorld();
978 if (obj->isActiveObject())
979 RemoveFromActive(obj);
980
982
983 if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers()
984 obj->UpdateObjectVisibilityOnDestroy();
985
986 obj->RemoveFromGrid();
987
988 obj->ResetMap();
989
990 if (remove)
991 DeleteFromWorld(obj);
992}
993
994template<>
995void Map::RemoveFromMap(Transport* obj, bool remove)
996{
997 if (obj->IsInWorld())
998 {
999 obj->RemoveFromWorld();
1000
1001 UpdateData data(GetId());
1002 if (obj->IsDestroyedObject())
1003 obj->BuildDestroyUpdateBlock(&data);
1004 else
1005 obj->BuildOutOfRangeUpdateBlock(&data);
1006
1007 WorldPacket packet;
1008 data.BuildPacket(&packet);
1009 for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
1010 {
1011 if (itr->GetSource()->GetTransport() != obj && itr->GetSource()->m_visibleTransports.count(obj->GetGUID()))
1012 {
1013 itr->GetSource()->SendDirectMessage(&packet);
1014 itr->GetSource()->m_visibleTransports.erase(obj->GetGUID());
1015 }
1016 }
1017 }
1018
1020 {
1021 TransportsContainer::iterator itr = _transports.find(obj);
1022 if (itr == _transports.end())
1023 return;
1024 if (itr == _transportsUpdateIter)
1026 _transports.erase(itr);
1027 }
1028 else
1029 _transports.erase(obj);
1030
1031 obj->ResetMap();
1032
1033 if (remove)
1034 DeleteFromWorld(obj);
1035}
1036
1037template <typename T>
1038/*static*/ bool Map::CheckGridIntegrity(T* object, bool moved, char const* objType)
1039{
1040 Cell const& cur_cell = object->GetCurrentCell();
1041 Cell xy_cell(object->GetPositionX(), object->GetPositionY());
1042 if (xy_cell != cur_cell)
1043 {
1044 TC_LOG_DEBUG("maps", "{} {} X: {} Y: {} ({}) is in grid[{}, {}]cell[{}, {}] instead of grid[{}, {}]cell[{}, {}]",
1045 objType, object->GetGUID().ToString(),
1046 object->GetPositionX(), object->GetPositionY(), (moved ? "final" : "original"),
1047 cur_cell.GridX(), cur_cell.GridY(), cur_cell.CellX(), cur_cell.CellY(),
1048 xy_cell.GridX(), xy_cell.GridY(), xy_cell.CellX(), xy_cell.CellY());
1049 return true; // not crash at error, just output error in debug mode
1050 }
1051
1052 return true;
1053}
1054
1055void Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation)
1056{
1057 ASSERT(player);
1058
1059 Cell old_cell(player->GetPositionX(), player->GetPositionY());
1060 Cell new_cell(x, y);
1061
1062 player->Relocate(x, y, z, orientation);
1063 if (player->IsVehicle())
1064 player->GetVehicleKit()->RelocatePassengers();
1065
1066 if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell))
1067 {
1068 TC_LOG_DEBUG("maps", "Player {} relocation grid[{}, {}]cell[{}, {}]->grid[{}, {}]cell[{}, {}]", player->GetName(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1069
1070 player->RemoveFromGrid();
1071
1072 if (old_cell.DiffGrid(new_cell))
1073 EnsureGridLoadedForActiveObject(new_cell, player);
1074
1075 AddToGrid(player, new_cell);
1076 }
1077
1078 player->UpdatePositionData();
1079 player->UpdateObjectVisibility(false);
1080}
1081
1082void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float ang, bool respawnRelocationOnFail)
1083{
1084 ASSERT(CheckGridIntegrity(creature, false, "Creature"));
1085
1086 Cell new_cell(x, y);
1087
1088 if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
1089 return;
1090
1091 Cell old_cell = creature->GetCurrentCell();
1092 // delay creature move for grid/cell to grid/cell moves
1093 if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
1094 {
1095#ifdef TRINITY_DEBUG
1096 TC_LOG_DEBUG("maps", "Creature {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", creature->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1097#endif
1098 AddCreatureToMoveList(creature, x, y, z, ang);
1099 // in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList
1100 }
1101 else
1102 {
1103 creature->Relocate(x, y, z, ang);
1104 if (creature->IsVehicle())
1105 creature->GetVehicleKit()->RelocatePassengers();
1106 creature->UpdateObjectVisibility(false);
1107 creature->UpdatePositionData();
1109 }
1110
1111 ASSERT(CheckGridIntegrity(creature, true, "Creature"));
1112}
1113
1114void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail)
1115{
1116 ASSERT(CheckGridIntegrity(go, false, "GameObject"));
1117 Cell new_cell(x, y);
1118
1119 if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
1120 return;
1121
1122 Cell old_cell = go->GetCurrentCell();
1123
1124 // delay creature move for grid/cell to grid/cell moves
1125 if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
1126 {
1127#ifdef TRINITY_DEBUG
1128 TC_LOG_DEBUG("maps", "GameObject {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1129#endif
1130 AddGameObjectToMoveList(go, x, y, z, orientation);
1131 // in diffcell/diffgrid case notifiers called at finishing move go in Map::MoveAllGameObjectsInMoveList
1132 }
1133 else
1134 {
1135 go->Relocate(x, y, z, orientation);
1136 go->AfterRelocation();
1138 }
1139
1140 ASSERT(CheckGridIntegrity(go, true, "GameObject"));
1141}
1142
1143void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float z, float orientation)
1144{
1145 ASSERT(CheckGridIntegrity(dynObj, false, "DynamicObject"));
1146 Cell new_cell(x, y);
1147
1148 if (!getNGrid(new_cell.GridX(), new_cell.GridY()))
1149 return;
1150
1151 Cell old_cell = dynObj->GetCurrentCell();
1152
1153 // delay creature move for grid/cell to grid/cell moves
1154 if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
1155 {
1156#ifdef TRINITY_DEBUG
1157 TC_LOG_DEBUG("maps", "GameObject {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", dynObj->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1158#endif
1159 AddDynamicObjectToMoveList(dynObj, x, y, z, orientation);
1160 // in diffcell/diffgrid case notifiers called at finishing move dynObj in Map::MoveAllGameObjectsInMoveList
1161 }
1162 else
1163 {
1164 dynObj->Relocate(x, y, z, orientation);
1165 dynObj->UpdatePositionData();
1166 dynObj->UpdateObjectVisibility(false);
1168 }
1169
1170 ASSERT(CheckGridIntegrity(dynObj, true, "DynamicObject"));
1171}
1172
1173void Map::AreaTriggerRelocation(AreaTrigger* at, float x, float y, float z, float orientation)
1174{
1175 ASSERT(CheckGridIntegrity(at, false, "AreaTrigger"));
1176 Cell new_cell(x, y);
1177
1178 if (!getNGrid(new_cell.GridX(), new_cell.GridY()))
1179 return;
1180
1181 Cell old_cell = at->GetCurrentCell();
1182
1183 // delay areatrigger move for grid/cell to grid/cell moves
1184 if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
1185 {
1186#ifdef TRINITY_DEBUG
1187 TC_LOG_DEBUG("maps", "AreaTrigger ({}) added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", at->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1188#endif
1189 AddAreaTriggerToMoveList(at, x, y, z, orientation);
1190 // in diffcell/diffgrid case notifiers called at finishing move at in Map::MoveAllAreaTriggersInMoveList
1191 }
1192 else
1193 {
1194 at->Relocate(x, y, z, orientation);
1195 at->UpdateShape();
1196 at->UpdateObjectVisibility(false);
1198 }
1199
1200 ASSERT(CheckGridIntegrity(at, true, "AreaTrigger"));
1201}
1202
1203void Map::AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang)
1204{
1205 if (_creatureToMoveLock) //can this happen?
1206 return;
1207
1209 _creaturesToMove.push_back(c);
1210 c->SetNewCellPosition(x, y, z, ang);
1211}
1212
1214{
1215 if (_creatureToMoveLock) //can this happen?
1216 return;
1217
1220}
1221
1222void Map::AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang)
1223{
1224 if (_gameObjectsToMoveLock) //can this happen?
1225 return;
1226
1228 _gameObjectsToMove.push_back(go);
1229 go->SetNewCellPosition(x, y, z, ang);
1230}
1231
1233{
1234 if (_gameObjectsToMoveLock) //can this happen?
1235 return;
1236
1239}
1240
1241void Map::AddDynamicObjectToMoveList(DynamicObject* dynObj, float x, float y, float z, float ang)
1242{
1243 if (_dynamicObjectsToMoveLock) //can this happen?
1244 return;
1245
1247 _dynamicObjectsToMove.push_back(dynObj);
1248 dynObj->SetNewCellPosition(x, y, z, ang);
1249}
1250
1252{
1253 if (_dynamicObjectsToMoveLock) //can this happen?
1254 return;
1255
1258}
1259
1260void Map::AddAreaTriggerToMoveList(AreaTrigger* at, float x, float y, float z, float ang)
1261{
1262 if (_areaTriggersToMoveLock) //can this happen?
1263 return;
1264
1266 _areaTriggersToMove.push_back(at);
1267 at->SetNewCellPosition(x, y, z, ang);
1268}
1269
1271{
1272 if (_areaTriggersToMoveLock) //can this happen?
1273 return;
1274
1277}
1278
1280{
1281 _creatureToMoveLock = true;
1282 for (std::vector<Creature*>::iterator itr = _creaturesToMove.begin(); itr != _creaturesToMove.end(); ++itr)
1283 {
1284 Creature* c = *itr;
1285 if (c->FindMap() != this) //pet is teleported to another map
1286 continue;
1287
1289 {
1291 continue;
1292 }
1293
1295 if (!c->IsInWorld())
1296 continue;
1297
1298 // do move or do move to respawn or remove creature if previous all fail
1300 {
1301 // update pos
1302 c->Relocate(c->_newPosition);
1303 if (c->IsVehicle())
1305 //CreatureRelocationNotify(c, new_cell, new_cell.cellCoord());
1306 c->UpdatePositionData();
1307 c->UpdateObjectVisibility(false);
1308 }
1309 else
1310 {
1311 // if creature can't be move in new cell/grid (not loaded) move it to repawn cell/grid
1312 // creature coordinates will be updated and notifiers send
1313 if (!CreatureRespawnRelocation(c, false))
1314 {
1315 // ... or unload (if respawn grid also not loaded)
1316#ifdef TRINITY_DEBUG
1317 TC_LOG_DEBUG("maps", "Creature {} cannot be move to unloaded respawn grid.", c->GetGUID().ToString());
1318#endif
1319 //AddObjectToRemoveList(Pet*) should only be called in Pet::Remove
1320 //This may happen when a player just logs in and a pet moves to a nearby unloaded cell
1321 //To avoid this, we can load nearby cells when player log in
1322 //But this check is always needed to ensure safety
1324 //need to check why pet is frequently relocated to an unloaded cell
1325 if (c->IsPet())
1326 ((Pet*)c)->Remove(PET_SAVE_NOT_IN_SLOT, true);
1327 else
1329 }
1330 }
1331 }
1332 _creaturesToMove.clear();
1333 _creatureToMoveLock = false;
1334}
1335
1337{
1339 for (std::vector<GameObject*>::iterator itr = _gameObjectsToMove.begin(); itr != _gameObjectsToMove.end(); ++itr)
1340 {
1341 GameObject* go = *itr;
1342 if (go->FindMap() != this) //transport is teleported to another map
1343 continue;
1344
1346 {
1348 continue;
1349 }
1350
1352 if (!go->IsInWorld())
1353 continue;
1354
1355 // do move or do move to respawn or remove creature if previous all fail
1357 {
1358 // update pos
1359 go->Relocate(go->_newPosition);
1360 go->AfterRelocation();
1361 }
1362 else
1363 {
1364 // if GameObject can't be move in new cell/grid (not loaded) move it to repawn cell/grid
1365 // GameObject coordinates will be updated and notifiers send
1366 if (!GameObjectRespawnRelocation(go, false))
1367 {
1368 // ... or unload (if respawn grid also not loaded)
1369#ifdef TRINITY_DEBUG
1370 TC_LOG_DEBUG("maps", "GameObject {} cannot be move to unloaded respawn grid.", go->GetGUID().ToString());
1371#endif
1373 }
1374 }
1375 }
1376 _gameObjectsToMove.clear();
1377 _gameObjectsToMoveLock = false;
1378}
1379
1381{
1383 for (std::vector<DynamicObject*>::iterator itr = _dynamicObjectsToMove.begin(); itr != _dynamicObjectsToMove.end(); ++itr)
1384 {
1385 DynamicObject* dynObj = *itr;
1386 if (dynObj->FindMap() != this) //transport is teleported to another map
1387 continue;
1388
1390 {
1392 continue;
1393 }
1394
1396 if (!dynObj->IsInWorld())
1397 continue;
1398
1399 // do move or do move to respawn or remove creature if previous all fail
1401 {
1402 // update pos
1403 dynObj->Relocate(dynObj->_newPosition);
1404 dynObj->UpdatePositionData();
1405 dynObj->UpdateObjectVisibility(false);
1406 }
1407 else
1408 {
1409#ifdef TRINITY_DEBUG
1410 TC_LOG_DEBUG("maps", "DynamicObject {} cannot be moved to unloaded grid.", dynObj->GetGUID().ToString());
1411#endif
1412 }
1413 }
1414
1415 _dynamicObjectsToMove.clear();
1417}
1418
1420{
1422 for (std::vector<AreaTrigger*>::iterator itr = _areaTriggersToMove.begin(); itr != _areaTriggersToMove.end(); ++itr)
1423 {
1424 AreaTrigger* at = *itr;
1425 if (at->FindMap() != this) //transport is teleported to another map
1426 continue;
1427
1429 {
1431 continue;
1432 }
1433
1435 if (!at->IsInWorld())
1436 continue;
1437
1438 // do move or do move to respawn or remove creature if previous all fail
1440 {
1441 // update pos
1442 at->Relocate(at->_newPosition);
1443 at->UpdateShape();
1444 at->UpdateObjectVisibility(false);
1445 }
1446 else
1447 {
1448#ifdef TRINITY_DEBUG
1449 TC_LOG_DEBUG("maps", "AreaTrigger {} cannot be moved to unloaded grid.", at->GetGUID().ToString());
1450#endif
1451 }
1452 }
1453
1454 _areaTriggersToMove.clear();
1456}
1457
1458template <typename T>
1459bool Map::MapObjectCellRelocation(T* object, Cell new_cell, [[maybe_unused]] char const* objType)
1460{
1461 Cell const& old_cell = object->GetCurrentCell();
1462 if (!old_cell.DiffGrid(new_cell)) // in same grid
1463 {
1464 // if in same cell then none do
1465 if (old_cell.DiffCell(new_cell))
1466 {
1467#ifdef TRINITY_DEBUG
1468 TC_LOG_DEBUG("maps", "{} {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", objType, object->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY());
1469#endif
1470
1471 object->RemoveFromGrid();
1472 AddToGrid(object, new_cell);
1473 }
1474 else
1475 {
1476#ifdef TRINITY_DEBUG
1477 TC_LOG_DEBUG("maps", "{} {} moved in same grid[{}, {}]cell[{}, {}].", objType, object->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
1478#endif
1479 }
1480
1481 return true;
1482 }
1483
1484 // in diff. grids but active creature
1485 if (object->isActiveObject())
1486 {
1487 EnsureGridLoadedForActiveObject(new_cell, object);
1488
1489#ifdef TRINITY_DEBUG
1490 TC_LOG_DEBUG("maps", "Active {} {} moved from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", objType, object->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1491#endif
1492
1493 object->RemoveFromGrid();
1494 AddToGrid(object, new_cell);
1495
1496 return true;
1497 }
1498
1499 if (Creature* c = object->ToCreature())
1500 if (c->GetCharmerOrOwnerGUID().IsPlayer())
1501 EnsureGridLoaded(new_cell);
1502
1503 // in diff. loaded grid normal object
1504 if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY())))
1505 {
1506#ifdef TRINITY_DEBUG
1507 TC_LOG_DEBUG("maps", "{} {} moved from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", objType, object->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1508#endif
1509
1510 object->RemoveFromGrid();
1511 EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY()));
1512 AddToGrid(object, new_cell);
1513
1514 return true;
1515 }
1516
1517 // fail to move: normal object attempt move to unloaded grid
1518#ifdef TRINITY_DEBUG
1519 TC_LOG_DEBUG("maps", "{} {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded grid[{}, {}]cell[{}, {}].", objType, object->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
1520#endif
1521 return false;
1522}
1523
1525{
1526 return MapObjectCellRelocation(c, new_cell, "Creature");
1527}
1528
1530{
1531 return MapObjectCellRelocation(go, new_cell, "GameObject");
1532}
1533
1535{
1536 return MapObjectCellRelocation(go, new_cell, "DynamicObject");
1537}
1538
1540{
1541 return MapObjectCellRelocation(at, new_cell, "AreaTrigger");
1542}
1543
1544bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
1545{
1546 float resp_x, resp_y, resp_z, resp_o;
1547 c->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o);
1548 Cell resp_cell(resp_x, resp_y);
1549
1550 //creature will be unloaded with grid
1551 if (diffGridOnly && !c->GetCurrentCell().DiffGrid(resp_cell))
1552 return true;
1553
1554 c->CombatStop();
1555 c->GetMotionMaster()->Clear();
1556
1557#ifdef TRINITY_DEBUG
1558 TC_LOG_DEBUG("maps", "Creature {} moved from grid[{}, {}]cell[{}, {}] to respawn grid[{}, {}]cell[{}, {}].", c->GetGUID().ToString(), c->GetCurrentCell().GridX(), c->GetCurrentCell().GridY(), c->GetCurrentCell().CellX(), c->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY());
1559#endif
1560
1561 // teleport it to respawn point (like normal respawn if player see)
1562 if (CreatureCellRelocation(c, resp_cell))
1563 {
1564 c->Relocate(resp_x, resp_y, resp_z, resp_o);
1565 c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators
1566 //CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord());
1567 c->UpdatePositionData();
1568 c->UpdateObjectVisibility(false);
1569 return true;
1570 }
1571
1572 return false;
1573}
1574
1576{
1577 float resp_x, resp_y, resp_z, resp_o;
1578 go->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o);
1579 Cell resp_cell(resp_x, resp_y);
1580
1581 //GameObject will be unloaded with grid
1582 if (diffGridOnly && !go->GetCurrentCell().DiffGrid(resp_cell))
1583 return true;
1584
1585#ifdef TRINITY_DEBUG
1586 TC_LOG_DEBUG("maps", "GameObject {} moved from grid[{}, {}]cell[{}, {}] to respawn grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString(), go->GetCurrentCell().GridX(), go->GetCurrentCell().GridY(), go->GetCurrentCell().CellX(), go->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY());
1587#endif
1588
1589 // teleport it to respawn point (like normal respawn if player see)
1590 if (GameObjectCellRelocation(go, resp_cell))
1591 {
1592 go->Relocate(resp_x, resp_y, resp_z, resp_o);
1593 go->UpdatePositionData();
1594 go->UpdateObjectVisibility(false);
1595 return true;
1596 }
1597
1598 return false;
1599}
1600
1601bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
1602{
1603 const uint32 x = ngrid.getX();
1604 const uint32 y = ngrid.getY();
1605
1606 {
1607 if (!unloadAll)
1608 {
1609 //pets, possessed creatures (must be active), transport passengers
1611 return false;
1612
1613 if (ActiveObjectsNearGrid(ngrid))
1614 return false;
1615 }
1616
1617 TC_LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {}", x, y, GetId());
1618
1619 if (!unloadAll)
1620 {
1621 // Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids
1622 // Must know real mob position before move
1626
1627 // move creatures to respawn grids if this is diff.grid or to remove list
1628 ObjectGridEvacuator worker;
1630 ngrid.VisitAllGrids(visitor);
1631
1632 // Finish creature moves, remove and delete all creatures with delayed remove before unload
1636 }
1637
1638 {
1639 ObjectGridCleaner worker;
1641 ngrid.VisitAllGrids(visitor);
1642 }
1643
1645
1646 // After removing all objects from the map, purge empty tracked phases
1648
1649 {
1650 ObjectGridUnloader worker;
1652 ngrid.VisitAllGrids(visitor);
1653 }
1654
1655 ASSERT(i_objectsToRemove.empty());
1656
1657 delete &ngrid;
1658 setNGrid(nullptr, x, y);
1659 }
1660 int gx = (MAX_NUMBER_OF_GRIDS - 1) - x;
1661 int gy = (MAX_NUMBER_OF_GRIDS - 1) - y;
1662
1663 m_terrain->UnloadMap(gx, gy);
1664
1665 TC_LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {} finished", x, y, GetId());
1666 return true;
1667}
1668
1670{
1671 if (HavePlayers())
1672 {
1673 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
1674 {
1675 Player* player = itr->GetSource();
1676 if (!player->IsBeingTeleportedFar())
1677 {
1678 // this is happening for bg
1679 TC_LOG_ERROR("maps", "Map::UnloadAll: player {} is still in map {} during unload, this should not happen!", player->GetName(), GetId());
1680 player->TeleportTo(player->m_homebind);
1681 }
1682 }
1683 }
1684}
1685
1687{
1688 // clear all delayed moves, useless anyway do this moves before map unload.
1689 _creaturesToMove.clear();
1690 _gameObjectsToMove.clear();
1691
1693 {
1694 NGridType &grid(*i->GetSource());
1695 ++i;
1696 UnloadGrid(grid, true); // deletes the grid and removes it from the GridRefManager
1697 }
1698
1699 for (TransportsContainer::iterator itr = _transports.begin(); itr != _transports.end();)
1700 {
1701 Transport* transport = *itr;
1702 ++itr;
1703
1704 RemoveFromMap<Transport>(transport, true);
1705 }
1706
1707 for (auto& cellCorpsePair : _corpsesByCell)
1708 {
1709 for (Corpse* corpse : cellCorpsePair.second)
1710 {
1711 corpse->RemoveFromWorld();
1712 corpse->ResetMap();
1713 delete corpse;
1714 }
1715 }
1716
1717 _corpsesByCell.clear();
1718 _corpsesByPlayer.clear();
1719 _corpseBones.clear();
1720}
1721
1722void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data,
1723 Optional<map_liquidHeaderTypeFlags> reqLiquidType, float collisionHeight)
1724{
1725 m_terrain->GetFullTerrainStatusForPosition(phaseShift, GetId(), x, y, z, data, reqLiquidType, collisionHeight, &_dynamicTree);
1726}
1727
1728ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, Optional<map_liquidHeaderTypeFlags> ReqLiquidType, LiquidData* data,
1729 float collisionHeight)
1730{
1731 return m_terrain->GetLiquidStatus(phaseShift, GetId(), x, y, z, ReqLiquidType, data, collisionHeight);
1732}
1733
1734uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z)
1735{
1736 return m_terrain->GetAreaId(phaseShift, GetId(), x, y, z, &_dynamicTree);
1737}
1738
1739uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z)
1740{
1741 return m_terrain->GetZoneId(phaseShift, GetId(), x, y, z, &_dynamicTree);
1742}
1743
1744void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z)
1745{
1746 return m_terrain->GetZoneAndAreaId(phaseShift, GetId(), zoneid, areaid, x, y, z, &_dynamicTree);
1747}
1748
1749float Map::GetMinHeight(PhaseShift const& phaseShift, float x, float y)
1750{
1751 return m_terrain->GetMinHeight(phaseShift, GetId(), x, y);
1752}
1753
1754float Map::GetGridHeight(PhaseShift const& phaseShift, float x, float y)
1755{
1756 return m_terrain->GetGridHeight(phaseShift, GetId(), x, y);
1757}
1758
1759float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap, float maxSearchDist)
1760{
1761 return m_terrain->GetStaticHeight(phaseShift, GetId(), x, y, z, checkVMap, maxSearchDist);
1762}
1763
1764float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y)
1765{
1766 return m_terrain->GetWaterLevel(phaseShift, GetId(), x, y);
1767}
1768
1769bool Map::IsInWater(PhaseShift const& phaseShift, float x, float y, float z, LiquidData* data)
1770{
1771 return m_terrain->IsInWater(phaseShift, GetId(), x, y, z, data);
1772}
1773
1774bool Map::IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z)
1775{
1776 return m_terrain->IsUnderWater(phaseShift, GetId(), x, y, z);
1777}
1778
1779float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground, bool swim, float collisionHeight)
1780{
1781 return m_terrain->GetWaterOrGroundLevel(phaseShift, GetId(), x, y, z, ground, swim, collisionHeight, &_dynamicTree);
1782}
1783
1784bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
1785{
1786 if ((checks & LINEOFSIGHT_CHECK_VMAP)
1787 && !VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(phaseShift, GetId(), m_terrain.get(), x1, y1), x1, y1, z1, x2, y2, z2, ignoreFlags))
1788 return false;
1789 if (sWorld->getBoolConfig(CONFIG_CHECK_GOBJECT_LOS) && (checks & LINEOFSIGHT_CHECK_GOBJECT)
1790 && !_dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phaseShift))
1791 return false;
1792 return true;
1793}
1794
1795bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist)
1796{
1797 G3D::Vector3 startPos(x1, y1, z1);
1798 G3D::Vector3 dstPos(x2, y2, z2);
1799
1800 G3D::Vector3 resultPos;
1801 bool result = _dynamicTree.getObjectHitPos(startPos, dstPos, resultPos, modifyDist, phaseShift);
1802
1803 rx = resultPos.x;
1804 ry = resultPos.y;
1805 rz = resultPos.z;
1806 return result;
1807}
1808
1810{
1811 MapEntry const* entry = sMapStore.LookupEntry(mapid);
1812 if (!entry)
1814
1815 if (!entry->IsDungeon())
1816 return TRANSFER_ABORT_NONE;
1817
1818 Difficulty targetDifficulty = player->GetDifficultyID(entry);
1819 // Get the highest available difficulty if current setting is higher than the instance allows
1820 MapDifficultyEntry const* mapDiff = sDB2Manager.GetDownscaledMapDifficultyData(mapid, targetDifficulty);
1821 if (!mapDiff)
1823
1824 //Bypass checks for GMs
1825 if (player->IsGameMaster())
1826 return TRANSFER_ABORT_NONE;
1827
1828 //Other requirements
1829 {
1831 if (!player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, &params, true))
1832 return params;
1833 }
1834
1835 Group* group = player->GetGroup();
1836 if (entry->IsRaid() && entry->Expansion() >= sWorld->getIntConfig(CONFIG_EXPANSION)) // can only enter in a raid group but raids from old expansion don't need a group
1837 if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
1839
1840 if (entry->Instanceable())
1841 {
1842 //Get instance where player's group is bound & its map
1843 uint32 instanceIdToCheck = sMapMgr->FindInstanceIdForPlayer(mapid, player);
1844 if (Map* boundMap = sMapMgr->FindMap(mapid, instanceIdToCheck))
1845 if (TransferAbortParams denyReason = boundMap->CannotEnter(player))
1846 return denyReason;
1847
1848 // players are only allowed to enter 10 instances per hour
1849 if (!entry->GetFlags2().HasFlag(MapFlags2::IgnoreInstanceFarmLimit) && entry->IsDungeon() && !player->CheckInstanceCount(instanceIdToCheck) && !player->isDead())
1851 }
1852
1853 return TRANSFER_ABORT_NONE;
1854}
1855
1856char const* Map::GetMapName() const
1857{
1858 return i_mapEntry->MapName[sWorld->GetDefaultDbcLocale()];
1859}
1860
1862{
1863 TC_LOG_DEBUG("maps", "Creating player data for himself {}", player->GetGUID().ToString());
1864
1865 UpdateData data(player->GetMapId());
1866
1867 // attach to player data current transport data
1868 if (Transport* transport = dynamic_cast<Transport*>(player->GetTransport()))
1869 {
1870 transport->BuildCreateUpdateBlockForPlayer(&data, player);
1871 player->m_visibleTransports.insert(transport->GetGUID());
1872 }
1873
1874 // build data for self presence in world at own client (one time for map)
1875 player->BuildCreateUpdateBlockForPlayer(&data, player);
1876
1877 // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
1878 if (Transport* transport = dynamic_cast<Transport*>(player->GetTransport()))
1879 for (WorldObject* passenger : transport->GetPassengers())
1880 if (player != passenger && player->HaveAtClient(passenger))
1881 passenger->BuildCreateUpdateBlockForPlayer(&data, player);
1882
1883 WorldPacket packet;
1884 data.BuildPacket(&packet);
1885 player->SendDirectMessage(&packet);
1886}
1887
1889{
1890 // Hack to send out transports
1891 UpdateData transData(GetId());
1892 for (Transport* transport : _transports)
1893 {
1894 if (transport->IsInWorld() && transport != player->GetTransport() && player->InSamePhase(transport))
1895 {
1896 transport->BuildCreateUpdateBlockForPlayer(&transData, player);
1897 player->m_visibleTransports.insert(transport->GetGUID());
1898 }
1899 }
1900
1901 WorldPacket packet;
1902 transData.BuildPacket(&packet);
1903 player->SendDirectMessage(&packet);
1904}
1905
1907{
1908 // Hack to send out transports
1909 UpdateData transData(player->GetMapId());
1910 for (Transport* transport : _transports)
1911 {
1912 if (player->m_visibleTransports.count(transport->GetGUID()) && transport != player->GetTransport())
1913 {
1914 transport->BuildOutOfRangeUpdateBlock(&transData);
1915 player->m_visibleTransports.erase(transport->GetGUID());
1916 }
1917 }
1918
1919 WorldPacket packet;
1920 transData.BuildPacket(&packet);
1921 player->SendDirectMessage(&packet);
1922}
1923
1925{
1926 // Hack to send out transports
1927 UpdateData transData(player->GetMapId());
1928 for (Transport* transport : _transports)
1929 {
1930 if (!transport->IsInWorld())
1931 continue;
1932
1933 auto transportItr = player->m_visibleTransports.find(transport->GetGUID());
1934 if (player->InSamePhase(transport))
1935 {
1936 if (transportItr == player->m_visibleTransports.end())
1937 {
1938 transport->BuildCreateUpdateBlockForPlayer(&transData, player);
1939 player->m_visibleTransports.insert(transport->GetGUID());
1940 }
1941 }
1942 else if (transportItr != player->m_visibleTransports.end())
1943 {
1944 transport->BuildOutOfRangeUpdateBlock(&transData);
1945 player->m_visibleTransports.erase(transportItr);
1946 }
1947 }
1948
1949 WorldPacket packet;
1950 transData.BuildPacket(&packet);
1951 player->GetSession()->SendPacket(&packet);
1952}
1953
1954inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y)
1955{
1957 {
1958 TC_LOG_ERROR("maps", "map::setNGrid() Invalid grid coordinates found: {}, {}!", x, y);
1959 ABORT();
1960 }
1961 i_grids[x][y] = grid;
1962}
1963
1965{
1966 UpdateDataMapType update_players;
1967
1968 while (!_updateObjects.empty())
1969 {
1970 Object* obj = *_updateObjects.begin();
1971 ASSERT(obj->IsInWorld());
1972 _updateObjects.erase(_updateObjects.begin());
1973 obj->BuildUpdate(update_players);
1974 }
1975
1976 WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
1977 for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
1978 {
1979 iter->second.BuildPacket(&packet);
1980 iter->first->SendDirectMessage(&packet);
1981 packet.clear(); // clean the string
1982 }
1983}
1984
1985// CheckRespawn MUST do one of the following:
1986// -) return true
1987// -) set info->respawnTime to zero, which indicates the respawn time should be deleted (and will never be processed again without outside intervention)
1988// -) set info->respawnTime to a new respawn time, which must be strictly GREATER than the current time (GameTime::GetGameTime())
1990{
1991 SpawnData const* data = sObjectMgr->GetSpawnData(info->type, info->spawnId);
1992 ASSERT(data, "Invalid respawn info with type %u, spawnID " UI64FMTD " in respawn queue.", info->type, info->spawnId);
1993
1994 // First, check if this creature's spawn group is inactive
1996 {
1997 info->respawnTime = 0;
1998 return false;
1999 }
2000
2001 // Next, check if there's already an instance of this object that would block the respawn
2002 bool alreadyExists = false;
2003 switch (info->type)
2004 {
2006 {
2007 // escort check for creatures only (if the world config boolean is set)
2008 bool const isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && data->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC);
2009
2010 auto range = _creatureBySpawnIdStore.equal_range(info->spawnId);
2011 for (auto it = range.first; it != range.second; ++it)
2012 {
2013 Creature* creature = it->second;
2014 if (!creature->IsAlive())
2015 continue;
2016 // escort NPCs are allowed to respawn as long as all other instances are already escorting
2017 if (isEscort && creature->IsEscorted())
2018 continue;
2019 alreadyExists = true;
2020 break;
2021 }
2022 break;
2023 }
2025 // gameobject check is simpler - they cannot be dead or escorting
2027 alreadyExists = true;
2028 break;
2029 default:
2030 ABORT_MSG("Invalid spawn type %u with spawnId " UI64FMTD " on map %u", uint32(info->type), info->spawnId, GetId());
2031 return true;
2032 }
2033 if (alreadyExists)
2034 {
2035 info->respawnTime = 0;
2036 return false;
2037 }
2038
2039 // next, check linked respawn time
2040 ObjectGuid thisGUID = info->type == SPAWN_TYPE_GAMEOBJECT
2041 ? ObjectGuid::Create<HighGuid::GameObject>(GetId(), info->entry, info->spawnId)
2042 : ObjectGuid::Create<HighGuid::Creature>(GetId(), info->entry, info->spawnId);
2043 if (time_t linkedTime = GetLinkedRespawnTime(thisGUID))
2044 {
2045 time_t now = GameTime::GetGameTime();
2046 time_t respawnTime;
2047 if (linkedTime == std::numeric_limits<time_t>::max())
2048 respawnTime = linkedTime;
2049 else if (sObjectMgr->GetLinkedRespawnGuid(thisGUID) == thisGUID) // never respawn, save "something" in DB
2050 respawnTime = now + WEEK;
2051 else // set us to check again shortly after linked unit
2052 respawnTime = std::max<time_t>(now, linkedTime) + urand(5, 15);
2053 info->respawnTime = respawnTime;
2054 return false;
2055 }
2056 // everything ok, let's spawn
2057 return true;
2058}
2059
2061{
2062 if (info->respawnTime <= GameTime::GetGameTime())
2063 return;
2065 _respawnTimes->increase(static_cast<RespawnInfoWithHandle*>(info)->handle);
2066 SaveRespawnInfoDB(*info, dbTrans);
2067}
2068
2070{
2071 std::vector<WorldObject*> toUnload;
2072 switch (type)
2073 {
2075 for (auto const& pair : Trinity::Containers::MapEqualRange(GetCreatureBySpawnIdStore(), spawnId))
2076 toUnload.push_back(pair.second);
2077 break;
2079 for (auto const& pair : Trinity::Containers::MapEqualRange(GetGameObjectBySpawnIdStore(), spawnId))
2080 toUnload.push_back(pair.second);
2081 break;
2082 default:
2083 break;
2084 }
2085
2086 for (WorldObject* o : toUnload)
2088
2089 return toUnload.size();
2090}
2091
2093{
2094 if (!info.spawnId)
2095 {
2096 TC_LOG_ERROR("maps", "Attempt to insert respawn info for zero spawn id (type {})", uint32(info.type));
2097 return false;
2098 }
2099
2100 RespawnInfoMap* bySpawnIdMap = GetRespawnMapForType(info.type);
2101 if (!bySpawnIdMap)
2102 return false;
2103
2104 // check if we already have the maximum possible number of respawns scheduled
2105 if (SpawnData::TypeHasData(info.type))
2106 {
2107 auto it = bySpawnIdMap->find(info.spawnId);
2108 if (it != bySpawnIdMap->end()) // spawnid already has a respawn scheduled
2109 {
2110 RespawnInfo* const existing = it->second;
2111 if (info.respawnTime <= existing->respawnTime) // delete existing in this case
2112 DeleteRespawnInfo(existing);
2113 else
2114 return false;
2115 }
2116 ASSERT(bySpawnIdMap->find(info.spawnId) == bySpawnIdMap->end(), "Insertion of respawn info with id (%u," UI64FMTD ") into spawn id map failed - state desync.", uint32(info.type), info.spawnId);
2117 }
2118 else
2119 ABORT_MSG("Invalid respawn info for spawn id (%u," UI64FMTD ") being inserted", uint32(info.type), info.spawnId);
2120
2122 ri->handle = _respawnTimes->push(ri);
2123 bySpawnIdMap->emplace(ri->spawnId, ri);
2124 return true;
2125}
2126
2127static void PushRespawnInfoFrom(std::vector<RespawnInfo const*>& data, RespawnInfoMap const& map)
2128{
2129 data.reserve(data.size() + map.size());
2130 for (auto const& pair : map)
2131 data.push_back(pair.second);
2132}
2133
2134void Map::GetRespawnInfo(std::vector<RespawnInfo const*>& respawnData, SpawnObjectTypeMask types) const
2135{
2136 if (types & SPAWN_TYPEMASK_CREATURE)
2138 if (types & SPAWN_TYPEMASK_GAMEOBJECT)
2140}
2141
2143{
2144 RespawnInfoMap const* map = GetRespawnMapForType(type);
2145 if (!map)
2146 return nullptr;
2147 auto it = map->find(spawnId);
2148 if (it == map->end())
2149 return nullptr;
2150 return it->second;
2151}
2152
2153void Map::UnloadAllRespawnInfos() // delete everything from memory
2154{
2155 for (RespawnInfo* info : *_respawnTimes)
2156 delete info;
2157 _respawnTimes->clear();
2160}
2161
2163{
2164 // Delete from all relevant containers to ensure consistency
2165 ASSERT(info);
2166
2167 // spawnid store
2168 auto spawnMap = GetRespawnMapForType(info->type);
2169 if (!spawnMap)
2170 return;
2171
2172 auto range = spawnMap->equal_range(info->spawnId);
2173 auto it = std::find_if(range.first, range.second, [info](RespawnInfoMap::value_type const& pair) { return (pair.second == info); });
2174 ASSERT(it != range.second, "Respawn stores inconsistent for map %u, spawnid " UI64FMTD " (type %u)", GetId(), info->spawnId, uint32(info->type));
2175 spawnMap->erase(it);
2176
2177 // respawn heap
2178 _respawnTimes->erase(static_cast<RespawnInfoWithHandle*>(info)->handle);
2179
2180 // database
2181 DeleteRespawnInfoFromDB(info->type, info->spawnId, dbTrans);
2182
2183 // then cleanup the object
2184 delete info;
2185}
2186
2188{
2189 if (Instanceable())
2190 return;
2191
2193 stmt->setUInt16(0, type);
2194 stmt->setUInt64(1, spawnId);
2195 stmt->setUInt16(2, GetId());
2196 stmt->setUInt32(3, GetInstanceId());
2197 CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
2198}
2199
2201{
2202 if (!IsGridLoaded(gridId)) // if grid isn't loaded, this will be processed in grid load handler
2203 return;
2204
2205 switch (type)
2206 {
2208 {
2209 Creature* obj = new Creature();
2210 if (!obj->LoadFromDB(spawnId, this, true, true))
2211 delete obj;
2212 break;
2213 }
2215 {
2216 GameObject* obj = new GameObject();
2217 if (!obj->LoadFromDB(spawnId, this, true))
2218 delete obj;
2219 break;
2220 }
2221 default:
2222 ABORT_MSG("Invalid spawn type %u (spawnid " UI64FMTD ") on map %u", uint32(type), spawnId, GetId());
2223 }
2224}
2225
2227{
2228 time_t now = GameTime::GetGameTime();
2229 while (!_respawnTimes->empty())
2230 {
2231 RespawnInfoWithHandle* next = _respawnTimes->top();
2232 if (now < next->respawnTime) // done for this tick
2233 break;
2234
2235 if (uint32 poolId = sPoolMgr->IsPartOfAPool(next->type, next->spawnId)) // is this part of a pool?
2236 { // if yes, respawn will be handled by (external) pooling logic, just delete the respawn time
2237 // step 1: remove entry from maps to avoid it being reachable by outside logic
2238 _respawnTimes->pop();
2239 ASSERT_NOTNULL(GetRespawnMapForType(next->type))->erase(next->spawnId);
2240
2241 // step 2: tell pooling logic to do its thing
2242 sPoolMgr->UpdatePool(GetPoolData(), poolId, next->type, next->spawnId);
2243
2244 // step 3: get rid of the actual entry
2245 RemoveRespawnTime(next->type, next->spawnId, nullptr, true);
2246 delete next;
2247 }
2248 else if (CheckRespawn(next)) // see if we're allowed to respawn
2249 { // ok, respawn
2250 // step 1: remove entry from maps to avoid it being reachable by outside logic
2251 _respawnTimes->pop();
2252 ASSERT_NOTNULL(GetRespawnMapForType(next->type))->erase(next->spawnId);
2253
2254 // step 2: do the respawn, which involves external logic
2255 DoRespawn(next->type, next->spawnId, next->gridId);
2256
2257 // step 3: get rid of the actual entry
2258 RemoveRespawnTime(next->type, next->spawnId, nullptr, true);
2259 delete next;
2260 }
2261 else if (!next->respawnTime)
2262 { // just remove this respawn entry without rescheduling
2263 _respawnTimes->pop();
2264 ASSERT_NOTNULL(GetRespawnMapForType(next->type))->erase(next->spawnId);
2265 RemoveRespawnTime(next->type, next->spawnId, nullptr, true);
2266 delete next;
2267 }
2268 else
2269 { // new respawn time, update heap position
2270 ASSERT(now < next->respawnTime); // infinite loop guard
2271 _respawnTimes->decrease(next->handle);
2272 SaveRespawnInfoDB(*next);
2273 }
2274 }
2275}
2276
2277void Map::ApplyDynamicModeRespawnScaling(WorldObject const* obj, ObjectGuid::LowType spawnId, uint32& respawnDelay, uint32 mode) const
2278{
2279 ASSERT(mode == 1);
2280 ASSERT(obj->GetMap() == this);
2281
2283 return;
2284
2285 SpawnObjectType type;
2286 switch (obj->GetTypeId())
2287 {
2288 case TYPEID_UNIT:
2289 type = SPAWN_TYPE_CREATURE;
2290 break;
2291 case TYPEID_GAMEOBJECT:
2292 type = SPAWN_TYPE_GAMEOBJECT;
2293 break;
2294 default:
2295 return;
2296 }
2297
2298 SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId);
2299 if (!data)
2300 return;
2301
2303 return;
2304
2305 auto it = _zonePlayerCountMap.find(obj->GetZoneId());
2306 if (it == _zonePlayerCountMap.end())
2307 return;
2308 uint32 const playerCount = it->second;
2309 if (!playerCount)
2310 return;
2311 double const adjustFactor = sWorld->getFloatConfig(type == SPAWN_TYPE_GAMEOBJECT ? CONFIG_RESPAWN_DYNAMICRATE_GAMEOBJECT : CONFIG_RESPAWN_DYNAMICRATE_CREATURE) / playerCount;
2312 if (adjustFactor >= 1.0) // nothing to do here
2313 return;
2315 if (respawnDelay <= timeMinimum)
2316 return;
2317
2318 respawnDelay = std::max<uint32>(ceil(respawnDelay * adjustFactor), timeMinimum);
2319}
2320
2322{
2324 // check if the object is on its respawn timer
2325 if (GetRespawnTime(type, spawnId))
2326 return false;
2327
2328 SpawnMetadata const* spawnData = ASSERT_NOTNULL(sObjectMgr->GetSpawnMetadata(type, spawnId));
2329 // check if the object is part of a spawn group
2330 SpawnGroupTemplateData const* spawnGroup = ASSERT_NOTNULL(spawnData->spawnGroupData);
2331 if (!(spawnGroup->flags & SPAWNGROUP_FLAG_SYSTEM))
2332 if (!IsSpawnGroupActive(spawnGroup->groupId))
2333 return false;
2334
2335 if (spawnData->ToSpawnData()->poolId)
2336 if (!GetPoolData().IsSpawnedObject(type, spawnId))
2337 return false;
2338
2339 return true;
2340}
2341
2343{
2344 SpawnGroupTemplateData const* data = sObjectMgr->GetSpawnGroupData(groupId);
2345 if (data && (data->flags & SPAWNGROUP_FLAG_SYSTEM || data->mapId == GetId()))
2346 return data;
2347 return nullptr;
2348}
2349
2350bool Map::SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn, bool force, std::vector<WorldObject*>* spawnedObjects)
2351{
2352 SpawnGroupTemplateData const* groupData = GetSpawnGroupData(groupId);
2353 if (!groupData || groupData->flags & SPAWNGROUP_FLAG_SYSTEM)
2354 {
2355 TC_LOG_ERROR("maps", "Tried to spawn non-existing (or system) spawn group {} on map {}. Blocked.", groupId, GetId());
2356 return false;
2357 }
2358
2359 SetSpawnGroupActive(groupId, true); // start processing respawns for the group
2360
2361 std::vector<SpawnData const*> toSpawn;
2362 for (auto& pair : sObjectMgr->GetSpawnMetadataForGroup(groupId))
2363 {
2364 SpawnMetadata const* data = pair.second;
2365 ASSERT(groupData->mapId == data->mapId);
2366
2367 auto respawnMap = GetRespawnMapForType(data->type);
2368 if (!respawnMap)
2369 continue;
2370
2371 if (force || ignoreRespawn)
2372 RemoveRespawnTime(data->type, data->spawnId);
2373
2374 uint32 nRespawnTimers = respawnMap->count(data->spawnId);
2375 if (SpawnData::TypeHasData(data->type))
2376 {
2377 // has a respawn timer
2378 if (nRespawnTimers)
2379 continue;
2380
2381 // has a spawn already active
2382 if (!force)
2383 if (WorldObject* obj = GetWorldObjectBySpawnId(data->type, data->spawnId))
2384 if ((data->type != SPAWN_TYPE_CREATURE) || obj->ToCreature()->IsAlive())
2385 continue;
2386
2387 toSpawn.push_back(ASSERT_NOTNULL(data->ToSpawnData()));
2388 }
2389 }
2390
2391 for (SpawnData const* data : toSpawn)
2392 {
2393 // don't spawn if the current map difficulty is not used by the spawn
2394 if (std::find(data->spawnDifficulties.begin(), data->spawnDifficulties.end(), GetDifficultyID()) == data->spawnDifficulties.end())
2395 continue;
2396
2397 // don't spawn if the grid isn't loaded (will be handled in grid loader)
2398 if (!IsGridLoaded(data->spawnPoint))
2399 continue;
2400
2401 // now do the actual (re)spawn
2402 switch (data->type)
2403 {
2405 {
2406 Creature* creature = new Creature();
2407 if (!creature->LoadFromDB(data->spawnId, this, true, force))
2408 delete creature;
2409 else if (spawnedObjects)
2410 spawnedObjects->push_back(creature);
2411 break;
2412 }
2414 {
2415 GameObject* gameobject = new GameObject();
2416 if (!gameobject->LoadFromDB(data->spawnId, this, true))
2417 delete gameobject;
2418 else if (spawnedObjects)
2419 spawnedObjects->push_back(gameobject);
2420 break;
2421 }
2423 {
2424 AreaTrigger* areaTrigger = new AreaTrigger();
2425 if (!areaTrigger->LoadFromDB(data->spawnId, this, true, false))
2426 delete areaTrigger;
2427 else if (spawnedObjects)
2428 spawnedObjects->push_back(areaTrigger);
2429 break;
2430 }
2431 default:
2432 ABORT_MSG("Invalid spawn type %u with spawnId " UI64FMTD, uint32(data->type), data->spawnId);
2433 return false;
2434 }
2435 }
2436 return true;
2437}
2438
2439bool Map::SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes, size_t* count)
2440{
2441 SpawnGroupTemplateData const* groupData = GetSpawnGroupData(groupId);
2442 if (!groupData || groupData->flags & SPAWNGROUP_FLAG_SYSTEM)
2443 {
2444 TC_LOG_ERROR("maps", "Tried to despawn non-existing (or system) spawn group {} on map {}. Blocked.", groupId, GetId());
2445 return false;
2446 }
2447
2448 for (auto const& pair : sObjectMgr->GetSpawnMetadataForGroup(groupId))
2449 {
2450 SpawnMetadata const* data = pair.second;
2451 ASSERT(groupData->mapId == data->mapId);
2452 if (deleteRespawnTimes)
2453 RemoveRespawnTime(data->type, data->spawnId);
2454 size_t c = DespawnAll(data->type, data->spawnId);
2455 if (count)
2456 *count += c;
2457 }
2458 SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too
2459 return true;
2460}
2461
2462void Map::SetSpawnGroupActive(uint32 groupId, bool state)
2463{
2464 SpawnGroupTemplateData const* const data = GetSpawnGroupData(groupId);
2465 if (!data || data->flags & SPAWNGROUP_FLAG_SYSTEM)
2466 {
2467 TC_LOG_ERROR("maps", "Tried to set non-existing (or system) spawn group {} to {} on map {}. Blocked.", groupId, state ? "active" : "inactive", GetId());
2468 return;
2469 }
2470 if (state != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN)) // toggled
2471 _toggledSpawnGroupIds.insert(groupId);
2472 else
2473 _toggledSpawnGroupIds.erase(groupId);
2474}
2475
2477{
2478 SpawnGroupTemplateData const* const data = GetSpawnGroupData(groupId);
2479 if (!data)
2480 {
2481 TC_LOG_ERROR("maps", "Tried to query state of non-existing spawn group {} on map {}.", groupId, GetId());
2482 return false;
2483 }
2484 if (data->flags & SPAWNGROUP_FLAG_SYSTEM)
2485 return true;
2486 // either manual spawn group and toggled, or not manual spawn group and not toggled...
2487 return (_toggledSpawnGroupIds.find(groupId) != _toggledSpawnGroupIds.end()) != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN);
2488}
2489
2491{
2492 std::vector<uint32> const* spawnGroups = sObjectMgr->GetSpawnGroupsForMap(GetId());
2493 if (!spawnGroups)
2494 return;
2495
2496 for (uint32 spawnGroupId : *spawnGroups)
2497 {
2498 SpawnGroupTemplateData const* spawnGroupTemplate = ASSERT_NOTNULL(GetSpawnGroupData(spawnGroupId));
2499 if (spawnGroupTemplate->flags & (SPAWNGROUP_FLAG_SYSTEM | SPAWNGROUP_FLAG_MANUAL_SPAWN))
2500 continue;
2501
2502 SetSpawnGroupActive(spawnGroupId, sConditionMgr->IsMapMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPAWN_GROUP, spawnGroupId, this));
2503 }
2504}
2505
2507{
2508 std::vector<uint32> const* spawnGroups = sObjectMgr->GetSpawnGroupsForMap(GetId());
2509 if (!spawnGroups)
2510 return;
2511
2512 for (uint32 spawnGroupId : *spawnGroups)
2513 {
2514 SpawnGroupTemplateData const* spawnGroupTemplate = ASSERT_NOTNULL(GetSpawnGroupData(spawnGroupId));
2515
2516 bool isActive = IsSpawnGroupActive(spawnGroupId);
2517 bool shouldBeActive = sConditionMgr->IsMapMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPAWN_GROUP, spawnGroupId, this);
2518
2519 if (spawnGroupTemplate->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN)
2520 {
2521 // Only despawn the group if it isn't meeting conditions
2522 if (isActive && !shouldBeActive && spawnGroupTemplate->flags & SPAWNGROUP_FLAG_DESPAWN_ON_CONDITION_FAILURE)
2523 SpawnGroupDespawn(spawnGroupId, true);
2524
2525 continue;
2526 }
2527
2528 if (isActive == shouldBeActive)
2529 continue;
2530
2531 if (shouldBeActive)
2532 SpawnGroupSpawn(spawnGroupId);
2533 else if (spawnGroupTemplate->flags & SPAWNGROUP_FLAG_DESPAWN_ON_CONDITION_FAILURE)
2534 SpawnGroupDespawn(spawnGroupId, true);
2535 else
2536 SetSpawnGroupInactive(spawnGroupId);
2537 }
2538}
2539
2541{
2542 auto itr = _guidGenerators.find(high);
2543 if (itr == _guidGenerators.end())
2544 itr = _guidGenerators.insert(std::make_pair(high, std::make_unique<ObjectGuidGenerator>(high))).first;
2545
2546 return *itr->second;
2547}
2548
2550{
2551 _farSpellCallbacks.Enqueue(new FarSpellCallback(std::move(callback)));
2552}
2553
2555{
2556 {
2557 FarSpellCallback* callback;
2558 while (_farSpellCallbacks.Dequeue(callback))
2559 {
2560 (*callback)(this);
2561 delete callback;
2562 }
2563 }
2564
2566
2567 // Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load !
2568 // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
2569 if (!IsBattlegroundOrArena())
2570 {
2572 {
2573 NGridType *grid = i->GetSource();
2574 GridInfo* info = i->GetSource()->getGridInfoRef();
2575 ++i; // The update might delete the map and we need the next map before the iterator gets invalid
2576 ASSERT(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
2577 si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, t_diff);
2578 }
2579 }
2580}
2581
2583{
2584 ASSERT(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId());
2585
2586 obj->SetDestroyedObject(true);
2587 obj->CleanupsBeforeDelete(false); // remove or simplify at least cross referenced links
2588
2589 i_objectsToRemove.insert(obj);
2590}
2591
2593{
2594 ASSERT(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId());
2595 // i_objectsToSwitch is iterated only in Map::RemoveAllObjectsInRemoveList() and it uses
2596 // the contained objects only if GetTypeId() == TYPEID_UNIT , so we can return in all other cases
2597 if (obj->GetTypeId() != TYPEID_UNIT)
2598 return;
2599
2600 std::map<WorldObject*, bool>::iterator itr = i_objectsToSwitch.find(obj);
2601 if (itr == i_objectsToSwitch.end())
2602 i_objectsToSwitch.insert(itr, std::make_pair(obj, on));
2603 else if (itr->second != on)
2604 i_objectsToSwitch.erase(itr);
2605 else
2606 ABORT();
2607}
2608
2610{
2611 while (!i_objectsToSwitch.empty())
2612 {
2613 std::map<WorldObject*, bool>::iterator itr = i_objectsToSwitch.begin();
2614 WorldObject* obj = itr->first;
2615 bool on = itr->second;
2616 i_objectsToSwitch.erase(itr);
2617
2619 {
2620 switch (obj->GetTypeId())
2621 {
2622 case TYPEID_UNIT:
2623 SwitchGridContainers<Creature>(obj->ToCreature(), on);
2624 break;
2625 default:
2626 break;
2627 }
2628 }
2629 }
2630
2631 //TC_LOG_DEBUG("maps", "Object remover 1 check.");
2632 while (!i_objectsToRemove.empty())
2633 {
2634 std::set<WorldObject*>::iterator itr = i_objectsToRemove.begin();
2635 WorldObject* obj = *itr;
2636
2637 switch (obj->GetTypeId())
2638 {
2639 case TYPEID_CORPSE:
2640 {
2641 Corpse* corpse = ObjectAccessor::GetCorpse(*obj, obj->GetGUID());
2642 if (!corpse)
2643 TC_LOG_ERROR("maps", "Tried to delete corpse/bones {} that is not in map.", obj->GetGUID().ToString());
2644 else
2645 RemoveFromMap(corpse, true);
2646 break;
2647 }
2649 RemoveFromMap(obj->ToDynObject(), true);
2650 break;
2651 case TYPEID_AREATRIGGER:
2652 RemoveFromMap((AreaTrigger*)obj, true);
2653 break;
2655 RemoveFromMap((Conversation*)obj, true);
2656 break;
2657 case TYPEID_GAMEOBJECT:
2658 {
2659 GameObject* go = obj->ToGameObject();
2660 if (Transport* transport = go->ToTransport())
2661 RemoveFromMap(transport, true);
2662 else
2663 RemoveFromMap(go, true);
2664 break;
2665 }
2666 case TYPEID_UNIT:
2667 // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call
2668 // make sure that like sources auras/etc removed before destructor start
2670 RemoveFromMap(obj->ToCreature(), true);
2671 break;
2672 default:
2673 TC_LOG_ERROR("maps", "Non-grid object (TypeId: {}) is in grid object remove list, ignored.", obj->GetTypeId());
2674 break;
2675 }
2676
2677 i_objectsToRemove.erase(itr);
2678 }
2679
2680 //TC_LOG_DEBUG("maps", "Object remover 2 check.");
2681}
2682
2684{
2685 uint32 count = 0;
2687 if (!itr->GetSource()->IsGameMaster())
2688 ++count;
2689 return count;
2690}
2691
2692void Map::SendToPlayers(WorldPacket const* data) const
2693{
2695 itr->GetSource()->SendDirectMessage(data);
2696}
2697
2699{
2700 CellCoord cell_min(ngrid.getX() * MAX_NUMBER_OF_CELLS, ngrid.getY() * MAX_NUMBER_OF_CELLS);
2701 CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
2702
2703 //we must find visible range in cells so we unload only non-visible cells...
2704 float viewDist = GetVisibilityRange();
2705 int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1;
2706
2707 cell_min.dec_x(cell_range);
2708 cell_min.dec_y(cell_range);
2709 cell_max.inc_x(cell_range);
2710 cell_max.inc_y(cell_range);
2711
2713 {
2714 Player* player = iter->GetSource();
2715
2717 if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
2718 (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord))
2719 return true;
2720 }
2721
2722 for (ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter)
2723 {
2724 WorldObject* obj = *iter;
2725
2727 if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
2728 (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord))
2729 return true;
2730 }
2731
2732 return false;
2733}
2734
2736{
2737 AddToActiveHelper(obj);
2738
2739 Optional<Position> respawnLocation;
2740 switch (obj->GetTypeId())
2741 {
2742 case TYPEID_UNIT:
2743 if (Creature* creature = obj->ToCreature(); !creature->IsPet() && creature->GetSpawnId())
2744 {
2745 respawnLocation.emplace();
2746 creature->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
2747 }
2748 break;
2749 case TYPEID_GAMEOBJECT:
2750 if (GameObject* gameObject = obj->ToGameObject(); gameObject->GetSpawnId())
2751 {
2752 respawnLocation.emplace();
2753 gameObject->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
2754 }
2755 break;
2756 default:
2757 break;
2758 }
2759
2760 if (respawnLocation)
2761 {
2762 GridCoord p = Trinity::ComputeGridCoord(respawnLocation->GetPositionX(), respawnLocation->GetPositionY());
2763 if (getNGrid(p.x_coord, p.y_coord))
2765 else
2766 {
2768 TC_LOG_ERROR("maps", "Active object {} added to grid[{}, {}] but spawn grid[{}, {}] was not loaded.",
2769 obj->GetGUID().ToString(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
2770 }
2771 }
2772}
2773
2775{
2777
2778 Optional<Position> respawnLocation;
2779 switch (obj->GetTypeId())
2780 {
2781 case TYPEID_UNIT:
2782 if (Creature* creature = obj->ToCreature(); !creature->IsPet() && creature->GetSpawnId())
2783 {
2784 respawnLocation.emplace();
2785 creature->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
2786 }
2787 break;
2788 case TYPEID_GAMEOBJECT:
2789 if (GameObject* gameObject = obj->ToGameObject(); gameObject->GetSpawnId())
2790 {
2791 respawnLocation.emplace();
2792 gameObject->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
2793 }
2794 break;
2795 default:
2796 break;
2797 }
2798
2799 if (respawnLocation)
2800 {
2801 GridCoord p = Trinity::ComputeGridCoord(respawnLocation->GetPositionX(), respawnLocation->GetPositionY());
2802 if (getNGrid(p.x_coord, p.y_coord))
2804 else
2805 {
2807 TC_LOG_ERROR("maps", "Active object {} removed from to grid[{}, {}] but spawn grid[{}, {}] was not loaded.",
2808 obj->GetGUID().ToString(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
2809 }
2810 }
2811}
2812
2813template TC_GAME_API bool Map::AddToMap(Corpse*);
2814template TC_GAME_API bool Map::AddToMap(Creature*);
2815template TC_GAME_API bool Map::AddToMap(GameObject*);
2817template TC_GAME_API bool Map::AddToMap(AreaTrigger*);
2818template TC_GAME_API bool Map::AddToMap(SceneObject*);
2819template TC_GAME_API bool Map::AddToMap(Conversation*);
2820
2821template TC_GAME_API void Map::RemoveFromMap(Corpse*, bool);
2822template TC_GAME_API void Map::RemoveFromMap(Creature*, bool);
2823template TC_GAME_API void Map::RemoveFromMap(GameObject*, bool);
2824template TC_GAME_API void Map::RemoveFromMap(DynamicObject*, bool);
2825template TC_GAME_API void Map::RemoveFromMap(AreaTrigger*, bool);
2826template TC_GAME_API void Map::RemoveFromMap(SceneObject*, bool);
2827template TC_GAME_API void Map::RemoveFromMap(Conversation*, bool);
2828
2829/* ******* Dungeon Instance Maps ******* */
2830
2831InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, TeamId InstanceTeam, InstanceLock* instanceLock)
2832 : Map(id, expiry, InstanceId, SpawnMode),
2833 i_data(nullptr), i_script_id(0), i_scenario(nullptr), i_instanceLock(instanceLock)
2834{
2835 //lets initialize visibility distance for dungeons
2837
2838 // the timer is started by default, and stopped when the first player joins
2839 // this make sure it gets unloaded if for some reason no player joins
2841
2842 sWorldStateMgr->SetValue(WS_TEAM_IN_INSTANCE_ALLIANCE, InstanceTeam == TEAM_ALLIANCE, false, this);
2843 sWorldStateMgr->SetValue(WS_TEAM_IN_INSTANCE_HORDE, InstanceTeam == TEAM_HORDE, false, this);
2844
2845 if (i_instanceLock)
2846 {
2847 i_instanceLock->SetInUse(true);
2848 i_instanceExpireEvent = i_instanceLock->GetExpiryTime(); // ignore extension state for reset event (will ask players to accept extended save on expiration)
2849 }
2850}
2851
2853{
2854 if (i_instanceLock)
2855 i_instanceLock->SetInUse(false);
2856
2857 delete i_data;
2858 delete i_scenario;
2859}
2860
2862{
2863 //init visibility distance for instances
2866}
2867
2868/*
2869 Do map specific checks to see if the player can enter
2870*/
2872{
2873 if (player->GetMapRef().getTarget() == this)
2874 {
2875 TC_LOG_ERROR("maps", "InstanceMap::CannotEnter - player {} {} already in map {}, {}, {}!", player->GetName(), player->GetGUID().ToString(), GetId(), GetInstanceId(), GetDifficultyID());
2876 ABORT();
2877 return TRANSFER_ABORT_ERROR;
2878 }
2879
2880 // allow GM's to enter
2881 if (player->IsGameMaster())
2882 return Map::CannotEnter(player);
2883
2884 // cannot enter if the instance is full (player cap), GMs don't count
2885 uint32 maxPlayers = GetMaxPlayers();
2886 if (GetPlayersCountExceptGMs() >= maxPlayers)
2887 {
2888 TC_LOG_WARN("maps", "MAP: Instance '{}' of map '{}' cannot have more than '{}' players. Player '{}' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName());
2890 }
2891
2892 // cannot enter while an encounter is in progress (unless this is a relog, in which case it is permitted)
2893 if (!player->IsLoading() && IsRaid() && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
2895
2896 if (i_instanceLock)
2897 {
2898 // cannot enter if player is permanent saved to a different instance id
2899 TransferAbortReason lockError = sInstanceLockMgr.CanJoinInstanceLock(player->GetGUID(), { GetEntry(), GetMapDifficulty() }, i_instanceLock);
2900 if (lockError != TRANSFER_ABORT_NONE)
2901 return lockError;
2902 }
2903
2904 return Map::CannotEnter(player);
2905}
2906
2907/*
2908 Do map specific checks and add the player to the map if successful.
2909*/
2910bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
2911{
2912 // increase current instances (hourly limit)
2914
2915 MapDb2Entries entries{ GetEntry(), GetMapDifficulty() };
2916 if (entries.MapDifficulty->HasResetSchedule() && i_instanceLock && !i_instanceLock->IsNew() && i_data)
2917 {
2918 if (!entries.MapDifficulty->IsUsingEncounterLocks())
2919 {
2920 InstanceLock const* playerLock = sInstanceLockMgr.FindActiveInstanceLock(player->GetGUID(), entries);
2921 if (!playerLock || (playerLock->IsExpired() && playerLock->IsExtended()) ||
2923 {
2925 pendingRaidLock.TimeUntilLock = 60000;
2927 pendingRaidLock.Extending = playerLock && playerLock->IsExtended();
2928 pendingRaidLock.WarningOnly = entries.Map->IsFlexLocking(); // events it triggers: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
2929 player->GetSession()->SendPacket(pendingRaidLock.Write());
2930 if (!entries.Map->IsFlexLocking())
2931 player->SetPendingBind(GetInstanceId(), 60000);
2932 }
2933 }
2934 }
2935
2936 TC_LOG_DEBUG("maps", "MAP: Player '{}' entered instance '{}' of map '{}'", player->GetName(), GetInstanceId(), GetMapName());
2937 // initialize unload state
2938 m_unloadTimer = 0;
2939
2940 // this will acquire the same mutex so it cannot be in the previous block
2941 Map::AddPlayerToMap(player, initPlayer);
2942
2943 if (i_data)
2944 i_data->OnPlayerEnter(player);
2945
2946 if (i_scenario)
2947 i_scenario->OnPlayerEnter(player);
2948
2949 return true;
2950}
2951
2953{
2954 Map::Update(t_diff);
2955
2956 if (i_data)
2957 {
2958 i_data->Update(t_diff);
2960 }
2961
2962 if (i_scenario)
2963 i_scenario->Update(t_diff);
2964
2966 {
2969 }
2970}
2971
2973{
2974 TC_LOG_DEBUG("maps", "MAP: Removing player '{}' from instance '{}' of map '{}' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName());
2975
2976 if (i_data)
2977 i_data->OnPlayerLeave(player);
2978
2979 // if last player set unload timer
2980 if (!m_unloadTimer && m_mapRefManager.getSize() == 1)
2982
2983 if (i_scenario)
2984 i_scenario->OnPlayerExit(player);
2985
2986 Map::RemovePlayerFromMap(player, remove);
2987}
2988
2990{
2991 if (i_data != nullptr)
2992 return;
2993
2994 InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(GetId());
2995 if (mInstance)
2996 {
2997 i_script_id = mInstance->ScriptId;
2998 i_data = sScriptMgr->CreateInstanceData(this);
2999 }
3000
3001 if (!i_data)
3002 return;
3003
3005 {
3006 i_data->Create();
3007 return;
3008 }
3009
3010 MapDb2Entries entries{ GetEntry(), GetMapDifficulty() };
3011 if (!entries.IsInstanceIdBound() && !IsRaid() && !entries.MapDifficulty->IsRestoringDungeonState() && i_owningGroupRef.isValid())
3012 {
3013 i_data->Create();
3014 return;
3015 }
3016
3019 if (!lockData->Data.empty())
3020 {
3021 TC_LOG_DEBUG("maps", "Loading instance data for `{}` with id {}", sObjectMgr->GetScriptName(i_script_id), i_InstanceId);
3022 i_data->Load(lockData->Data.c_str());
3023 }
3024 else
3025 i_data->Create();
3026}
3027
3029{
3031 i_owningGroupRef.link(group, this);
3032}
3033
3034/*
3035 Returns true if there are no players in the instance
3036*/
3038{
3039 // raids can be reset if no boss was killed
3042
3043 if (HavePlayers())
3044 {
3045 switch (method)
3046 {
3048 // notify the players to leave the instance so it can be reset
3049 for (MapReference const& ref : m_mapRefManager)
3050 ref.GetSource()->SendResetFailedNotify(GetId());
3051 break;
3053 // no client notification
3054 break;
3056 {
3058 raidInstanceMessage.Type = RAID_INSTANCE_EXPIRED;
3059 raidInstanceMessage.MapID = GetId();
3060 raidInstanceMessage.DifficultyID = GetDifficultyID();
3061 raidInstanceMessage.Write();
3062
3063 for (MapReference const& ref : m_mapRefManager)
3064 ref.GetSource()->SendDirectMessage(raidInstanceMessage.GetRawPacket());
3065
3066 if (i_data)
3067 {
3069 pendingRaidLock.TimeUntilLock = 60000;
3071 pendingRaidLock.Extending = true;
3072 pendingRaidLock.WarningOnly = GetEntry()->IsFlexLocking();
3073 pendingRaidLock.Write();
3074
3075 for (MapReference const& ref : m_mapRefManager)
3076 {
3077 ref.GetSource()->SendDirectMessage(pendingRaidLock.GetRawPacket());
3078
3079 if (!pendingRaidLock.WarningOnly)
3080 ref.GetSource()->SetPendingBind(GetInstanceId(), 60000);
3081 }
3082 }
3083 break;
3084 }
3085 default:
3086 break;
3087 }
3088
3090 }
3091 else
3092 {
3093 // unloaded at next update
3095 }
3096
3098}
3099
3100std::string const& InstanceMap::GetScriptName() const
3101{
3102 return sObjectMgr->GetScriptName(i_script_id);
3103}
3104
3106{
3107 if (i_instanceLock)
3108 {
3109 uint32 instanceCompletedEncounters = i_instanceLock->GetData()->CompletedEncountersMask | (1u << updateSaveDataEvent.DungeonEncounter->Bit);
3110
3111 MapDb2Entries entries{ GetEntry(), GetMapDifficulty() };
3112
3113 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3114
3115 if (entries.IsInstanceIdBound())
3116 sInstanceLockMgr.UpdateSharedInstanceLock(trans, InstanceLockUpdateEvent(GetInstanceId(), i_data->GetSaveData(),
3117 instanceCompletedEncounters, updateSaveDataEvent.DungeonEncounter, i_data->GetEntranceLocationForCompletedEncounters(instanceCompletedEncounters)));
3118
3119 for (MapReference& mapReference : m_mapRefManager)
3120 {
3121 Player* player = mapReference.GetSource();
3122 // never instance bind GMs with GM mode enabled
3123 if (player->IsGameMaster())
3124 continue;
3125
3126 InstanceLock const* playerLock = sInstanceLockMgr.FindActiveInstanceLock(player->GetGUID(), entries);
3127 std::string const* oldData = nullptr;
3128 uint32 playerCompletedEncounters = 0;
3129 if (playerLock)
3130 {
3131 oldData = &playerLock->GetData()->Data;
3132 playerCompletedEncounters = playerLock->GetData()->CompletedEncountersMask | (1u << updateSaveDataEvent.DungeonEncounter->Bit);
3133 }
3134
3135 bool isNewLock = !playerLock || playerLock->IsNew() || playerLock->IsExpired();
3136
3137 InstanceLock const* newLock = sInstanceLockMgr.UpdateInstanceLockForPlayer(trans, player->GetGUID(), entries,
3138 InstanceLockUpdateEvent(GetInstanceId(), i_data->UpdateBossStateSaveData(oldData ? *oldData : "", updateSaveDataEvent),
3139 instanceCompletedEncounters, updateSaveDataEvent.DungeonEncounter, i_data->GetEntranceLocationForCompletedEncounters(playerCompletedEncounters)));
3140
3141 if (isNewLock)
3142 {
3144 data.Gm = player->IsGameMaster();
3145 player->SendDirectMessage(data.Write());
3146
3147 player->GetSession()->SendCalendarRaidLockoutAdded(newLock);
3148 }
3149 }
3150
3151 CharacterDatabase.CommitTransaction(trans);
3152 }
3153}
3154
3156{
3157 if (i_instanceLock)
3158 {
3159 uint32 instanceCompletedEncounters = i_instanceLock->GetData()->CompletedEncountersMask;
3160
3161 MapDb2Entries entries{ GetEntry(), GetMapDifficulty() };
3162
3163 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3164
3165 if (entries.IsInstanceIdBound())
3166 sInstanceLockMgr.UpdateSharedInstanceLock(trans, InstanceLockUpdateEvent(GetInstanceId(), i_data->GetSaveData(),
3167 instanceCompletedEncounters, nullptr, {}));
3168
3169 for (MapReference& mapReference : m_mapRefManager)
3170 {
3171 Player* player = mapReference.GetSource();
3172 // never instance bind GMs with GM mode enabled
3173 if (player->IsGameMaster())
3174 continue;
3175
3176 InstanceLock const* playerLock = sInstanceLockMgr.FindActiveInstanceLock(player->GetGUID(), entries);
3177 std::string const* oldData = nullptr;
3178 if (playerLock)
3179 oldData = &playerLock->GetData()->Data;
3180
3181 bool isNewLock = !playerLock || playerLock->IsNew() || playerLock->IsExpired();
3182
3183 InstanceLock const* newLock = sInstanceLockMgr.UpdateInstanceLockForPlayer(trans, player->GetGUID(), entries,
3184 InstanceLockUpdateEvent(GetInstanceId(), i_data->UpdateAdditionalSaveData(oldData ? *oldData : "", updateSaveDataEvent),
3185 instanceCompletedEncounters, nullptr, {}));
3186
3187 if (isNewLock)
3188 {
3190 data.Gm = player->IsGameMaster();
3191 player->SendDirectMessage(data.Write());
3192
3193 player->GetSession()->SendCalendarRaidLockoutAdded(newLock);
3194 }
3195 }
3196
3197 CharacterDatabase.CommitTransaction(trans);
3198 }
3199}
3200
3202{
3203 MapDb2Entries entries{ GetEntry(), GetMapDifficulty() };
3204 InstanceLock const* playerLock = sInstanceLockMgr.FindActiveInstanceLock(player->GetGUID(), entries);
3205
3206 bool isNewLock = !playerLock || playerLock->IsNew() || playerLock->IsExpired();
3207
3208 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3209
3210 InstanceLock const* newLock = sInstanceLockMgr.UpdateInstanceLockForPlayer(trans, player->GetGUID(), entries,
3212
3213 CharacterDatabase.CommitTransaction(trans);
3214
3215 if (isNewLock)
3216 {
3218 data.Gm = player->IsGameMaster();
3219 player->SendDirectMessage(data.Write());
3220
3221 player->GetSession()->SendCalendarRaidLockoutAdded(newLock);
3222 }
3223}
3224
3226{
3227 return sDB2Manager.GetMapDifficultyData(GetId(), GetDifficultyID());
3228}
3229
3231{
3232 return i_mapEntry->ID;
3233}
3234
3236{
3237 return i_mapEntry && i_mapEntry->Instanceable();
3238}
3239
3240bool Map::IsDungeon() const
3241{
3242 return i_mapEntry && i_mapEntry->IsDungeon();
3243}
3244
3246{
3248}
3249
3250bool Map::IsRaid() const
3251{
3252 return i_mapEntry && i_mapEntry->IsRaid();
3253}
3254
3255bool Map::IsLFR() const
3256{
3257 switch (i_spawnMode)
3258 {
3259 case DIFFICULTY_LFR:
3260 case DIFFICULTY_LFR_NEW:
3262 return true;
3263 default:
3264 return false;
3265 }
3266}
3267
3268bool Map::IsNormal() const
3269{
3270 switch (i_spawnMode)
3271 {
3272 case DIFFICULTY_NORMAL:
3273 case DIFFICULTY_10_N:
3274 case DIFFICULTY_25_N:
3278 return true;
3279 default:
3280 return false;
3281 }
3282}
3283
3284bool Map::IsHeroic() const
3285{
3286 if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(i_spawnMode))
3287 {
3288 if (difficulty->Flags & DIFFICULTY_FLAG_DISPLAY_HEROIC)
3289 return true;
3290 }
3291
3292 // compatibility purposes of old difficulties
3293 switch (i_spawnMode)
3294 {
3295 case DIFFICULTY_10_HC:
3296 case DIFFICULTY_25_HC:
3297 case DIFFICULTY_HEROIC:
3299 return true;
3300 default:
3301 return false;
3302 }
3303}
3304
3305bool Map::IsMythic() const
3306{
3307 if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(i_spawnMode))
3308 return difficulty->Flags & DIFFICULTY_FLAG_DISPLAY_MYTHIC;
3309 return false;
3310}
3311
3313{
3315}
3316
3318{
3319 return IsHeroic() || IsMythic() || IsMythicPlus();
3320}
3321
3323{
3325}
3326
3328{
3330}
3331
3333{
3335}
3336
3338{
3339 return i_mapEntry && i_mapEntry->IsBattleArena();
3340}
3341
3343{
3345}
3346
3348{
3349 return i_mapEntry && i_mapEntry->IsScenario();
3350}
3351
3353{
3354 return i_mapEntry && i_mapEntry->IsGarrison();
3355}
3356
3358{
3359 return IsBattlegroundOrArena();
3360}
3361
3362bool Map::GetEntrancePos(int32 &mapid, float &x, float &y)
3363{
3364 if (!i_mapEntry)
3365 return false;
3366 return i_mapEntry->GetEntrancePos(mapid, x, y);
3367}
3368
3370{
3371 MapDifficultyEntry const* mapDiff = GetMapDifficulty();
3372 if (mapDiff && mapDiff->MaxPlayers)
3373 return mapDiff->MaxPlayers;
3374
3375 return GetEntry()->MaxPlayers;
3376}
3377
3379{
3380 if (sWorldStateMgr->GetValue(WS_TEAM_IN_INSTANCE_ALLIANCE, this))
3381 return TEAM_ALLIANCE;
3382 if (sWorldStateMgr->GetValue(WS_TEAM_IN_INSTANCE_HORDE, this))
3383 return TEAM_HORDE;
3384 return TEAM_NEUTRAL;
3385}
3386
3387/* ******* Battleground Instance Maps ******* */
3388
3389BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty spawnMode)
3390 : Map(id, expiry, InstanceId, spawnMode), m_bg(nullptr), _battlegroundScript(nullptr), _scriptId(0)
3391{
3392 //lets initialize visibility distance for BG/Arenas
3394}
3395
3397{
3398 if (m_bg)
3399 {
3400 //unlink to prevent crash, always unlink all pointer reference before destruction
3401 m_bg->SetBgMap(nullptr);
3402 m_bg = nullptr;
3403 }
3404}
3405
3407{
3408 //init visibility distance for BG/Arenas
3411}
3412
3413std::string const& BattlegroundMap::GetScriptName() const
3414{
3415 return sObjectMgr->GetScriptName(_scriptId);
3416}
3417
3419{
3421 return;
3422
3423 ASSERT(GetBG(), "Battleground not set yet!");
3424
3425 if (BattlegroundScriptTemplate const* scriptTemplate = sBattlegroundMgr->FindBattlegroundScriptTemplate(GetId(), GetBG()->GetTypeID()))
3426 {
3427 _scriptId = scriptTemplate->ScriptId;
3428 _battlegroundScript.reset(sScriptMgr->CreateBattlegroundData(this));
3429 }
3430
3431 // Make sure every battleground has a default script
3433 {
3434 if (IsBattleArena())
3435 _battlegroundScript = std::make_unique<ArenaScript>(this);
3436 else
3437 _battlegroundScript = std::make_unique<BattlegroundScript>(this);
3438 }
3439
3440 _battlegroundScript->OnInit();
3441}
3442
3444{
3445 if (player->GetMapRef().getTarget() == this)
3446 {
3447 TC_LOG_ERROR("maps", "BGMap::CannotEnter - player {} is already in map!", player->GetGUID().ToString());
3448 ABORT();
3449 return TRANSFER_ABORT_ERROR;
3450 }
3451
3452 if (player->GetBattlegroundId() != GetInstanceId())
3454
3455 // player number limit is checked in bgmgr, no need to do it here
3456
3457 return Map::CannotEnter(player);
3458}
3459
3460bool BattlegroundMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/)
3461{
3462 player->m_InstanceValid = true;
3463 return Map::AddPlayerToMap(player, initPlayer);
3464}
3465
3467{
3468 TC_LOG_DEBUG("maps", "MAP: Removing player '{}' from bg '{}' of map '{}' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName());
3469 Map::RemovePlayerFromMap(player, remove);
3470}
3471
3473{
3475}
3476
3478{
3479 if (HavePlayers())
3480 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
3481 if (Player* player = itr->GetSource())
3482 if (!player->IsBeingTeleportedFar())
3483 player->TeleportTo(player->GetBattlegroundEntryPoint());
3484}
3485
3487{
3488 Map::Update(diff);
3489 _battlegroundScript->OnUpdate(diff);
3490}
3491
3493{
3494 return _objectsStore.Find<AreaTrigger>(guid);
3495}
3496
3498{
3499 return _objectsStore.Find<SceneObject>(guid);
3500}
3501
3503{
3504 return _objectsStore.Find<Conversation>(guid);
3505}
3506
3508{
3509 return ObjectAccessor::GetPlayer(this, guid);
3510}
3511
3513{
3514 return _objectsStore.Find<Corpse>(guid);
3515}
3516
3518{
3519 return _objectsStore.Find<Creature>(guid);
3520}
3521
3523{
3524 return _objectsStore.Find<DynamicObject>(guid);
3525}
3526
3528{
3529 return _objectsStore.Find<GameObject>(guid);
3530}
3531
3533{
3534 return _objectsStore.Find<Pet>(guid);
3535}
3536
3538{
3539 if (!guid.IsMOTransport())
3540 return nullptr;
3541
3542 GameObject* go = GetGameObject(guid);
3543 return go ? go->ToTransport() : nullptr;
3544}
3545
3547{
3548 auto const bounds = GetCreatureBySpawnIdStore().equal_range(spawnId);
3549 if (bounds.first == bounds.second)
3550 return nullptr;
3551
3552 std::unordered_multimap<ObjectGuid::LowType, Creature*>::const_iterator creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
3553 {
3554 return pair.second->IsAlive();
3555 });
3556
3557 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
3558}
3559
3561{
3562 auto const bounds = GetGameObjectBySpawnIdStore().equal_range(spawnId);
3563 if (bounds.first == bounds.second)
3564 return nullptr;
3565
3566 std::unordered_multimap<ObjectGuid::LowType, GameObject*>::const_iterator creatureItr = std::find_if(bounds.first, bounds.second, [](Map::GameObjectBySpawnIdContainer::value_type const& pair)
3567 {
3568 return pair.second->isSpawned();
3569 });
3570
3571 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
3572}
3573
3575{
3576 auto const bounds = GetAreaTriggerBySpawnIdStore().equal_range(spawnId);
3577 if (bounds.first == bounds.second)
3578 return nullptr;
3579
3580 return bounds.first->second;
3581}
3582
3584{
3585 if (&*m_mapRefIter == &player->GetMapRef())
3586 m_mapRefIter = m_mapRefIter->nocheck_prev();
3587}
3588
3589void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans, bool startup)
3590{
3591 SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId);
3592 if (!data)
3593 {
3594 TC_LOG_ERROR("maps", "Map {} attempt to save respawn time for nonexistant spawnid ({},{}).", GetId(), type, spawnId);
3595 return;
3596 }
3597
3598 if (!respawnTime)
3599 {
3600 // Delete only
3601 RemoveRespawnTime(data->type, data->spawnId, dbTrans);
3602 return;
3603 }
3604
3605 RespawnInfo ri;
3606 ri.type = data->type;
3607 ri.spawnId = data->spawnId;
3608 ri.entry = entry;
3609 ri.respawnTime = respawnTime;
3610 ri.gridId = gridId;
3611 bool success = AddRespawnInfo(ri);
3612
3613 if (startup)
3614 {
3615 if (!success)
3616 TC_LOG_ERROR("maps", "Attempt to load saved respawn {} for ({},{}) failed - duplicate respawn? Skipped.", respawnTime, uint32(type), spawnId);
3617 }
3618 else if (success)
3619 SaveRespawnInfoDB(ri, dbTrans);
3620}
3621
3623{
3624 if (Instanceable())
3625 return;
3626
3628 stmt->setUInt16(0, info.type);
3629 stmt->setUInt64(1, info.spawnId);
3630 stmt->setInt64(2, info.respawnTime);
3631 stmt->setUInt16(3, GetId());
3632 stmt->setUInt32(4, GetInstanceId());
3633 CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
3634}
3635
3637{
3638 if (Instanceable())
3639 return;
3640
3642 stmt->setUInt16(0, GetId());
3643 stmt->setUInt32(1, GetInstanceId());
3644 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
3645 {
3646 do
3647 {
3648 Field* fields = result->Fetch();
3649 SpawnObjectType type = SpawnObjectType(fields[0].GetUInt16());
3650 ObjectGuid::LowType spawnId = fields[1].GetUInt64();
3651 time_t respawnTime = fields[2].GetInt64();
3652
3653 if (SpawnData::TypeHasData(type))
3654 {
3655 if (SpawnData const* data = sObjectMgr->GetSpawnData(type, spawnId))
3656 SaveRespawnTime(type, spawnId, data->id, time_t(respawnTime), Trinity::ComputeGridCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId(), nullptr, true);
3657 else
3658 TC_LOG_ERROR("maps", "Loading saved respawn time of {} for spawnid ({},{}) - spawn does not exist, ignoring", respawnTime, uint32(type), spawnId);
3659 }
3660 else
3661 {
3662 TC_LOG_ERROR("maps", "Loading saved respawn time of {} for spawnid ({},{}) - invalid spawn type, ignoring", respawnTime, uint32(type), spawnId);
3663 }
3664
3665 } while (result->NextRow());
3666 }
3667}
3668
3670{
3671 if (Instanceable())
3672 return;
3673
3675 stmt->setUInt16(0, GetId());
3676 stmt->setUInt32(1, GetInstanceId());
3677 CharacterDatabase.Execute(stmt);
3678}
3679
3681{
3682 ObjectGuid linkedGuid = sObjectMgr->GetLinkedRespawnGuid(guid);
3683 switch (linkedGuid.GetHigh())
3684 {
3685 case HighGuid::Creature:
3686 return GetCreatureRespawnTime(linkedGuid.GetCounter());
3688 return GetGORespawnTime(linkedGuid.GetCounter());
3689 default:
3690 break;
3691 }
3692
3693 return time_t(0);
3694}
3695
3697{
3699 stmt->setUInt32(0, GetId());
3700 stmt->setUInt32(1, GetInstanceId());
3701
3702 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3703 // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, race, class, gender, flags, dynFlags, time, corpseType, instanceId, guid FROM corpse WHERE mapId = ? AND instanceId = ?
3704 PreparedQueryResult result = CharacterDatabase.Query(stmt);
3705 if (!result)
3706 return;
3707
3708 std::unordered_map<ObjectGuid::LowType, std::unordered_set<uint32>> phases;
3709 std::unordered_map<ObjectGuid::LowType, std::vector<UF::ChrCustomizationChoice>> customizations;
3710
3711 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_PHASES);
3712 stmt->setUInt32(0, GetId());
3713 stmt->setUInt32(1, GetInstanceId());
3714
3715 // 0 1
3716 // SELECT OwnerGuid, PhaseId FROM corpse_phases cp LEFT JOIN corpse c ON cp.OwnerGuid = c.guid WHERE c.mapId = ? AND c.instanceId = ?
3717 if (PreparedQueryResult phaseResult = CharacterDatabase.Query(stmt))
3718 {
3719 do
3720 {
3721 Field* fields = phaseResult->Fetch();
3722 ObjectGuid::LowType guid = fields[0].GetUInt64();
3723 uint32 phaseId = fields[1].GetUInt32();
3724
3725 phases[guid].insert(phaseId);
3726
3727 } while (phaseResult->NextRow());
3728 }
3729
3730 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_CUSTOMIZATIONS);
3731 stmt->setUInt32(0, GetId());
3732 stmt->setUInt32(1, GetInstanceId());
3733
3734 // 0 1 2
3735 // SELECT cc.ownerGuid, cc.chrCustomizationOptionID, cc.chrCustomizationChoiceID FROM corpse_customizations cc LEFT JOIN corpse c ON cc.ownerGuid = c.guid WHERE c.mapId = ? AND c.instanceId = ?
3736 if (PreparedQueryResult customizationResult = CharacterDatabase.Query(stmt))
3737 {
3738 do
3739 {
3740 Field* fields = customizationResult->Fetch();
3741 ObjectGuid::LowType guid = fields[0].GetUInt64();
3742 std::vector<UF::ChrCustomizationChoice>& customizationsForCorpse = customizations[guid];
3743
3744 customizationsForCorpse.emplace_back();
3745 UF::ChrCustomizationChoice& choice = customizationsForCorpse.back();
3746 choice.ChrCustomizationOptionID = fields[1].GetUInt32();
3747 choice.ChrCustomizationChoiceID = fields[2].GetUInt32();
3748
3749 } while (customizationResult->NextRow());
3750 }
3751
3752 do
3753 {
3754 Field* fields = result->Fetch();
3755 CorpseType type = CorpseType(fields[13].GetUInt8());
3756 ObjectGuid::LowType guid = fields[15].GetUInt64();
3757 if (type >= MAX_CORPSE_TYPE || type == CORPSE_BONES)
3758 {
3759 TC_LOG_ERROR("misc", "Corpse (guid: {}) have wrong corpse type ({}), not loading.", guid, type);
3760 continue;
3761 }
3762
3763 Corpse* corpse = new Corpse(type);
3764 if (!corpse->LoadCorpseFromDB(GenerateLowGuid<HighGuid::Corpse>(), fields))
3765 {
3766 delete corpse;
3767 continue;
3768 }
3769
3770 for (uint32 phaseId : phases[guid])
3771 PhasingHandler::AddPhase(corpse, phaseId, false);
3772
3773 corpse->SetCustomizations(Trinity::Containers::MakeIteratorPair(customizations[guid].begin(), customizations[guid].end()));
3774
3775 AddCorpse(corpse);
3776
3777 } while (result->NextRow());
3778}
3779
3781{
3782 // DELETE cp, c FROM corpse_phases cp INNER JOIN corpse c ON cp.OwnerGuid = c.guid WHERE c.mapId = ? AND c.instanceId = ?
3784 stmt->setUInt32(0, GetId());
3785 stmt->setUInt32(1, GetInstanceId());
3786 CharacterDatabase.Execute(stmt);
3787}
3788
3790{
3791 corpse->SetMap(this);
3792
3793 _corpsesByCell[corpse->GetCellCoord().GetId()].insert(corpse);
3794 if (corpse->GetType() != CORPSE_BONES)
3795 _corpsesByPlayer[corpse->GetOwnerGUID()] = corpse;
3796 else
3797 _corpseBones.insert(corpse);
3798}
3799
3801{
3802 ASSERT(corpse);
3803
3805 if (corpse->IsInGrid())
3806 RemoveFromMap(corpse, false);
3807 else
3808 {
3809 corpse->RemoveFromWorld();
3810 corpse->ResetMap();
3811 }
3812
3813 _corpsesByCell[corpse->GetCellCoord().GetId()].erase(corpse);
3814 if (corpse->GetType() != CORPSE_BONES)
3815 _corpsesByPlayer.erase(corpse->GetOwnerGUID());
3816 else
3817 _corpseBones.erase(corpse);
3818}
3819
3820Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= false*/)
3821{
3822 Corpse* corpse = GetCorpseByPlayer(ownerGuid);
3823 if (!corpse)
3824 return nullptr;
3825
3826 RemoveCorpse(corpse);
3827
3828 // remove corpse from DB
3829 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3830 corpse->DeleteFromDB(trans);
3831 CharacterDatabase.CommitTransaction(trans);
3832
3833 Corpse* bones = nullptr;
3834
3835 // create the bones only if the map and the grid is loaded at the corpse's location
3836 // ignore bones creating option in case insignia
3837 if ((insignia ||
3839 !IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
3840 {
3841 // Create bones, don't change Corpse
3842 bones = new Corpse();
3843 bones->Create(corpse->GetGUID().GetCounter(), this);
3844
3846 bones->SetOwnerGUID(corpse->m_corpseData->Owner);
3847 bones->SetPartyGUID(corpse->m_corpseData->PartyGUID);
3848 bones->SetGuildGUID(corpse->m_corpseData->GuildGUID);
3849 bones->SetDisplayId(corpse->m_corpseData->DisplayID);
3850 bones->SetRace(corpse->m_corpseData->RaceID);
3851 bones->SetSex(corpse->m_corpseData->Sex);
3852 bones->SetClass(corpse->m_corpseData->Class);
3853 bones->SetCustomizations(Trinity::Containers::MakeIteratorPair(corpse->m_corpseData->Customizations.begin(), corpse->m_corpseData->Customizations.end()));
3854 bones->ReplaceAllFlags(corpse->m_corpseData->Flags | CORPSE_FLAG_BONES);
3855 bones->SetFactionTemplate(corpse->m_corpseData->FactionTemplate);
3856
3857 bones->SetCellCoord(corpse->GetCellCoord());
3858 bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
3859
3860 PhasingHandler::InheritPhaseShift(bones, corpse);
3861
3862 AddCorpse(bones);
3863
3864 bones->UpdatePositionData();
3865 bones->SetZoneScript();
3866
3867 // add bones in grid store if grid loaded where corpse placed
3868 AddToMap(bones);
3869 }
3870
3871 // all references to the corpse should be removed at this point
3872 delete corpse;
3873
3874 return bones;
3875}
3876
3878{
3879 time_t now = GameTime::GetGameTime();
3880
3881 std::vector<ObjectGuid> corpses;
3882 corpses.reserve(_corpsesByPlayer.size());
3883
3884 for (auto const& p : _corpsesByPlayer)
3885 if (p.second->IsExpired(now))
3886 corpses.push_back(p.first);
3887
3888 for (ObjectGuid const& ownerGuid : corpses)
3889 ConvertCorpseToBones(ownerGuid);
3890
3891 std::vector<Corpse*> expiredBones;
3892 for (Corpse* bones : _corpseBones)
3893 if (bones->IsExpired(now))
3894 expiredBones.push_back(bones);
3895
3896 for (Corpse* bones : expiredBones)
3897 {
3898 RemoveCorpse(bones);
3899 delete bones;
3900 }
3901}
3902
3903void Map::SendZoneDynamicInfo(uint32 zoneId, Player* player) const
3904{
3905 auto itr = _zoneDynamicInfo.find(zoneId);
3906 if (itr == _zoneDynamicInfo.end())
3907 return;
3908
3909 if (uint32 music = itr->second.MusicId)
3910 player->SendDirectMessage(WorldPackets::Misc::PlayMusic(music).Write());
3911
3912 SendZoneWeather(itr->second, player);
3913
3914 for (ZoneDynamicInfo::LightOverride const& lightOverride : itr->second.LightOverrides)
3915 {
3917 overrideLight.AreaLightID = lightOverride.AreaLightId;
3918 overrideLight.OverrideLightID = lightOverride.OverrideLightId;
3919 overrideLight.TransitionMilliseconds = lightOverride.TransitionMilliseconds;
3920 player->SendDirectMessage(overrideLight.Write());
3921 }
3922}
3923
3924void Map::SendZoneWeather(uint32 zoneId, Player* player) const
3925{
3927 {
3928 auto itr = _zoneDynamicInfo.find(zoneId);
3929 if (itr == _zoneDynamicInfo.end())
3930 return;
3931
3932 SendZoneWeather(itr->second, player);
3933 }
3934}
3935
3936void Map::SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const
3937{
3938 if (WeatherState weatherId = zoneDynamicInfo.WeatherId)
3939 {
3940 WorldPackets::Misc::Weather weather(weatherId, zoneDynamicInfo.Intensity);
3941 player->SendDirectMessage(weather.Write());
3942 }
3943 else if (zoneDynamicInfo.DefaultWeather)
3944 {
3945 zoneDynamicInfo.DefaultWeather->SendWeatherUpdateToPlayer(player);
3946 }
3947 else
3949}
3950
3951void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
3952{
3953 _zoneDynamicInfo[zoneId].MusicId = musicId;
3954
3955 Map::PlayerList const& players = GetPlayers();
3956 if (!players.isEmpty())
3957 {
3958 WorldPackets::Misc::PlayMusic playMusic(musicId);
3959 playMusic.Write();
3960
3961 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
3962 if (Player* player = itr->GetSource())
3963 if (player->GetZoneId() == zoneId && !player->HasAuraType(SPELL_AURA_FORCE_WEATHER))
3964 player->SendDirectMessage(playMusic.GetRawPacket());
3965 }
3966}
3967
3969{
3970 WeatherData const* weatherData = WeatherMgr::GetWeatherData(zoneId);
3971 if (!weatherData)
3972 return nullptr;
3973
3974 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
3975 if (!info.DefaultWeather)
3976 {
3977 info.DefaultWeather = std::make_unique<Weather>(zoneId, weatherData);
3978 info.DefaultWeather->ReGenerate();
3979 info.DefaultWeather->UpdateWeather();
3980 }
3981
3982 return info.DefaultWeather.get();
3983}
3984
3986{
3988 if (zoneDynamicInfo)
3989 {
3990 if (WeatherState weatherId = zoneDynamicInfo->WeatherId)
3991 return weatherId;
3992
3993 if (zoneDynamicInfo->DefaultWeather)
3994 return zoneDynamicInfo->DefaultWeather->GetWeatherState();
3995 }
3996
3997 return WEATHER_STATE_FINE;
3998}
3999
4000void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float intensity)
4001{
4002 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4003 info.WeatherId = weatherId;
4004 info.Intensity = intensity;
4005
4006 Map::PlayerList const& players = GetPlayers();
4007 if (!players.isEmpty())
4008 {
4009 WorldPackets::Misc::Weather weather(weatherId, intensity);
4010 weather.Write();
4011
4012 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
4013 if (Player* player = itr->GetSource())
4014 if (player->GetZoneId() == zoneId)
4015 player->SendDirectMessage(weather.GetRawPacket());
4016 }
4017}
4018
4019void Map::SetZoneOverrideLight(uint32 zoneId, uint32 areaLightId, uint32 overrideLightId, Milliseconds transitionTime)
4020{
4021 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4022 // client can support only one override for each light (zone independent)
4023 info.LightOverrides.erase(std::remove_if(info.LightOverrides.begin(), info.LightOverrides.end(), [areaLightId](ZoneDynamicInfo::LightOverride const& lightOverride)
4024 {
4025 return lightOverride.AreaLightId == areaLightId;
4026 }), info.LightOverrides.end());
4027
4028 // set new override (if any)
4029 if (overrideLightId)
4030 {
4031 ZoneDynamicInfo::LightOverride& lightOverride = info.LightOverrides.emplace_back();
4032 lightOverride.AreaLightId = areaLightId;
4033 lightOverride.OverrideLightId = overrideLightId;
4034 lightOverride.TransitionMilliseconds = static_cast<uint32>(transitionTime.count());
4035 }
4036
4037 Map::PlayerList const& players = GetPlayers();
4038 if (!players.isEmpty())
4039 {
4041 overrideLight.AreaLightID = areaLightId;
4042 overrideLight.OverrideLightID = overrideLightId;
4043 overrideLight.TransitionMilliseconds = static_cast<uint32>(transitionTime.count());
4044 overrideLight.Write();
4045
4046 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
4047 if (Player* player = itr->GetSource())
4048 if (player->GetZoneId() == zoneId)
4049 player->SendDirectMessage(overrideLight.GetRawPacket());
4050 }
4051}
4052
4054{
4055 Map::PlayerList const& players = GetPlayers();
4056 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
4057 {
4058 if (Player* player = itr->GetSource())
4059 {
4060 if (player->IsInWorld())
4061 {
4062 player->UpdateAreaDependentAuras(player->GetAreaId());
4063 player->UpdateZoneDependentAuras(player->GetZoneId());
4064 }
4065 }
4066 }
4067}
4068
4069std::string Map::GetDebugInfo() const
4070{
4071 std::stringstream sstr;
4072 sstr << std::boolalpha
4073 << "Id: " << GetId() << " InstanceId: " << GetInstanceId() << " Difficulty: " << std::to_string(GetDifficultyID())
4074 << " HasPlayers: " << HavePlayers();
4075 return sstr.str();
4076}
4077
4078std::string InstanceMap::GetDebugInfo() const
4079{
4080 std::stringstream sstr;
4081 sstr << Map::GetDebugInfo() << "\n"
4082 << std::boolalpha
4083 << "ScriptId: " << GetScriptId() << " ScriptName: " << GetScriptName();
4084 return sstr.str();
4085}
4086
#define sBattlegroundMgr
@ CHAR_SEL_CORPSE_CUSTOMIZATIONS
@ CHAR_DEL_ALL_RESPAWNS
@ CHAR_REP_RESPAWN
@ CHAR_SEL_CORPSE_PHASES
@ CHAR_DEL_RESPAWN
@ CHAR_SEL_CORPSES
@ CHAR_DEL_CORPSES_FROM_MAP
@ CHAR_SEL_RESPAWNS
@ IN_MILLISECONDS
Definition: Common.h:35
@ WEEK
Definition: Common.h:32
#define sConditionMgr
Definition: ConditionMgr.h:367
@ CONDITION_SOURCE_TYPE_SPAWN_GROUP
Definition: ConditionMgr.h:187
CorpseType
Definition: Corpse.h:30
@ CORPSE_BONES
Definition: Corpse.h:31
@ CORPSE_FLAG_BONES
Definition: Corpse.h:43
#define MAX_CORPSE_TYPE
Definition: Corpse.h:35
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:553
Difficulty
Definition: DBCEnums.h:918
@ DIFFICULTY_25_HC
Definition: DBCEnums.h:925
@ DIFFICULTY_NORMAL_RAID
Definition: DBCEnums.h:931
@ DIFFICULTY_NORMAL
Definition: DBCEnums.h:920
@ DIFFICULTY_LFR_15TH_ANNIVERSARY
Definition: DBCEnums.h:954
@ DIFFICULTY_HEROIC
Definition: DBCEnums.h:921
@ DIFFICULTY_MYTHIC_KEYSTONE
Definition: DBCEnums.h:927
@ DIFFICULTY_3_MAN_SCENARIO_HC
Definition: DBCEnums.h:929
@ DIFFICULTY_TIMEWALKING_RAID
Definition: DBCEnums.h:946
@ DIFFICULTY_TIMEWALKING
Definition: DBCEnums.h:939
@ DIFFICULTY_10_N
Definition: DBCEnums.h:922
@ DIFFICULTY_25_N
Definition: DBCEnums.h:923
@ DIFFICULTY_NORMAL_WARFRONT
Definition: DBCEnums.h:952
@ DIFFICULTY_NORMAL_ISLAND
Definition: DBCEnums.h:948
@ DIFFICULTY_LFR_NEW
Definition: DBCEnums.h:934
@ DIFFICULTY_10_HC
Definition: DBCEnums.h:924
@ DIFFICULTY_LFR
Definition: DBCEnums.h:926
@ DIFFICULTY_FLAG_DISPLAY_MYTHIC
Definition: DBCEnums.h:968
@ DIFFICULTY_FLAG_DISPLAY_HEROIC
Definition: DBCEnums.h:967
@ IgnoreInstanceFarmLimit
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
#define UI64FMTD
Definition: Define.h:126
#define TC_GAME_API
Definition: Define.h:123
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
std::unordered_set< uint32 > params[2]
Definition: DisableMgr.cpp:50
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ABORT_MSG
Definition: Errors.h:75
#define ABORT
Definition: Errors.h:74
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
#define MAX_NUMBER_OF_CELLS
Definition: GridDefines.h:36
#define TOTAL_NUMBER_OF_CELLS_PER_MAP
Definition: GridDefines.h:53
#define SIZE_OF_GRIDS
Definition: GridDefines.h:40
CoordPair< MAX_NUMBER_OF_GRIDS > GridCoord
Definition: GridDefines.h:177
#define MAX_NUMBER_OF_GRIDS
Definition: GridDefines.h:38
#define CENTER_GRID_CELL_ID
Definition: GridDefines.h:50
#define SIZE_OF_GRID_CELL
Definition: GridDefines.h:48
#define CENTER_GRID_ID
Definition: GridDefines.h:41
#define CENTER_GRID_OFFSET
Definition: GridDefines.h:43
NGrid< MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes > NGridType
Definition: GridDefines.h:99
#define sInstanceLockMgr
@ LOG_LEVEL_DEBUG
Definition: LogCommon.h:28
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition: Log.h:179
#define TC_LOG_ERROR(filterType__, message__,...)
Definition: Log.h:188
#define sLog
Definition: Log.h:154
#define TC_LOG_WARN(filterType__, message__,...)
Definition: Log.h:185
ZLiquidStatus
Definition: MapDefines.h:125
#define sMapMgr
Definition: MapManager.h:184
@ MAP_OBJECT_CELL_MOVE_INACTIVE
Definition: MapObject.h:32
@ MAP_OBJECT_CELL_MOVE_ACTIVE
Definition: MapObject.h:31
@ MAP_OBJECT_CELL_MOVE_NONE
Definition: MapObject.h:30
static void PushRespawnInfoFrom(std::vector< RespawnInfo const * > &data, RespawnInfoMap const &map)
Definition: Map.cpp:2127
GridState * si_GridStates[MAX_GRID_STATE]
Definition: Map.cpp:72
#define MIN_UNLOAD_DELAY
Definition: Map.h:153
InstanceResetMethod
Definition: Map.h:846
std::unordered_map< ObjectGuid::LowType, RespawnInfo * > RespawnInfoMap
Definition: Map.h:163
InstanceResetResult
Definition: Map.h:853
#define MAP_INVALID_ZONE
Definition: Map.h:154
TransferAbortReason
Definition: Map.h:87
@ TRANSFER_ABORT_TOO_MANY_INSTANCES
Definition: Map.h:92
@ TRANSFER_ABORT_DIFFICULTY
Definition: Map.h:95
@ TRANSFER_ABORT_MAP_NOT_ALLOWED
Definition: Map.h:103
@ TRANSFER_ABORT_MAX_PLAYERS
Definition: Map.h:90
@ TRANSFER_ABORT_ZONE_IN_COMBAT
Definition: Map.h:93
@ TRANSFER_ABORT_NONE
Definition: Map.h:88
@ TRANSFER_ABORT_LOCKED_TO_DIFFERENT_INSTANCE
Definition: Map.h:104
@ TRANSFER_ABORT_NEED_GROUP
Definition: Map.h:98
@ TRANSFER_ABORT_ERROR
Definition: Map.h:89
#define TC_METRIC_VALUE(category, value,...)
Definition: Metric.h:214
#define TC_METRIC_TAG(name, value)
Definition: Metric.h:180
@ GRID_STATE_REMOVAL
Definition: NGrid.h:58
@ GRID_STATE_INVALID
Definition: NGrid.h:55
@ GRID_STATE_IDLE
Definition: NGrid.h:57
@ GRID_STATE_ACTIVE
Definition: NGrid.h:56
@ MAX_GRID_STATE
Definition: NGrid.h:59
#define DEFAULT_VISIBILITY_NOTIFY_PERIOD
Definition: NGrid.h:28
#define MAX_VISIBILITY_DISTANCE
Definition: ObjectDefines.h:28
#define DEFAULT_VISIBILITY_DISTANCE
Definition: ObjectDefines.h:35
@ TYPEID_AREATRIGGER
Definition: ObjectGuid.h:47
@ TYPEID_DYNAMICOBJECT
Definition: ObjectGuid.h:45
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:44
@ TYPEID_UNIT
Definition: ObjectGuid.h:41
@ TYPEID_CORPSE
Definition: ObjectGuid.h:46
@ TYPEID_CONVERSATION
Definition: ObjectGuid.h:49
@ TYPEID_PLAYER
Definition: ObjectGuid.h:42
HighGuid
Definition: ObjectGuid.h:76
#define sObjectMgr
Definition: ObjectMgr.h:1979
std::unordered_map< Player *, UpdateData > UpdateDataMapType
Definition: Object.h:79
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ PET_SAVE_NOT_IN_SLOT
Definition: PetDefines.h:48
@ RAID_INSTANCE_EXPIRED
Definition: Player.h:821
#define sPoolMgr
Definition: PoolMgr.h:179
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
#define sScriptMgr
Definition: ScriptMgr.h:1418
TeamId
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
LineOfSightChecks
@ LINEOFSIGHT_CHECK_VMAP
@ LINEOFSIGHT_CHECK_GOBJECT
@ WS_TEAM_IN_INSTANCE_ALLIANCE
@ WS_TEAM_IN_INSTANCE_HORDE
@ SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE
Definition: SpawnData.h:57
@ SPAWNGROUP_FLAG_MANUAL_SPAWN
Definition: SpawnData.h:56
@ SPAWNGROUP_FLAG_DESPAWN_ON_CONDITION_FAILURE
Definition: SpawnData.h:59
@ SPAWNGROUP_FLAG_SYSTEM
Definition: SpawnData.h:54
@ SPAWNGROUP_FLAG_ESCORTQUESTNPC
Definition: SpawnData.h:58
SpawnObjectTypeMask
Definition: SpawnData.h:42
@ SPAWN_TYPEMASK_CREATURE
Definition: SpawnData.h:43
@ SPAWN_TYPEMASK_GAMEOBJECT
Definition: SpawnData.h:44
SpawnObjectType
Definition: SpawnData.h:33
@ SPAWN_TYPE_GAMEOBJECT
Definition: SpawnData.h:35
@ SPAWN_TYPE_AREATRIGGER
Definition: SpawnData.h:36
@ SPAWN_TYPE_CREATURE
Definition: SpawnData.h:34
@ SPELL_AURA_FORCE_WEATHER
#define sTerrainMgr
Definition: TerrainMgr.h:165
#define sTransportMgr
Definition: TransportMgr.h:183
#define sWorldStateMgr
Definition: WorldStateMgr.h:50
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
void UpdateShape()
TransferAbortParams CannotEnter(Player *player) override
Definition: Map.cpp:3443
BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Difficulty spawnMode)
Definition: Map.cpp:3389
~BattlegroundMap()
Definition: Map.cpp:3396
void SetUnload()
Definition: Map.cpp:3472
void RemoveAllPlayers() override
Definition: Map.cpp:3477
std::unique_ptr< BattlegroundScript > _battlegroundScript
Definition: Map.h:927
Battleground * GetBG() const
Definition: Map.h:916
void InitScriptData()
Definition: Map.cpp:3418
std::string const & GetScriptName() const
Definition: Map.cpp:3413
bool AddPlayerToMap(Player *player, bool initPlayer=true) override
Definition: Map.cpp:3460
Battleground * m_bg
Definition: Map.h:926
void RemovePlayerFromMap(Player *, bool) override
Definition: Map.cpp:3466
virtual void InitVisibilityDistance() override
Definition: Map.cpp:3406
uint32 _scriptId
Definition: Map.h:928
void Update(uint32 diff) override
Definition: Map.cpp:3486
void SetBgMap(BattlegroundMap *map)
void clear()
Definition: ByteBuffer.h:127
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
Definition: Corpse.h:53
void ReplaceAllFlags(uint32 flags)
Definition: Corpse.h:106
void SetRace(uint8 race)
Definition: Corpse.h:103
void SetClass(uint8 playerClass)
Definition: Corpse.h:104
void SetSex(uint8 sex)
Definition: Corpse.h:105
void SetGuildGUID(ObjectGuid guildGuid)
Definition: Corpse.h:101
void SetDisplayId(uint32 displayId)
Definition: Corpse.h:102
void SetCustomizations(Trinity::IteratorPair< Iter > customizations)
Definition: Corpse.h:113
CorpseDynFlags GetCorpseDynamicFlags() const
Definition: Corpse.h:92
void SetFactionTemplate(int32 factionTemplate)
Definition: Corpse.h:107
void RemoveFromWorld() override
Definition: Corpse.cpp:56
void SetOwnerGUID(ObjectGuid owner)
Definition: Corpse.h:99
void SetPartyGUID(ObjectGuid partyGuid)
Definition: Corpse.h:100
UF::UpdateField< UF::CorpseData, 0, TYPEID_CORPSE > m_corpseData
Definition: Corpse.h:138
CellCoord const & GetCellCoord() const
Definition: Corpse.h:128
void ReplaceAllCorpseDynamicFlags(CorpseDynFlags dynamicFlags)
Definition: Corpse.h:95
ObjectGuid GetOwnerGUID() const override
Definition: Corpse.h:98
bool LoadCorpseFromDB(ObjectGuid::LowType guid, Field *fields)
Definition: Corpse.cpp:181
void SetCellCoord(CellCoord const &cellCoord)
Definition: Corpse.h:129
bool Create(ObjectGuid::LowType guidlow, Map *map)
Definition: Corpse.cpp:65
CorpseType GetType() const
Definition: Corpse.h:126
void DeleteFromDB(CharacterDatabaseTransaction trans)
Definition: Corpse.cpp:156
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr, float *dist=nullptr) const
Definition: Creature.cpp:2872
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
Definition: Creature.cpp:1828
bool IsEscorted() const
Definition: Creature.cpp:3696
bool m_isTempWorldObject
Definition: Creature.h:410
bool isInLineOfSight(G3D::Vector3 const &startPos, G3D::Vector3 const &endPos, PhaseShift const &phaseShift) const
bool getObjectHitPos(G3D::Vector3 const &startPos, G3D::Vector3 const &endPos, G3D::Vector3 &resultHitPos, float modifyDist, PhaseShift const &phaseShift) const
void update(uint32 diff)
Class used to access individual fields of database query result.
Definition: Field.h:92
int64 GetInt64() const
Definition: Field.cpp:85
uint64 GetUInt64() const
Definition: Field.cpp:77
uint32 GetUInt32() const
Definition: Field.cpp:61
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr) const
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool=true)
void RemoveFromWorld() override
Definition: GameObject.cpp:954
ObjectGuid::LowType GetSpawnId() const
Definition: GameObject.h:212
void AfterRelocation()
Transport * ToTransport()
Definition: GameObject.h:400
void AddToWorld() override
Definition: GameObject.cpp:927
Definition: NGrid.h:31
PeriodicTimer & getRelocationTimer()
Definition: NGrid.h:44
void RemoveFromGrid()
Definition: GridObject.h:32
bool IsInGrid() const
Definition: GridObject.h:30
virtual void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const =0
Definition: Grid.h:46
void AddWorldObject(SPECIFIC_OBJECT *obj)
Definition: Grid.h:58
void AddGridObject(SPECIFIC_OBJECT *obj)
Definition: Grid.h:111
Definition: Group.h:205
bool isRaidGroup() const
Definition: Group.cpp:1640
virtual InstanceLockData const * GetInstanceInitializationData() const
bool IsExtended() const
void SetInUse(bool inUse)
InstanceResetTimePoint GetExpiryTime() const
bool IsNew() const
bool IsExpired() const
InstanceLockData * GetData()
Optional< SystemTimePoint > i_instanceExpireEvent
Definition: Map.h:893
InstanceLock * i_instanceLock
Definition: Map.h:897
TransferAbortParams CannotEnter(Player *player) override
Definition: Map.cpp:2871
void Update(uint32) override
Definition: Map.cpp:2952
InstanceResetResult Reset(InstanceResetMethod method)
Definition: Map.cpp:3037
TeamId GetTeamIdInInstance() const
Definition: Map.cpp:3378
InstanceScenario * i_scenario
Definition: Map.h:896
void TrySetOwningGroup(Group *group)
Definition: Map.cpp:3028
void CreateInstanceLockForPlayer(Player *player)
Definition: Map.cpp:3201
InstanceMap(uint32 id, time_t, uint32 InstanceId, Difficulty SpawnMode, TeamId InstanceTeam, InstanceLock *instanceLock)
Definition: Map.cpp:2831
uint32 GetMaxPlayers() const
Definition: Map.cpp:3369
virtual void InitVisibilityDistance() override
Definition: Map.cpp:2861
uint32 GetScriptId() const
Definition: Map.h:869
void RemovePlayerFromMap(Player *, bool) override
Definition: Map.cpp:2972
GroupInstanceReference i_owningGroupRef
Definition: Map.h:898
bool AddPlayerToMap(Player *player, bool initPlayer=true) override
Definition: Map.cpp:2910
InstanceScript * i_data
Definition: Map.h:894
std::string const & GetScriptName() const
Definition: Map.cpp:3100
std::string GetDebugInfo() const override
Definition: Map.cpp:4078
void CreateInstanceData()
Definition: Map.cpp:2989
uint32 i_script_id
Definition: Map.h:895
InstanceScript * GetInstanceScript()
Definition: Map.h:871
void UpdateInstanceLock(UpdateBossStateSaveDataEvent const &updateSaveDataEvent)
Definition: Map.cpp:3105
~InstanceMap()
Definition: Map.cpp:2852
std::string GetSaveData()
Optional< uint32 > GetEntranceLocationForCompletedEncounters(uint32 completedEncountersMask) const
void Load(char const *data)
virtual void OnPlayerLeave(Player *)
void UpdateCombatResurrection(uint32 diff)
virtual void Create()
void SetEntranceLocation(uint32 worldSafeLocationId)
std::string UpdateAdditionalSaveData(std::string const &oldData, UpdateAdditionalSaveDataEvent const &event)
virtual void OnPlayerEnter(Player *)
virtual void Update(uint32)
std::string UpdateBossStateSaveData(std::string const &oldData, UpdateBossStateSaveDataEvent const &event)
bool isEmpty() const
Definition: LinkedList.h:110
uint32 getSize() const
Definition: LinkedList.h:128
void SetCurrentCell(Cell const &cell)
Definition: MapObject.h:49
MapObjectCellMoveState _moveState
Definition: MapObject.h:51
Position _newPosition
Definition: MapObject.h:52
void SetNewCellPosition(float x, float y, float z, float o)
Definition: MapObject.h:53
Cell const & GetCurrentCell() const
Definition: MapObject.h:48
Definition: Map.h:190
MapEntry const * i_mapEntry
Definition: Map.h:610
void DynamicObjectRelocation(DynamicObject *go, float x, float y, float z, float orientation)
Definition: Map.cpp:1143
bool _creatureToMoveLock
Definition: Map.h:574
std::map< WorldObject *, bool > i_objectsToSwitch
Definition: Map.h:658
WorldObject * GetWorldObjectBySpawnId(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition: Map.h:408
std::unordered_map< uint32, uint32 > _zonePlayerCountMap
Definition: Map.h:790
std::vector< Creature * > _creaturesToMove
Definition: Map.h:575
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition: Map.cpp:2549
void GameObjectRelocation(GameObject *go, float x, float y, float z, float orientation, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1114
void AddGameObjectToMoveList(GameObject *go, float x, float y, float z, float ang)
Definition: Map.cpp:1222
void RemoveDynamicObjectFromMoveList(DynamicObject *go)
Definition: Map.cpp:1251
bool IsDungeon() const
Definition: Map.cpp:3240
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1082
ZLiquidStatus GetLiquidStatus(PhaseShift const &phaseShift, float x, float y, float z, Optional< map_liquidHeaderTypeFlags > ReqLiquidType={}, LiquidData *data=nullptr, float collisionHeight=2.03128f)
Definition: Map.cpp:1728
void SetZoneMusic(uint32 zoneId, uint32 musicId)
Definition: Map.cpp:3951
bool IsBattlegroundOrArena() const
Definition: Map.cpp:3342
void RemoveInfiniteAOIVignette(Vignettes::VignetteData *vignette)
Definition: Map.cpp:517
bool UnloadGrid(NGridType &ngrid, bool pForce)
Definition: Map.cpp:1601
void SetSpawnGroupInactive(uint32 groupId)
Definition: Map.h:714
std::unordered_map< ObjectGuid, Corpse * > _corpsesByPlayer
Definition: Map.h:804
void UpdateSpawnGroupConditions()
Definition: Map.cpp:2506
void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float intensity)
Definition: Map.cpp:4000
Pet * GetPet(ObjectGuid const &guid)
Definition: Map.cpp:3532
MapStoredObjectTypesContainer & GetObjectsStore()
Definition: Map.h:423
TransportsContainer::iterator _transportsUpdateIter
Definition: Map.h:630
bool IsNormal() const
Definition: Map.cpp:3268
void InitializeObject(T *obj)
Definition: Map.cpp:537
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition: Map.cpp:2350
void SwitchGridContainers(T *obj, bool on)
Definition: Map.cpp:251
void AddObjectToRemoveList(WorldObject *obj)
Definition: Map.cpp:2582
void SendZoneWeather(uint32 zoneId, Player *player) const
Definition: Map.cpp:3924
virtual void RemovePlayerFromMap(Player *, bool)
Definition: Map.cpp:947
virtual bool AddPlayerToMap(Player *player, bool initPlayer=true)
Definition: Map.cpp:417
void MoveAllGameObjectsInMoveList()
Definition: Map.cpp:1336
Creature * GetCreatureBySpawnId(ObjectGuid::LowType spawnId) const
Definition: Map.cpp:3546
void RemoveAreaTriggerFromMoveList(AreaTrigger *at)
Definition: Map.cpp:1270
void RemoveFromActiveHelper(WorldObject *obj)
Definition: Map.h:738
void DeleteRespawnInfoFromDB(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr)
Definition: Map.cpp:2187
size_t DespawnAll(SpawnObjectType type, ObjectGuid::LowType spawnId)
Definition: Map.cpp:2069
void AddAreaTriggerToMoveList(AreaTrigger *at, float x, float y, float z, float ang)
Definition: Map.cpp:1260
std::function< void(Map *)> FarSpellCallback
Definition: Map.h:719
void SetSpawnGroupActive(uint32 groupId, bool state)
Definition: Map.cpp:2462
void LoadGrid(float x, float y)
Definition: Map.cpp:407
bool IsUnderWater(PhaseShift const &phaseShift, float x, float y, float z)
Definition: Map.cpp:1774
void SendZoneDynamicInfo(uint32 zoneId, Player *player) const
Definition: Map.cpp:3903
void RemoveFromActive(WorldObject *obj)
Definition: Map.cpp:2774
MapDifficultyEntry const * GetMapDifficulty() const
Definition: Map.cpp:3225
PeriodicTimer _vignetteUpdateTimer
Definition: Map.h:842
bool AddToMap(T *)
Definition: Map.cpp:552
void DeleteCorpseData()
Definition: Map.cpp:3780
void AddInfiniteAOIVignette(Vignettes::VignetteData *vignette)
Definition: Map.cpp:504
RespawnInfoMap * GetRespawnMapForType(SpawnObjectType type)
Definition: Map.h:757
void EnsureGridCreated(GridCoord const &)
Definition: Map.cpp:315
virtual TransferAbortParams CannotEnter(Player *)
Definition: Map.h:321
void RemoveUpdateObject(Object *obj)
Definition: Map.h:538
RespawnInfoMap _gameObjectRespawnTimesBySpawnId
Definition: Map.h:756
NGridType * i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
Definition: Map.h:649
void UpdatePersonalPhasesForPlayer(Player const *player)
Definition: Map.cpp:456
void ProcessRespawns()
Definition: Map.cpp:2226
Weather * GetOrGenerateZoneDefaultWeather(uint32 zoneId)
Definition: Map.cpp:3968
uint32 m_unloadTimer
Definition: Map.h:614
virtual void DelayedUpdate(uint32 diff)
Definition: Map.cpp:2554
Player * GetPlayer(ObjectGuid const &guid)
Definition: Map.cpp:3507
AreaTriggerBySpawnIdContainer & GetAreaTriggerBySpawnIdStore()
Definition: Map.h:434
bool IsLFR() const
Definition: Map.cpp:3255
bool isInLineOfSight(PhaseShift const &phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition: Map.cpp:1784
bool IsNonRaidDungeon() const
Definition: Map.cpp:3245
time_t GetLinkedRespawnTime(ObjectGuid guid) const
Definition: Map.cpp:3680
void AddCorpse(Corpse *corpse)
Definition: Map.cpp:3789
bool IsBattleground() const
Definition: Map.cpp:3332
void UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone)
Definition: Map.cpp:673
WorldStateValueContainer _worldStateValues
Definition: Map.h:830
IntervalTimer _weatherUpdateTimer
Definition: Map.h:793
bool CheckRespawn(RespawnInfo *info)
Definition: Map.cpp:1989
bool IsRaid() const
Definition: Map.cpp:3250
void ProcessRelocationNotifies(const uint32 diff)
Definition: Map.cpp:870
void UnloadAllRespawnInfos()
Definition: Map.cpp:2153
void UnloadAll()
Definition: Map.cpp:1686
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr, bool alwaysDeleteFromDB=false)
Definition: Map.h:688
bool GetEntrancePos(int32 &mapid, float &x, float &y)
Definition: Map.cpp:3362
bool _dynamicObjectsToMoveLock
Definition: Map.h:580
NGridType * getNGrid(uint3