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