TrinityCore
Loading...
Searching...
No Matches
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 "ChatPackets.h"
22#include "DatabaseEnv.h"
23#include "DisableMgr.h"
24#include "DynamicTree.h"
25#include "GameObjectModel.h"
26#include "GameTime.h"
27#include "GridNotifiers.h"
28#include "GridNotifiersImpl.h"
29#include "GridStates.h"
30#include "Group.h"
31#include "InstanceScript.h"
32#include "Log.h"
33#include "MapInstanced.h"
34#include "MapManager.h"
35#include "Metric.h"
36#include "MiscPackets.h"
37#include "MMapFactory.h"
38#include "MotionMaster.h"
39#include "ObjectAccessor.h"
40#include "ObjectGridLoader.h"
41#include "ObjectMgr.h"
42#include "Pet.h"
43#include "PoolMgr.h"
44#include "ScriptMgr.h"
45#include "Transport.h"
46#include "Vehicle.h"
47#include "VMapFactory.h"
48#include "VMapManager2.h"
49#include "Weather.h"
50#include "WeatherMgr.h"
51#include "World.h"
52#include <boost/heap/fibonacci_heap.hpp>
53#include <unordered_set>
54#include <vector>
55
56u_map_magic MapMagic = { {'M','A','P','S'} };
58u_map_magic MapAreaMagic = { {'A','R','E','A'} };
59u_map_magic MapHeightMagic = { {'M','H','G','T'} };
60u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
61
62static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
63static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
64
65#define DEFAULT_GRID_EXPIRY 300
66#define MAX_GRID_LOAD_TIME 50
67#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld->getRate(RATE_CREATURE_AGGRO))
68
70
71ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), DefaultWeather(nullptr), WeatherId(WEATHER_STATE_FINE),
72 Intensity(0.0f) { }
73
75
77struct RespawnListContainer : boost::heap::fibonacci_heap<RespawnInfoWithHandle*, boost::heap::compare<CompareRespawnInfo>>
78{
79};
80
82{
83 explicit RespawnInfoWithHandle(RespawnInfo const& other) : RespawnInfo(other) { }
84
85 RespawnListContainer::handle_type handle;
86};
87
89{
90 // Delete all waiting spawns, else there will be a memory leak
91 // This doesn't delete from database.
93
94 while (!i_worldObjects.empty())
95 {
96 WorldObject* obj = *i_worldObjects.begin();
98 //ASSERT(obj->GetTypeId() == TYPEID_CORPSE);
99 obj->RemoveFromWorld();
100 obj->ResetMap();
101 }
102
103 if (!m_scriptSchedule.empty())
104 sMapMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
105
107}
108
109bool Map::ExistMap(uint32 mapid, int gx, int gy)
110{
111 std::string fileName = Trinity::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), mapid, gx, gy);
112
113 bool ret = false;
114 FILE* pf = fopen(fileName.c_str(), "rb");
115
116 if (!pf)
117 {
118 TC_LOG_ERROR("maps", "Map file '{}' does not exist!", fileName);
119 TC_LOG_ERROR("maps", "Please place MAP-files (*.map) in the appropriate directory ({}), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath()+"maps/"));
120 }
121 else
122 {
123 map_fileheader header;
124 if (fread(&header, sizeof(header), 1, pf) == 1)
125 {
126 if (header.mapMagic.asUInt != MapMagic.asUInt || header.versionMagic != MapVersionMagic)
127 TC_LOG_ERROR("maps", "Map file '{}' is from an incompatible map version (%.*s v{}), %.*s v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.",
128 fileName, 4, header.mapMagic.asChar, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic);
129 else
130 ret = true;
131 }
132 fclose(pf);
133 }
134
135 return ret;
136}
137
138bool Map::ExistVMap(uint32 mapid, int gx, int gy)
139{
141 {
142 if (vmgr->isMapLoadingEnabled())
143 {
144 VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy);
145 std::string name = vmgr->getDirFileName(mapid, gx, gy);
146 switch (result)
147 {
149 break;
151 TC_LOG_ERROR("maps", "VMap file '{}' does not exist", (sWorld->GetDataPath() + "vmaps/" + name));
152 TC_LOG_ERROR("maps", "Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory ({}), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "vmaps/"));
153 return false;
155 TC_LOG_ERROR("maps", "VMap file '{}' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name));
156 TC_LOG_ERROR("maps", "This is because the version of the VMap file and the version of this module are different, please re-extract the maps with the tools compiled with this module.");
157 return false;
158 }
159 }
160 }
161
162 return true;
163}
164
165void Map::LoadMMap(int gx, int gy)
166{
168 return;
169
170 bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap(sWorld->GetDataPath(), GetId(), gx, gy);
171
172 if (mmapLoadResult)
173 TC_LOG_DEBUG("mmaps.tiles", "MMAP loaded name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy);
174 else
175 TC_LOG_WARN("mmaps.tiles", "Could not load MMAP name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy);
176}
177
178void Map::LoadVMap(int gx, int gy)
179{
180 if (!VMAP::VMapFactory::createOrGetVMapManager()->isMapLoadingEnabled())
181 return;
182 // x and y are swapped !!
183 int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld->GetDataPath()+ "vmaps").c_str(), GetId(), gx, gy);
184 switch (vmapLoadResult)
185 {
187 TC_LOG_DEBUG("maps", "VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy);
188 break;
190 TC_LOG_ERROR("maps", "Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy);
191 break;
193 TC_LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy);
194 break;
195 }
196}
197
198void Map::LoadMap(int gx, int gy, bool reload)
199{
200 if (i_InstanceId != 0)
201 {
202 if (GridMaps[gx][gy])
203 return;
204
205 // load grid map for base map
206 if (!m_parentMap->GridMaps[gx][gy])
208
209 ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridCoord(gx, gy));
210 GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy];
211 return;
212 }
213
214 if (GridMaps[gx][gy] && !reload)
215 return;
216
217 //map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
218 if (GridMaps[gx][gy])
219 {
220 TC_LOG_DEBUG("maps", "Unloading previously loaded map {} before reloading.", GetId());
221 sScriptMgr->OnUnloadGridMap(this, GridMaps[gx][gy], gx, gy);
222
223 delete (GridMaps[gx][gy]);
224 GridMaps[gx][gy]=nullptr;
225 }
226
227 // map file name
228 std::string fileName = Trinity::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), GetId(), gx, gy);
229 TC_LOG_DEBUG("maps", "Loading map {}", fileName);
230 // loading data
231 GridMaps[gx][gy] = new GridMap();
232 if (!GridMaps[gx][gy]->loadData(fileName.c_str()))
233 TC_LOG_ERROR("maps", "Error loading map file: \n {}\n", fileName);
234
235 sScriptMgr->OnLoadGridMap(this, GridMaps[gx][gy], gx, gy);
236}
237
238void Map::LoadMapAndVMap(int gx, int gy)
239{
240 LoadMap(gx, gy);
241 // Only load the data for the base map
242 if (i_InstanceId == 0)
243 {
244 LoadVMap(gx, gy);
245 LoadMMap(gx, gy);
246 }
247}
248
250{
251 for (uint32 cellX = 0; cellX < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellX++)
252 for (uint32 cellY = 0; cellY < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellY++)
254}
255
263
271
272Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent):
273_creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false),
274i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
275m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
276m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD),
277m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()),
278i_gridExpiry(expiry),
279i_scriptLock(false), _respawnTimes(std::make_unique<RespawnListContainer>()), _respawnCheckTimer(0)
280{
281 m_parentMap = (_parent ? _parent : this);
282 for (unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
283 {
284 for (unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j)
285 {
286 //z code
287 GridMaps[idx][j] =nullptr;
288 setNGrid(nullptr, idx, j);
289 }
290 }
291
292 _zonePlayerCountMap.clear();
293
294 //lets initialize visibility distance for map
296
298
300}
301
308
309// Template specialization of utility methods
310template<class T>
311void Map::AddToGrid(T* obj, Cell const& cell)
312{
313 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
314 if (obj->IsStoredInWorldObjectGridContainer())
315 grid->GetGridType(cell.CellX(), cell.CellY()).template AddWorldObject<T>(obj);
316 else
317 grid->GetGridType(cell.CellX(), cell.CellY()).template AddGridObject<T>(obj);
318}
319
320template<>
321void Map::AddToGrid(Creature* obj, Cell const& cell)
322{
323 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
325 grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj);
326 else
327 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
328
329 obj->SetCurrentCell(cell);
330}
331
332template<>
333void Map::AddToGrid(GameObject* obj, Cell const& cell)
334{
335 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
336 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
337
338 obj->SetCurrentCell(cell);
339}
340
341template<>
342void Map::AddToGrid(DynamicObject* obj, Cell const& cell)
343{
344 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
346 grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj);
347 else
348 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
349
350 obj->SetCurrentCell(cell);
351}
352
353template<>
354void Map::AddToGrid(Corpse* obj, Cell const& cell)
355{
356 NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
357 // Corpses are a special object type - they can be added to grid via a call to AddToMap
358 // or loaded through ObjectGridLoader.
359 // Both corpses loaded from database and these freshly generated by Player::CreateCoprse are added to _corpsesByCell
360 // ObjectGridLoader loads all corpses from _corpsesByCell even if they were already added to grid before it was loaded
361 // so we need to explicitly check it here (Map::AddToGrid is only called from Player::BuildPlayerRepop, not from ObjectGridLoader)
362 // to avoid failing an assertion in GridObject::AddToGrid
363 if (grid->isGridObjectDataLoaded())
364 {
366 grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj);
367 else
368 grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
369 }
370}
371
372template<class T>
373void Map::SwitchGridContainers(T* /*obj*/, bool /*on*/) { }
374
375template<>
377{
380 if (!p.IsCoordValid())
381 {
382 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);
383 return;
384 }
385
386 Cell cell(p);
388 return;
389
390 if (sLog->ShouldLog("maps", LOG_LEVEL_DEBUG))
391 {
392 // Extract bitfield values
393 uint32 const grid_x = cell.data.Part.grid_x;
394 uint32 const grid_y = cell.data.Part.grid_y;
395
396 TC_LOG_DEBUG("maps", "Switch object {} from grid[{}, {}] {}", obj->GetGUID().ToString(), grid_x, grid_y, on);
397 }
398
399 NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
400 ASSERT(ngrid != nullptr);
401
402 GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
403
404 obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
405
406 if (on)
407 {
408 grid.AddWorldObject(obj);
409 AddWorldObject(obj);
410 }
411 else
412 {
413 grid.AddGridObject(obj);
415 }
416
417 obj->m_isTempWorldObject = on;
418}
419
420template<>
422{
425 if (!p.IsCoordValid())
426 {
427 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);
428 return;
429 }
430
431 Cell cell(p);
433 return;
434
435 if (sLog->ShouldLog("maps", LOG_LEVEL_DEBUG))
436 {
437 // Extract bitfield values
438 uint32 const grid_x = cell.data.Part.grid_x;
439 uint32 const grid_y = cell.data.Part.grid_y;
440
441 TC_LOG_DEBUG("maps", "Switch object {} from grid[{}, {}] {}", obj->GetGUID().ToString(), grid_x, grid_y, on);
442 }
443
444 NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
445 ASSERT(ngrid != nullptr);
446
447 GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
448
449 obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
450
451 if (on)
452 {
453 grid.AddWorldObject(obj);
454 AddWorldObject(obj);
455 }
456 else
457 {
458 grid.AddGridObject(obj);
460 }
461}
462
463template<class T>
465{
466 // Note: In case resurrectable corpse and pet its removed from global lists in own destructor
467 delete obj;
468}
469
470template<>
472{
474 RemoveUpdateObject(player);
475 delete player;
476}
477
478template<>
480{
482 delete transport;
483}
484
486{
487 std::lock_guard<std::mutex> lock(_gridLock);
489}
490
491//Create NGrid so the object can be added to it
492//But object data is not loaded here
494{
495 if (!getNGrid(p.x_coord, p.y_coord))
496 {
497 TC_LOG_DEBUG("maps", "Creating grid[{}, {}] for map {} instance {}", p.x_coord, p.y_coord, GetId(), i_InstanceId);
498
500 p.x_coord, p.y_coord);
501
502 // build a linkage between this map and NGridType
504
506
507 //z coord
508 int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord;
509 int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord;
510
511 if (!GridMaps[gx][gy])
512 LoadMapAndVMap(gx, gy);
513 }
514}
515
516//Load NGrid and make it active
518{
519 EnsureGridLoaded(cell);
520 NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
521 ASSERT(grid != nullptr);
522
523 // refresh grid state & timer
524 if (grid->GetGridState() != GRID_STATE_ACTIVE)
525 {
526 TC_LOG_DEBUG("maps", "Active object {} triggers loading of grid [{}, {}] on map {}", object->GetGUID().ToString(), cell.GridX(), cell.GridY(), GetId());
527 ResetGridExpiry(*grid, 0.1f);
529 }
530}
531
532//Create NGrid and load the object data in it
534{
535 EnsureGridCreated(GridCoord(cell.GridX(), cell.GridY()));
536 NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
537
538 ASSERT(grid != nullptr);
539 if (!grid->isGridObjectDataLoaded())
540 {
541 TC_LOG_DEBUG("maps", "Loading grid[{}, {}] for map {} instance {}", cell.GridX(), cell.GridY(), GetId(), i_InstanceId);
542
543 grid->setGridObjectDataLoaded(true);
544
545 ObjectGridLoader loader(*grid, this, cell);
546 loader.LoadN();
547
548 Balance();
549 return true;
550 }
551
552 return false;
553}
554
556{
557 // First make sure this grid is loaded
558 float gX = ((float(x) - 0.5f - CENTER_GRID_ID) * SIZE_OF_GRIDS) + (CENTER_GRID_OFFSET * 2);
559 float gY = ((float(y) - 0.5f - CENTER_GRID_ID) * SIZE_OF_GRIDS) + (CENTER_GRID_OFFSET * 2);
560 Cell cell = Cell(gX, gY);
561 EnsureGridLoaded(cell);
562
563 // Mark as don't unload
564 NGridType* grid = getNGrid(x, y);
565 grid->setUnloadExplicitLock(true);
566}
567
569{
570 // If grid is loaded, clear unload lock
571 if (IsGridLoaded(GridCoord(x, y)))
572 {
573 NGridType* grid = getNGrid(x, y);
574 grid->setUnloadExplicitLock(false);
575 }
576}
577
578void Map::LoadGrid(float x, float y)
579{
580 EnsureGridLoaded(Cell(x, y));
581}
582
584{
585 CellCoord cellCoord = Trinity::ComputeCellCoord(player->GetPositionX(), player->GetPositionY());
586 if (!cellCoord.IsCoordValid())
587 {
588 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);
589 return false;
590 }
591
592 Cell cell(cellCoord);
594 AddToGrid(player, cell);
595
596 // Check if we are adding to correct map
597 ASSERT (player->GetMap() == this);
598 player->SetMap(this);
599 player->AddToWorld();
600
601 SendInitSelf(player);
602 SendInitTransports(player);
603
604 player->m_clientGUIDs.clear();
605 player->UpdateObjectVisibility(false);
606
607 if (player->IsAlive())
608 ConvertCorpseToBones(player->GetGUID());
609
610 sScriptMgr->OnPlayerEnterMap(this, player);
611 return true;
612}
613
614template<class T>
615void Map::InitializeObject(T* /*obj*/) { }
616
617template<>
622
623template<>
628
629template<class T>
630bool Map::AddToMap(T* obj)
631{
633 if (obj->IsInWorld())
634 {
635 ASSERT(obj->IsInGrid());
636 obj->UpdateObjectVisibility(true);
637 return true;
638 }
639
640 CellCoord cellCoord = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
641 //It will create many problems (including crashes) if an object is not added to grid after creation
642 //The correct way to fix it is to make AddToMap return false and delete the object if it is not added to grid
643 //But now AddToMap is used in too many places, I will just see how many ASSERT failures it will cause
644 ASSERT(cellCoord.IsCoordValid());
645 if (!cellCoord.IsCoordValid())
646 {
647 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);
648 return false; //Should delete object
649 }
650
651 Cell cell(cellCoord);
652 if (obj->isActiveObject())
654 else
655 EnsureGridCreated(GridCoord(cell.GridX(), cell.GridY()));
656 AddToGrid(obj, cell);
657 TC_LOG_DEBUG("maps", "Object {} enters grid[{}, {}]", obj->GetGUID().ToString(), cell.GridX(), cell.GridY());
658
659 //Must already be set before AddToMap. Usually during obj->Create.
660 //obj->SetMap(this);
661 obj->AddToWorld();
662
663 InitializeObject(obj);
664
665 if (obj->isActiveObject())
666 AddToActive(obj);
667
668 //something, such as vehicle, needs to be update immediately
669 //also, trigger needs to cast spell, if not update, cannot see visual
670 obj->SetIsNewObject(true);
671 obj->UpdateObjectVisibilityOnCreate();
672 obj->SetIsNewObject(false);
673 return true;
674}
675
676template<>
678{
679 //TODO: Needs clean up. An object should not be added to map twice.
680 if (obj->IsInWorld())
681 return true;
682
684 if (!cellCoord.IsCoordValid())
685 {
686 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);
687 return false; //Should delete object
688 }
689
690 obj->AddToWorld();
691 _transports.insert(obj);
692
693 // Broadcast creation to players
694 if (!GetPlayers().isEmpty())
695 {
696 for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
697 {
698 if (itr->GetSource()->GetTransport() != obj)
699 {
700 UpdateData data;
701 obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
702 WorldPacket packet;
703 data.BuildPacket(&packet);
704 itr->GetSource()->SendDirectMessage(&packet);
705 }
706 }
707 }
708
709 return true;
710}
711
712bool Map::IsGridLoaded(GridCoord const& p) const
713{
714 NGridType* grid = getNGrid(p.x_coord, p.y_coord);
715 return grid && grid->isGridObjectDataLoaded();
716}
717
719{
720 // Check for valid position
721 if (!obj->IsPositionValid())
722 return;
723
724 // Update mobs/objects in ALL visible cells around object!
726
727 for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
728 {
729 for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
730 {
731 // marked cells are those that have been visited
732 // don't visit the same cell twice
733 uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
734 if (isCellMarked(cell_id))
735 continue;
736
737 markCell(cell_id);
738 CellCoord pair(x, y);
739 Cell cell(pair);
740 cell.SetNoCreate();
741 Visit(cell, gridVisitor);
742 Visit(cell, worldVisitor);
743 }
744 }
745}
746
748{
749 // Nothing to do if no change
750 if (oldZone == newZone)
751 return;
752
753 if (oldZone != MAP_INVALID_ZONE)
754 {
755 uint32& oldZoneCount = _zonePlayerCountMap[oldZone];
756 ASSERT(oldZoneCount, "A player left zone %u (went to %u) - but there were no players in the zone!", oldZone, newZone);
757 --oldZoneCount;
758 }
759 ++_zonePlayerCountMap[newZone];
760}
761
762void Map::Update(uint32 t_diff)
763{
764 _dynamicTree.update(t_diff);
767 {
768 Player* player = m_mapRefIter->GetSource();
769 if (player && player->IsInWorld())
770 {
771 //player->Update(t_diff);
772 WorldSession* session = player->GetSession();
773 MapSessionFilter updater(session);
774 session->Update(t_diff, updater);
775 }
776 }
777
779 if (_respawnCheckTimer <= t_diff)
780 {
783 }
784 else
785 _respawnCheckTimer -= t_diff;
786
789
790 Trinity::ObjectUpdater updater(t_diff);
791 // for creature
793 // for pets
795
796 // the player iterator is stored in the map object
797 // to make sure calls to Map::Remove don't invalidate it
799 {
800 Player* player = m_mapRefIter->GetSource();
801
802 if (!player || !player->IsInWorld())
803 continue;
804
805 // update players at tick
806 player->Update(t_diff);
807
808 VisitNearbyCellsOf(player, grid_object_update, world_object_update);
809
810 // If player is using far sight or mind vision, visit that object too
811 if (WorldObject* viewPoint = player->GetViewpoint())
812 VisitNearbyCellsOf(viewPoint, grid_object_update, world_object_update);
813
814 // Handle updates for creatures in combat with player and are more than 60 yards away
815 if (player->IsInCombat())
816 {
817 std::vector<Unit*> toVisit;
818 for (auto const& pair : player->GetCombatManager().GetPvECombatRefs())
819 if (Creature* unit = pair.second->GetOther(player)->ToCreature())
820 if (unit->GetMapId() == player->GetMapId() && !unit->IsWithinDistInMap(player, GetVisibilityRange(), false))
821 toVisit.push_back(unit);
822 for (Unit* unit : toVisit)
823 VisitNearbyCellsOf(unit, grid_object_update, world_object_update);
824 }
825
826 { // Update any creatures that own auras the player has applications of
827 std::unordered_set<Unit*> toVisit;
828 for (std::pair<uint32, AuraApplication*> pair : player->GetAppliedAuras())
829 {
830 if (Unit* caster = pair.second->GetBase()->GetCaster())
831 if (caster->GetTypeId() != TYPEID_PLAYER && !caster->IsWithinDistInMap(player, GetVisibilityRange(), false))
832 toVisit.insert(caster);
833 }
834 for (Unit* unit : toVisit)
835 VisitNearbyCellsOf(unit, grid_object_update, world_object_update);
836 }
837
838 { // Update player's summons
839 std::vector<Unit*> toVisit;
840
841 // Totems
842 for (ObjectGuid const& summonGuid : player->m_SummonSlot)
843 if (!summonGuid.IsEmpty())
844 if (Creature* unit = GetCreature(summonGuid))
845 if (unit->GetMapId() == player->GetMapId() && !unit->IsWithinDistInMap(player, GetVisibilityRange(), false))
846 toVisit.push_back(unit);
847
848 for (Unit* unit : toVisit)
849 VisitNearbyCellsOf(unit, grid_object_update, world_object_update);
850 }
851 }
852
853 // non-player active objects, increasing iterator in the loop in case of object removal
855 {
858
859 if (!obj || !obj->IsInWorld())
860 continue;
861
862 VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
863 }
864
866 {
869
870 if (!obj->IsInWorld())
871 continue;
872
873 obj->Update(t_diff);
874 }
875
877
879 if (!m_scriptSchedule.empty())
880 {
881 i_scriptLock = true;
883 i_scriptLock = false;
884 }
885
888 {
889 for (auto&& zoneInfo : _zoneDynamicInfo)
890 if (zoneInfo.second.DefaultWeather && !zoneInfo.second.DefaultWeather->Update(_weatherUpdateTimer.GetInterval()))
891 zoneInfo.second.DefaultWeather.reset();
892
894 }
895
898
899 if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty())
901
902 sScriptMgr->OnMapUpdate(this, t_diff);
903
904 TC_METRIC_VALUE("map_creatures", uint64(GetObjectsStore().Size<Creature>()),
905 TC_METRIC_TAG("map_id", std::to_string(GetId())),
906 TC_METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
907
908 TC_METRIC_VALUE("map_gameobjects", uint64(GetObjectsStore().Size<GameObject>()),
909 TC_METRIC_TAG("map_id", std::to_string(GetId())),
910 TC_METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
911}
912
914{
915 template<class T>inline void resetNotify(GridRefManager<T> &m)
916 {
917 for (typename GridRefManager<T>::iterator iter=m.begin(); iter != m.end(); ++iter)
918 iter->GetSource()->ResetAllNotifies();
919 }
920 template<class T> void Visit(GridRefManager<T> &) { }
921 void Visit(CreatureMapType &m) { resetNotify<Creature>(m);}
922 void Visit(PlayerMapType &m) { resetNotify<Player>(m);}
923};
924
926{
928 {
929 NGridType *grid = i->GetSource();
930
931 if (grid->GetGridState() != GRID_STATE_ACTIVE)
932 continue;
933
935 if (!grid->getGridInfoRef()->getRelocationTimer().TPassed())
936 continue;
937
938 uint32 gx = grid->getX(), gy = grid->getY();
939
941 CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
942
943 for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x)
944 {
945 for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y)
946 {
947 uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
948 if (!isCellMarked(cell_id))
949 continue;
950
951 CellCoord pair(x, y);
952 Cell cell(pair);
953 cell.SetNoCreate();
954
955 Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, MAX_VISIBILITY_DISTANCE);
958 Visit(cell, grid_object_relocation);
959 Visit(cell, world_object_relocation);
960 }
961 }
962 }
963
964 ResetNotifier reset;
968 {
969 NGridType *grid = i->GetSource();
970
971 if (grid->GetGridState() != GRID_STATE_ACTIVE)
972 continue;
973
974 if (!grid->getGridInfoRef()->getRelocationTimer().TPassed())
975 continue;
976
978
979 uint32 gx = grid->getX(), gy = grid->getY();
980
982 CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
983
984 for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x)
985 {
986 for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y)
987 {
988 uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
989 if (!isCellMarked(cell_id))
990 continue;
991
992 CellCoord pair(x, y);
993 Cell cell(pair);
994 cell.SetNoCreate();
995 Visit(cell, grid_notifier);
996 Visit(cell, world_notifier);
997 }
998 }
999 }
1000}
1001
1002void Map::RemovePlayerFromMap(Player* player, bool remove)
1003{
1004 // Before leaving map, update zone/area for stats
1005 player->UpdateZone(MAP_INVALID_ZONE, 0);
1006 sScriptMgr->OnPlayerLeaveMap(this, player);
1007
1008 player->CombatStop();
1009
1010 bool const inWorld = player->IsInWorld();
1011 player->RemoveFromWorld();
1012 SendRemoveTransports(player);
1013
1014 if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers()
1015 player->DestroyForNearbyPlayers(); // previous player->UpdateObjectVisibility(true)
1016
1017 if (player->IsInGrid())
1018 player->RemoveFromGrid();
1019 else
1020 ASSERT(remove); //maybe deleted in logoutplayer when player is not in a map
1021
1022 if (remove)
1023 DeleteFromWorld(player);
1024}
1025
1026template<class T>
1027void Map::RemoveFromMap(T *obj, bool remove)
1028{
1029 bool const inWorld = obj->IsInWorld() && obj->GetTypeId() >= TYPEID_UNIT && obj->GetTypeId() <= TYPEID_GAMEOBJECT;
1030 obj->RemoveFromWorld();
1031
1032 if (obj->isActiveObject())
1033 RemoveFromActive(obj);
1034
1035 if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers()
1036 obj->DestroyForNearbyPlayers(); // previous obj->UpdateObjectVisibility(true)
1037
1038 obj->RemoveFromGrid();
1039
1040 obj->ResetMap();
1041
1042 if (remove)
1043 DeleteFromWorld(obj);
1044}
1045
1046template<>
1047void Map::RemoveFromMap(Transport* obj, bool remove)
1048{
1049 obj->RemoveFromWorld();
1050
1051 Map::PlayerList const& players = GetPlayers();
1052 if (!players.isEmpty())
1053 {
1054 UpdateData data;
1055 obj->BuildOutOfRangeUpdateBlock(&data);
1056 WorldPacket packet;
1057 data.BuildPacket(&packet);
1058 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
1059 if (itr->GetSource()->GetTransport() != obj)
1060 itr->GetSource()->SendDirectMessage(&packet);
1061 }
1062
1064 {
1065 TransportsContainer::iterator itr = _transports.find(obj);
1066 if (itr == _transports.end())
1067 return;
1068 if (itr == _transportsUpdateIter)
1070 _transports.erase(itr);
1071 }
1072 else
1073 _transports.erase(obj);
1074
1075 obj->ResetMap();
1076
1077 if (remove)
1078 DeleteFromWorld(obj);
1079}
1080
1081void Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation)
1082{
1083 ASSERT(player);
1084
1085 Cell old_cell(player->GetPositionX(), player->GetPositionY());
1086 Cell new_cell(x, y);
1087
1088 player->Relocate(x, y, z, orientation);
1089 if (player->IsVehicle())
1090 player->GetVehicleKit()->RelocatePassengers();
1091
1092 if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell))
1093 {
1094 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());
1095
1096 player->RemoveFromGrid();
1097
1098 if (old_cell.DiffGrid(new_cell))
1099 EnsureGridLoadedForActiveObject(new_cell, player);
1100
1101 AddToGrid(player, new_cell);
1102 }
1103
1104 player->UpdatePositionData();
1105 player->UpdateObjectVisibility(false);
1106}
1107
1108void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float ang, bool respawnRelocationOnFail)
1109{
1110 ASSERT(CheckGridIntegrity(creature, false));
1111
1112 Cell old_cell = creature->GetCurrentCell();
1113 Cell new_cell(x, y);
1114
1115 if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
1116 return;
1117
1118 // delay creature move for grid/cell to grid/cell moves
1119 if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
1120 {
1121 #ifdef TRINITY_DEBUG
1122 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());
1123 #endif
1124 AddCreatureToMoveList(creature, x, y, z, ang);
1125 // in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList
1126 }
1127 else
1128 {
1129 creature->Relocate(x, y, z, ang);
1130 if (creature->IsVehicle())
1131 creature->GetVehicleKit()->RelocatePassengers();
1132 creature->UpdateObjectVisibility(false);
1133 creature->UpdatePositionData();
1135 }
1136
1137 ASSERT(CheckGridIntegrity(creature, true));
1138}
1139
1140void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail)
1141{
1142 Cell integrity_check(go->GetPositionX(), go->GetPositionY());
1143 Cell old_cell = go->GetCurrentCell();
1144
1145 ASSERT(integrity_check == old_cell);
1146 Cell new_cell(x, y);
1147
1148 if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
1149 return;
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[{}, {}].", 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());
1156#endif
1157 AddGameObjectToMoveList(go, x, y, z, orientation);
1158 // in diffcell/diffgrid case notifiers called at finishing move go in Map::MoveAllGameObjectsInMoveList
1159 }
1160 else
1161 {
1162 go->Relocate(x, y, z, orientation);
1163 go->UpdateModelPosition();
1164 go->UpdatePositionData();
1165 go->UpdateObjectVisibility(false);
1167 }
1168
1169 old_cell = go->GetCurrentCell();
1170 integrity_check = Cell(go->GetPositionX(), go->GetPositionY());
1171 ASSERT(integrity_check == old_cell);
1172}
1173
1174void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float z, float orientation)
1175{
1176 Cell integrity_check(dynObj->GetPositionX(), dynObj->GetPositionY());
1177 Cell old_cell = dynObj->GetCurrentCell();
1178
1179 ASSERT(integrity_check == old_cell);
1180 Cell new_cell(x, y);
1181
1182 if (!getNGrid(new_cell.GridX(), new_cell.GridY()))
1183 return;
1184
1185 // delay creature move for grid/cell to grid/cell moves
1186 if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
1187 {
1188#ifdef TRINITY_DEBUG
1189 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());
1190#endif
1191 AddDynamicObjectToMoveList(dynObj, x, y, z, orientation);
1192 // in diffcell/diffgrid case notifiers called at finishing move dynObj in Map::MoveAllGameObjectsInMoveList
1193 }
1194 else
1195 {
1196 dynObj->Relocate(x, y, z, orientation);
1197 dynObj->UpdatePositionData();
1198 dynObj->UpdateObjectVisibility(false);
1200 }
1201
1202 old_cell = dynObj->GetCurrentCell();
1203 integrity_check = Cell(dynObj->GetPositionX(), dynObj->GetPositionY());
1204 ASSERT(integrity_check == old_cell);
1205}
1206
1207void Map::AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang)
1208{
1209 if (_creatureToMoveLock) //can this happen?
1210 return;
1211
1213 _creaturesToMove.push_back(c);
1214 c->SetNewCellPosition(x, y, z, ang);
1215}
1216
1218{
1219 if (_creatureToMoveLock) //can this happen?
1220 return;
1221
1224}
1225
1226void Map::AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang)
1227{
1228 if (_gameObjectsToMoveLock) //can this happen?
1229 return;
1230
1232 _gameObjectsToMove.push_back(go);
1233 go->SetNewCellPosition(x, y, z, ang);
1234}
1235
1237{
1238 if (_gameObjectsToMoveLock) //can this happen?
1239 return;
1240
1243}
1244
1245void Map::AddDynamicObjectToMoveList(DynamicObject* dynObj, float x, float y, float z, float ang)
1246{
1247 if (_dynamicObjectsToMoveLock) //can this happen?
1248 return;
1249
1251 _dynamicObjectsToMove.push_back(dynObj);
1252 dynObj->SetNewCellPosition(x, y, z, ang);
1253}
1254
1256{
1257 if (_dynamicObjectsToMoveLock) //can this happen?
1258 return;
1259
1262}
1263
1265{
1266 _creatureToMoveLock = true;
1267 for (std::vector<Creature*>::iterator itr = _creaturesToMove.begin(); itr != _creaturesToMove.end(); ++itr)
1268 {
1269 Creature* c = *itr;
1270 if (c->FindMap() != this) //pet is teleported to another map
1271 continue;
1272
1274 {
1276 continue;
1277 }
1278
1280 if (!c->IsInWorld())
1281 continue;
1282
1283 // do move or do move to respawn or remove creature if previous all fail
1285 {
1286 // update pos
1287 c->Relocate(c->_newPosition);
1288 if (c->IsVehicle())
1290 //CreatureRelocationNotify(c, new_cell, new_cell.cellCoord());
1291 c->UpdatePositionData();
1292 c->UpdateObjectVisibility(false);
1293 }
1294 else
1295 {
1296 // if creature can't be move in new cell/grid (not loaded) move it to repawn cell/grid
1297 // creature coordinates will be updated and notifiers send
1298 if (!CreatureRespawnRelocation(c, false))
1299 {
1300 // ... or unload (if respawn grid also not loaded)
1301#ifdef TRINITY_DEBUG
1302 TC_LOG_DEBUG("maps", "Creature {} cannot be move to unloaded respawn grid.", c->GetGUID().ToString());
1303#endif
1304 //AddObjectToRemoveList(Pet*) should only be called in Pet::Remove
1305 //This may happen when a player just logs in and a pet moves to a nearby unloaded cell
1306 //To avoid this, we can load nearby cells when player log in
1307 //But this check is always needed to ensure safety
1309 //need to check why pet is frequently relocated to an unloaded cell
1310 if (c->IsPet())
1311 ((Pet*)c)->Remove(PET_SAVE_NOT_IN_SLOT, true);
1312 else
1314 }
1315 }
1316 }
1317 _creaturesToMove.clear();
1318 _creatureToMoveLock = false;
1319}
1320
1322{
1324 for (std::vector<GameObject*>::iterator itr = _gameObjectsToMove.begin(); itr != _gameObjectsToMove.end(); ++itr)
1325 {
1326 GameObject* go = *itr;
1327 if (go->FindMap() != this) //transport is teleported to another map
1328 continue;
1329
1331 {
1333 continue;
1334 }
1335
1337 if (!go->IsInWorld())
1338 continue;
1339
1340 // do move or do move to respawn or remove creature if previous all fail
1342 {
1343 // update pos
1344 go->Relocate(go->_newPosition);
1345 go->UpdateModelPosition();
1346 go->UpdatePositionData();
1347 go->UpdateObjectVisibility(false);
1348 }
1349 else
1350 {
1351 // if GameObject can't be move in new cell/grid (not loaded) move it to repawn cell/grid
1352 // GameObject coordinates will be updated and notifiers send
1353 if (!GameObjectRespawnRelocation(go, false))
1354 {
1355 // ... or unload (if respawn grid also not loaded)
1356#ifdef TRINITY_DEBUG
1357 TC_LOG_DEBUG("maps", "GameObject {} cannot be move to unloaded respawn grid.", go->GetGUID().ToString());
1358#endif
1360 }
1361 }
1362 }
1363 _gameObjectsToMove.clear();
1364 _gameObjectsToMoveLock = false;
1365}
1366
1368{
1370 for (std::vector<DynamicObject*>::iterator itr = _dynamicObjectsToMove.begin(); itr != _dynamicObjectsToMove.end(); ++itr)
1371 {
1372 DynamicObject* dynObj = *itr;
1373 if (dynObj->FindMap() != this) //transport is teleported to another map
1374 continue;
1375
1377 {
1379 continue;
1380 }
1381
1383 if (!dynObj->IsInWorld())
1384 continue;
1385
1386 // do move or do move to respawn or remove creature if previous all fail
1388 {
1389 // update pos
1390 dynObj->Relocate(dynObj->_newPosition);
1391 dynObj->UpdatePositionData();
1392 dynObj->UpdateObjectVisibility(false);
1393 }
1394 else
1395 {
1396#ifdef TRINITY_DEBUG
1397 TC_LOG_DEBUG("maps", "DynamicObject {} cannot be moved to unloaded grid.", dynObj->GetGUID().ToString());
1398#endif
1399 }
1400 }
1401
1402 _dynamicObjectsToMove.clear();
1404}
1405
1407{
1408 Cell const& old_cell = c->GetCurrentCell();
1409 if (!old_cell.DiffGrid(new_cell)) // in same grid
1410 {
1411 // if in same cell then none do
1412 if (old_cell.DiffCell(new_cell))
1413 {
1414#ifdef TRINITY_DEBUG
1415 TC_LOG_DEBUG("maps", "Creature {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", c->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY());
1416#endif
1417
1418 c->RemoveFromGrid();
1419 AddToGrid(c, new_cell);
1420 }
1421 else
1422 {
1423#ifdef TRINITY_DEBUG
1424 TC_LOG_DEBUG("maps", "Creature {} moved in same grid[{}, {}]cell[{}, {}].", c->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
1425#endif
1426 }
1427
1428 return true;
1429 }
1430
1431 // in diff. grids but active creature
1432 if (c->isActiveObject())
1433 {
1435
1436#ifdef TRINITY_DEBUG
1437 TC_LOG_DEBUG("maps", "Active creature {} moved from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", c->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());
1438#endif
1439
1440 c->RemoveFromGrid();
1441 AddToGrid(c, new_cell);
1442
1443 return true;
1444 }
1445
1447 EnsureGridLoaded(new_cell);
1448
1449 // in diff. loaded grid normal creature
1450 if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY())))
1451 {
1452 #ifdef TRINITY_DEBUG
1453 TC_LOG_DEBUG("maps", "Creature {} moved from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", c->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());
1454 #endif
1455
1456 c->RemoveFromGrid();
1457 EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY()));
1458 AddToGrid(c, new_cell);
1459
1460 return true;
1461 }
1462
1463 // fail to move: normal creature attempt move to unloaded grid
1464 #ifdef TRINITY_DEBUG
1465 TC_LOG_DEBUG("maps", "Creature {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded grid[{}, {}]cell[{}, {}].", c->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());
1466 #endif
1467 return false;
1468}
1469
1471{
1472 Cell const& old_cell = go->GetCurrentCell();
1473 if (!old_cell.DiffGrid(new_cell)) // in same grid
1474 {
1475 // if in same cell then none do
1476 if (old_cell.DiffCell(new_cell))
1477 {
1478#ifdef TRINITY_DEBUG
1479 TC_LOG_DEBUG("maps", "GameObject {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", go->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY());
1480#endif
1481
1482 go->RemoveFromGrid();
1483 AddToGrid(go, new_cell);
1484 }
1485 else
1486 {
1487#ifdef TRINITY_DEBUG
1488 TC_LOG_DEBUG("maps", "GameObject {} moved in same grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
1489#endif
1490 }
1491
1492 return true;
1493 }
1494
1495 // in diff. grids but active GameObject
1496 if (go->isActiveObject())
1497 {
1498 EnsureGridLoadedForActiveObject(new_cell, go);
1499
1500#ifdef TRINITY_DEBUG
1501 TC_LOG_DEBUG("maps", "Active GameObject {} moved 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());
1502#endif
1503
1504 go->RemoveFromGrid();
1505 AddToGrid(go, new_cell);
1506
1507 return true;
1508 }
1509
1510 // in diff. loaded grid normal GameObject
1511 if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY())))
1512 {
1513#ifdef TRINITY_DEBUG
1514 TC_LOG_DEBUG("maps", "GameObject {} moved 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());
1515#endif
1516
1517 go->RemoveFromGrid();
1518 EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY()));
1519 AddToGrid(go, new_cell);
1520
1521 return true;
1522 }
1523
1524 // fail to move: normal GameObject attempt move to unloaded grid
1525#ifdef TRINITY_DEBUG
1526 TC_LOG_DEBUG("maps", "GameObject {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded 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());
1527#endif
1528 return false;
1529}
1530
1532{
1533 Cell const& old_cell = go->GetCurrentCell();
1534 if (!old_cell.DiffGrid(new_cell)) // in same grid
1535 {
1536 // if in same cell then none do
1537 if (old_cell.DiffCell(new_cell))
1538 {
1539#ifdef TRINITY_DEBUG
1540 TC_LOG_DEBUG("maps", "DynamicObject {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", go->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY());
1541#endif
1542
1543 go->RemoveFromGrid();
1544 AddToGrid(go, new_cell);
1545 }
1546 else
1547 {
1548#ifdef TRINITY_DEBUG
1549 TC_LOG_DEBUG("maps", "DynamicObject {} moved in same grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
1550#endif
1551 }
1552
1553 return true;
1554 }
1555
1556 // in diff. grids but active GameObject
1557 if (go->isActiveObject())
1558 {
1559 EnsureGridLoadedForActiveObject(new_cell, go);
1560
1561#ifdef TRINITY_DEBUG
1562 TC_LOG_DEBUG("maps", "Active DynamicObject {} moved 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());
1563#endif
1564
1565 go->RemoveFromGrid();
1566 AddToGrid(go, new_cell);
1567
1568 return true;
1569 }
1570
1571 // in diff. loaded grid normal GameObject
1572 if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY())))
1573 {
1574#ifdef TRINITY_DEBUG
1575 TC_LOG_DEBUG("maps", "DynamicObject {} moved 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());
1576#endif
1577
1578 go->RemoveFromGrid();
1579 EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY()));
1580 AddToGrid(go, new_cell);
1581
1582 return true;
1583 }
1584
1585 // fail to move: normal GameObject attempt move to unloaded grid
1586#ifdef TRINITY_DEBUG
1587 TC_LOG_DEBUG("maps", "DynamicObject {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded 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());
1588#endif
1589 return false;
1590}
1591
1592bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
1593{
1594 float resp_x, resp_y, resp_z, resp_o;
1595 c->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o);
1596 Cell resp_cell(resp_x, resp_y);
1597
1598 //creature will be unloaded with grid
1599 if (diffGridOnly && !c->GetCurrentCell().DiffGrid(resp_cell))
1600 return true;
1601
1602 c->CombatStop();
1603 c->GetMotionMaster()->Clear();
1604
1605#ifdef TRINITY_DEBUG
1606 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());
1607#endif
1608
1609 // teleport it to respawn point (like normal respawn if player see)
1610 if (CreatureCellRelocation(c, resp_cell))
1611 {
1612 c->Relocate(resp_x, resp_y, resp_z, resp_o);
1613 c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators
1614 //CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord());
1615 c->UpdatePositionData();
1616 c->UpdateObjectVisibility(false);
1617 return true;
1618 }
1619
1620 return false;
1621}
1622
1624{
1625 float resp_x, resp_y, resp_z, resp_o;
1626 go->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o);
1627 Cell resp_cell(resp_x, resp_y);
1628
1629 //GameObject will be unloaded with grid
1630 if (diffGridOnly && !go->GetCurrentCell().DiffGrid(resp_cell))
1631 return true;
1632
1633#ifdef TRINITY_DEBUG
1634 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());
1635#endif
1636
1637 // teleport it to respawn point (like normal respawn if player see)
1638 if (GameObjectCellRelocation(go, resp_cell))
1639 {
1640 go->Relocate(resp_x, resp_y, resp_z, resp_o);
1641 go->UpdatePositionData();
1642 go->UpdateObjectVisibility(false);
1643 return true;
1644 }
1645
1646 return false;
1647}
1648
1649bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
1650{
1651 const uint32 x = ngrid.getX();
1652 const uint32 y = ngrid.getY();
1653
1654 {
1655 if (!unloadAll)
1656 {
1657 //pets, possessed creatures (must be active), transport passengers
1659 return false;
1660
1661 if (ActiveObjectsNearGrid(ngrid))
1662 return false;
1663 }
1664
1665 TC_LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {}", x, y, GetId());
1666
1667 if (!unloadAll)
1668 {
1669 // Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids
1670 // Must know real mob position before move
1673
1674 // move creatures to respawn grids if this is diff.grid or to remove list
1675 ObjectGridEvacuator worker;
1677 ngrid.VisitAllGrids(visitor);
1678
1679 // Finish creature moves, remove and delete all creatures with delayed remove before unload
1682 }
1683
1684 {
1685 ObjectGridCleaner worker;
1687 ngrid.VisitAllGrids(visitor);
1688 }
1689
1691
1692 {
1693 ObjectGridUnloader worker;
1695 ngrid.VisitAllGrids(visitor);
1696 }
1697
1698 ASSERT(i_objectsToRemove.empty());
1699
1700 delete &ngrid;
1701 setNGrid(nullptr, x, y);
1702 }
1703 int gx = (MAX_NUMBER_OF_GRIDS - 1) - x;
1704 int gy = (MAX_NUMBER_OF_GRIDS - 1) - y;
1705
1706 // delete grid map, but don't delete if it is from parent map (and thus only reference)
1707 //+++if (GridMaps[gx][gy]) don't check for GridMaps[gx][gy], we might have to unload vmaps
1708 {
1709 if (i_InstanceId == 0)
1710 {
1711 if (GridMaps[gx][gy])
1712 {
1713 GridMaps[gx][gy]->unloadData();
1714 delete GridMaps[gx][gy];
1715 }
1718 }
1719 else
1720 ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridCoord(gx, gy));
1721
1722 GridMaps[gx][gy] = nullptr;
1723 }
1724 TC_LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {} finished", x, y, GetId());
1725 return true;
1726}
1727
1729{
1730 if (HavePlayers())
1731 {
1732 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
1733 {
1734 Player* player = itr->GetSource();
1735 if (!player->IsBeingTeleportedFar())
1736 {
1737 // this is happening for bg
1738 TC_LOG_ERROR("maps", "Map::UnloadAll: player {} is still in map {} during unload, this should not happen!", player->GetName(), GetId());
1739 player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation());
1740 }
1741 }
1742 }
1743}
1744
1746{
1747 // clear all delayed moves, useless anyway do this moves before map unload.
1748 _creaturesToMove.clear();
1749 _gameObjectsToMove.clear();
1750
1752 {
1753 NGridType &grid(*i->GetSource());
1754 ++i;
1755 UnloadGrid(grid, true); // deletes the grid and removes it from the GridRefManager
1756 }
1757
1758 for (TransportsContainer::iterator itr = _transports.begin(); itr != _transports.end();)
1759 {
1760 Transport* transport = *itr;
1761 ++itr;
1762
1763 RemoveFromMap<Transport>(transport, true);
1764 }
1765
1766 for (auto& cellCorpsePair : _corpsesByCell)
1767 {
1768 for (Corpse* corpse : cellCorpsePair.second)
1769 {
1770 corpse->RemoveFromWorld();
1771 corpse->ResetMap();
1772 delete corpse;
1773 }
1774 }
1775
1776 _corpsesByCell.clear();
1777 _corpsesByPlayer.clear();
1778 _corpseBones.clear();
1779}
1780
1781// *****************************
1782// Grid function
1783// *****************************
1785{
1786 _flags = 0;
1787 // Area data
1788 _gridArea = 0;
1789 _areaMap = nullptr;
1790 // Height level data
1794 m_V9 = nullptr;
1795 m_V8 = nullptr;
1796 _minHeightPlanes = nullptr;
1797 // Liquid data
1800 _liquidOffX = 0;
1801 _liquidOffY = 0;
1802 _liquidWidth = 0;
1803 _liquidHeight = 0;
1805 _liquidEntry = nullptr;
1806 _liquidFlags = nullptr;
1807 _liquidMap = nullptr;
1808 _holes = nullptr;
1809}
1810
1812{
1813 unloadData();
1814}
1815
1816bool GridMap::loadData(char const* filename)
1817{
1818 // Unload old data if exist
1819 unloadData();
1820
1821 map_fileheader header;
1822 // Not return error if file not found
1823 FILE* in = fopen(filename, "rb");
1824 if (!in)
1825 return true;
1826
1827 if (fread(&header, sizeof(header), 1, in) != 1)
1828 {
1829 fclose(in);
1830 return false;
1831 }
1832
1833 if (header.mapMagic.asUInt == MapMagic.asUInt && header.versionMagic == MapVersionMagic)
1834 {
1835 // load up area data
1836 if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize))
1837 {
1838 TC_LOG_ERROR("maps", "Error loading map area data\n");
1839 fclose(in);
1840 return false;
1841 }
1842 // load up height data
1843 if (header.heightMapOffset && !loadHeightData(in, header.heightMapOffset, header.heightMapSize))
1844 {
1845 TC_LOG_ERROR("maps", "Error loading map height data\n");
1846 fclose(in);
1847 return false;
1848 }
1849 // load up liquid data
1850 if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize))
1851 {
1852 TC_LOG_ERROR("maps", "Error loading map liquids data\n");
1853 fclose(in);
1854 return false;
1855 }
1856 // loadup holes data (if any. check header.holesOffset)
1857 if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize))
1858 {
1859 TC_LOG_ERROR("maps", "Error loading map holes data\n");
1860 fclose(in);
1861 return false;
1862 }
1863 fclose(in);
1864 return true;
1865 }
1866
1867 TC_LOG_ERROR("maps", "Map file '{}' is from an incompatible map version (%.*s v{}), %.*s v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.",
1868 filename, 4, header.mapMagic.asChar, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic);
1869 fclose(in);
1870 return false;
1871}
1872
1874{
1875 delete[] _areaMap;
1876 delete[] m_V9;
1877 delete[] m_V8;
1878 delete[] _minHeightPlanes;
1879 delete[] _liquidEntry;
1880 delete[] _liquidFlags;
1881 delete[] _liquidMap;
1882 delete[] _holes;
1883 _areaMap = nullptr;
1884 m_V9 = nullptr;
1885 m_V8 = nullptr;
1886 _minHeightPlanes = nullptr;
1887 _liquidEntry = nullptr;
1888 _liquidFlags = nullptr;
1889 _liquidMap = nullptr;
1890 _holes = nullptr;
1892}
1893
1894bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/)
1895{
1896 map_areaHeader header;
1897 fseek(in, offset, SEEK_SET);
1898
1899 if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapAreaMagic.asUInt)
1900 return false;
1901
1902 _gridArea = header.gridArea;
1903 if (!(header.flags & MAP_AREA_NO_AREA))
1904 {
1905 _areaMap = new uint16[16 * 16];
1906 if (fread(_areaMap, sizeof(uint16), 16*16, in) != 16*16)
1907 return false;
1908 }
1909 return true;
1910}
1911
1912bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
1913{
1914 map_heightHeader header;
1915 fseek(in, offset, SEEK_SET);
1916
1917 if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapHeightMagic.asUInt)
1918 return false;
1919
1920 _gridHeight = header.gridHeight;
1921 if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
1922 {
1923 if ((header.flags & MAP_HEIGHT_AS_INT16))
1924 {
1925 m_uint16_V9 = new uint16 [129*129];
1926 m_uint16_V8 = new uint16 [128*128];
1927 if (fread(m_uint16_V9, sizeof(uint16), 129*129, in) != 129*129 ||
1928 fread(m_uint16_V8, sizeof(uint16), 128*128, in) != 128*128)
1929 return false;
1930 _gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
1932 }
1933 else if ((header.flags & MAP_HEIGHT_AS_INT8))
1934 {
1935 m_uint8_V9 = new uint8 [129*129];
1936 m_uint8_V8 = new uint8 [128*128];
1937 if (fread(m_uint8_V9, sizeof(uint8), 129*129, in) != 129*129 ||
1938 fread(m_uint8_V8, sizeof(uint8), 128*128, in) != 128*128)
1939 return false;
1940 _gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255;
1942 }
1943 else
1944 {
1945 m_V9 = new float [129*129];
1946 m_V8 = new float [128*128];
1947 if (fread(m_V9, sizeof(float), 129*129, in) != 129*129 ||
1948 fread(m_V8, sizeof(float), 128*128, in) != 128*128)
1949 return false;
1951 }
1952 }
1953 else
1955
1957 {
1958 std::array<int16, 9> maxHeights;
1959 std::array<int16, 9> minHeights;
1960 if (fread(maxHeights.data(), sizeof(int16), maxHeights.size(), in) != maxHeights.size() ||
1961 fread(minHeights.data(), sizeof(int16), minHeights.size(), in) != minHeights.size())
1962 return false;
1963
1964 static uint32 constexpr indices[8][3] =
1965 {
1966 { 3, 0, 4 },
1967 { 0, 1, 4 },
1968 { 1, 2, 4 },
1969 { 2, 5, 4 },
1970 { 5, 8, 4 },
1971 { 8, 7, 4 },
1972 { 7, 6, 4 },
1973 { 6, 3, 4 }
1974 };
1975
1976 static float constexpr boundGridCoords[9][2] =
1977 {
1978 { 0.0f, 0.0f },
1979 { 0.0f, -266.66666f },
1980 { 0.0f, -533.33331f },
1981 { -266.66666f, 0.0f },
1982 { -266.66666f, -266.66666f },
1983 { -266.66666f, -533.33331f },
1984 { -533.33331f, 0.0f },
1985 { -533.33331f, -266.66666f },
1986 { -533.33331f, -533.33331f }
1987 };
1988
1989 _minHeightPlanes = new G3D::Plane[8];
1990 for (uint32 quarterIndex = 0; quarterIndex < 8; ++quarterIndex)
1991 _minHeightPlanes[quarterIndex] = G3D::Plane(
1992 G3D::Vector3(boundGridCoords[indices[quarterIndex][0]][0], boundGridCoords[indices[quarterIndex][0]][1], minHeights[indices[quarterIndex][0]]),
1993 G3D::Vector3(boundGridCoords[indices[quarterIndex][1]][0], boundGridCoords[indices[quarterIndex][1]][1], minHeights[indices[quarterIndex][1]]),
1994 G3D::Vector3(boundGridCoords[indices[quarterIndex][2]][0], boundGridCoords[indices[quarterIndex][2]][1], minHeights[indices[quarterIndex][2]])
1995 );
1996 }
1997
1998 return true;
1999}
2000
2001bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
2002{
2003 map_liquidHeader header;
2004 fseek(in, offset, SEEK_SET);
2005
2006 if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapLiquidMagic.asUInt)
2007 return false;
2008
2011 _liquidOffX = header.offsetX;
2012 _liquidOffY = header.offsetY;
2013 _liquidWidth = header.width;
2014 _liquidHeight = header.height;
2015 _liquidLevel = header.liquidLevel;
2016
2017 if (!(header.flags & MAP_LIQUID_NO_TYPE))
2018 {
2019 _liquidEntry = new uint16[16*16];
2020 if (fread(_liquidEntry, sizeof(uint16), 16*16, in) != 16*16)
2021 return false;
2022
2023 _liquidFlags = new uint8[16*16];
2024 if (fread(_liquidFlags, sizeof(uint8), 16*16, in) != 16*16)
2025 return false;
2026 }
2027 if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
2028 {
2030 if (fread(_liquidMap, sizeof(float), _liquidWidth*_liquidHeight, in) != (uint32(_liquidWidth) * uint32(_liquidHeight)))
2031 return false;
2032 }
2033 return true;
2034}
2035
2036bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 /*size*/)
2037{
2038 if (fseek(in, offset, SEEK_SET) != 0)
2039 return false;
2040
2041 _holes = new uint16[16 * 16];
2042 if (fread(_holes, sizeof(uint16), 16 * 16, in) != 16 * 16)
2043 return false;
2044
2045 return true;
2046}
2047
2048uint16 GridMap::getArea(float x, float y) const
2049{
2050 if (!_areaMap)
2051 return _gridArea;
2052
2053 x = 16 * (CENTER_GRID_ID - x/SIZE_OF_GRIDS);
2054 y = 16 * (CENTER_GRID_ID - y/SIZE_OF_GRIDS);
2055 int lx = (int)x & 15;
2056 int ly = (int)y & 15;
2057 return _areaMap[lx*16 + ly];
2058}
2059
2060float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const
2061{
2062 return _gridHeight;
2063}
2064
2065float GridMap::getHeightFromFloat(float x, float y) const
2066{
2067 if (!m_V8 || !m_V9)
2068 return _gridHeight;
2069
2072
2073 int x_int = (int)x;
2074 int y_int = (int)y;
2075 x -= x_int;
2076 y -= y_int;
2077 x_int&=(MAP_RESOLUTION - 1);
2078 y_int&=(MAP_RESOLUTION - 1);
2079
2080 if (isHole(x_int, y_int))
2081 return INVALID_HEIGHT;
2082
2083 // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
2084 // +--------------> X
2085 // | h1-------h2 Coordinates is:
2086 // | | \ 1 / | h1 0, 0
2087 // | | \ / | h2 0, 1
2088 // | | 2 h5 3 | h3 1, 0
2089 // | | / \ | h4 1, 1
2090 // | | / 4 \ | h5 1/2, 1/2
2091 // | h3-------h4
2092 // V Y
2093 // For find height need
2094 // 1 - detect triangle
2095 // 2 - solve linear equation from triangle points
2096 // Calculate coefficients for solve h = a*x + b*y + c
2097
2098 float a, b, c;
2099 // Select triangle:
2100 if (x+y < 1)
2101 {
2102 if (x > y)
2103 {
2104 // 1 triangle (h1, h2, h5 points)
2105 float h1 = m_V9[(x_int)*129 + y_int];
2106 float h2 = m_V9[(x_int+1)*129 + y_int];
2107 float h5 = 2 * m_V8[x_int*128 + y_int];
2108 a = h2-h1;
2109 b = h5-h1-h2;
2110 c = h1;
2111 }
2112 else
2113 {
2114 // 2 triangle (h1, h3, h5 points)
2115 float h1 = m_V9[x_int*129 + y_int ];
2116 float h3 = m_V9[x_int*129 + y_int+1];
2117 float h5 = 2 * m_V8[x_int*128 + y_int];
2118 a = h5 - h1 - h3;
2119 b = h3 - h1;
2120 c = h1;
2121 }
2122 }
2123 else
2124 {
2125 if (x > y)
2126 {
2127 // 3 triangle (h2, h4, h5 points)
2128 float h2 = m_V9[(x_int+1)*129 + y_int ];
2129 float h4 = m_V9[(x_int+1)*129 + y_int+1];
2130 float h5 = 2 * m_V8[x_int*128 + y_int];
2131 a = h2 + h4 - h5;
2132 b = h4 - h2;
2133 c = h5 - h4;
2134 }
2135 else
2136 {
2137 // 4 triangle (h3, h4, h5 points)
2138 float h3 = m_V9[(x_int)*129 + y_int+1];
2139 float h4 = m_V9[(x_int+1)*129 + y_int+1];
2140 float h5 = 2 * m_V8[x_int*128 + y_int];
2141 a = h4 - h3;
2142 b = h3 + h4 - h5;
2143 c = h5 - h4;
2144 }
2145 }
2146 // Calculate height
2147 return a * x + b * y + c;
2148}
2149
2150float GridMap::getHeightFromUint8(float x, float y) const
2151{
2152 if (!m_uint8_V8 || !m_uint8_V9)
2153 return _gridHeight;
2154
2157
2158 int x_int = (int)x;
2159 int y_int = (int)y;
2160 x -= x_int;
2161 y -= y_int;
2162 x_int&=(MAP_RESOLUTION - 1);
2163 y_int&=(MAP_RESOLUTION - 1);
2164
2165 if (isHole(x_int, y_int))
2166 return INVALID_HEIGHT;
2167
2168 int32 a, b, c;
2169 uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int];
2170 if (x+y < 1)
2171 {
2172 if (x > y)
2173 {
2174 // 1 triangle (h1, h2, h5 points)
2175 int32 h1 = V9_h1_ptr[ 0];
2176 int32 h2 = V9_h1_ptr[129];
2177 int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
2178 a = h2-h1;
2179 b = h5-h1-h2;
2180 c = h1;
2181 }
2182 else
2183 {
2184 // 2 triangle (h1, h3, h5 points)
2185 int32 h1 = V9_h1_ptr[0];
2186 int32 h3 = V9_h1_ptr[1];
2187 int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
2188 a = h5 - h1 - h3;
2189 b = h3 - h1;
2190 c = h1;
2191 }
2192 }
2193 else
2194 {
2195 if (x > y)
2196 {
2197 // 3 triangle (h2, h4, h5 points)
2198 int32 h2 = V9_h1_ptr[129];
2199 int32 h4 = V9_h1_ptr[130];
2200 int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
2201 a = h2 + h4 - h5;
2202 b = h4 - h2;
2203 c = h5 - h4;
2204 }
2205 else
2206 {
2207 // 4 triangle (h3, h4, h5 points)
2208 int32 h3 = V9_h1_ptr[ 1];
2209 int32 h4 = V9_h1_ptr[130];
2210 int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
2211 a = h4 - h3;
2212 b = h3 + h4 - h5;
2213 c = h5 - h4;
2214 }
2215 }
2216 // Calculate height
2217 return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
2218}
2219
2220float GridMap::getHeightFromUint16(float x, float y) const
2221{
2222 if (!m_uint16_V8 || !m_uint16_V9)
2223 return _gridHeight;
2224
2227
2228 int x_int = (int)x;
2229 int y_int = (int)y;
2230 x -= x_int;
2231 y -= y_int;
2232 x_int&=(MAP_RESOLUTION - 1);
2233 y_int&=(MAP_RESOLUTION - 1);
2234
2235 if (isHole(x_int, y_int))
2236 return INVALID_HEIGHT;
2237
2238 int32 a, b, c;
2239 uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int];
2240 if (x+y < 1)
2241 {
2242 if (x > y)
2243 {
2244 // 1 triangle (h1, h2, h5 points)
2245 int32 h1 = V9_h1_ptr[ 0];
2246 int32 h2 = V9_h1_ptr[129];
2247 int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
2248 a = h2-h1;
2249 b = h5-h1-h2;
2250 c = h1;
2251 }
2252 else
2253 {
2254 // 2 triangle (h1, h3, h5 points)
2255 int32 h1 = V9_h1_ptr[0];
2256 int32 h3 = V9_h1_ptr[1];
2257 int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
2258 a = h5 - h1 - h3;
2259 b = h3 - h1;
2260 c = h1;
2261 }
2262 }
2263 else
2264 {
2265 if (x > y)
2266 {
2267 // 3 triangle (h2, h4, h5 points)
2268 int32 h2 = V9_h1_ptr[129];
2269 int32 h4 = V9_h1_ptr[130];
2270 int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
2271 a = h2 + h4 - h5;
2272 b = h4 - h2;
2273 c = h5 - h4;
2274 }
2275 else
2276 {
2277 // 4 triangle (h3, h4, h5 points)
2278 int32 h3 = V9_h1_ptr[ 1];
2279 int32 h4 = V9_h1_ptr[130];
2280 int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
2281 a = h4 - h3;
2282 b = h3 + h4 - h5;
2283 c = h5 - h4;
2284 }
2285 }
2286 // Calculate height
2287 return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
2288}
2289
2290bool GridMap::isHole(int row, int col) const
2291{
2292 if (!_holes)
2293 return false;
2294
2295 int cellRow = row / 8; // 8 squares per cell
2296 int cellCol = col / 8;
2297 int holeRow = row % 8 / 2;
2298 int holeCol = (col - (cellCol * 8)) / 2;
2299
2300 uint16 hole = _holes[cellRow * 16 + cellCol];
2301
2302 return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
2303}
2304
2305float GridMap::getMinHeight(float x, float y) const
2306{
2307 if (!_minHeightPlanes)
2308 return -500.0f;
2309
2311
2312 int32 doubleGridX = int32(std::floor(-(x - MAP_HALFSIZE) / CENTER_GRID_OFFSET));
2313 int32 doubleGridY = int32(std::floor(-(y - MAP_HALFSIZE) / CENTER_GRID_OFFSET));
2314
2315 float gx = x - (int32(gridCoord.x_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
2316 float gy = y - (int32(gridCoord.y_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS;
2317
2318 uint32 quarterIndex = 0;
2319 if (doubleGridY & 1)
2320 {
2321 if (doubleGridX & 1)
2322 quarterIndex = 4 + (gx <= gy);
2323 else
2324 quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy);
2325 }
2326 else if (doubleGridX & 1)
2327 quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy);
2328 else
2329 quarterIndex = gx > gy;
2330
2331 G3D::Ray ray = G3D::Ray::fromOriginAndDirection(G3D::Vector3(gx, gy, 0.0f), G3D::Vector3::unitZ());
2332 return ray.intersection(_minHeightPlanes[quarterIndex]).z;
2333}
2334
2335float GridMap::getLiquidLevel(float x, float y) const
2336{
2337 if (!_liquidMap)
2338 return _liquidLevel;
2339
2342
2343 int cx_int = ((int)x & (MAP_RESOLUTION-1)) - _liquidOffY;
2344 int cy_int = ((int)y & (MAP_RESOLUTION-1)) - _liquidOffX;
2345
2346 if (cx_int < 0 || cx_int >=_liquidHeight)
2347 return INVALID_HEIGHT;
2348 if (cy_int < 0 || cy_int >=_liquidWidth)
2349 return INVALID_HEIGHT;
2350
2351 return _liquidMap[cx_int*_liquidWidth + cy_int];
2352}
2353
2354// Get water state on map
2355inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, Optional<uint8> ReqLiquidType, LiquidData* data, float collisionHeight)
2356{
2357 // Check water type (if no water return)
2359 return LIQUID_MAP_NO_WATER;
2360
2361 // Get cell
2362 float cx = MAP_RESOLUTION * (CENTER_GRID_ID - x/SIZE_OF_GRIDS);
2363 float cy = MAP_RESOLUTION * (CENTER_GRID_ID - y/SIZE_OF_GRIDS);
2364
2365 int x_int = (int)cx & (MAP_RESOLUTION-1);
2366 int y_int = (int)cy & (MAP_RESOLUTION-1);
2367
2368 // Check water type in cell
2369 int idx=(x_int>>3)*16 + (y_int>>3);
2372 if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry))
2373 {
2375 uint32 liqTypeIdx = liquidEntry->SoundBank;
2376 if (entry < 21)
2377 {
2378 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
2379 {
2380 uint32 overrideLiquid = area->LiquidTypeID[liquidEntry->SoundBank];
2381 if (!overrideLiquid && area->ParentAreaID)
2382 {
2383 area = sAreaTableStore.LookupEntry(area->ParentAreaID);
2384 if (area)
2385 overrideLiquid = area->LiquidTypeID[liquidEntry->SoundBank];
2386 }
2387
2388 if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
2389 {
2390 entry = overrideLiquid;
2391 liqTypeIdx = liq->SoundBank;
2392 }
2393 }
2394 }
2395
2396 type |= 1 << liqTypeIdx;
2397 }
2398
2399 if (type == 0)
2400 return LIQUID_MAP_NO_WATER;
2401
2402 // Check req liquid type mask
2403 if (ReqLiquidType && !(*ReqLiquidType & type))
2404 return LIQUID_MAP_NO_WATER;
2405
2406 // Check water level:
2407 // Check water height map
2408 int lx_int = x_int - _liquidOffY;
2409 int ly_int = y_int - _liquidOffX;
2410 if (lx_int < 0 || lx_int >=_liquidHeight)
2411 return LIQUID_MAP_NO_WATER;
2412 if (ly_int < 0 || ly_int >=_liquidWidth)
2413 return LIQUID_MAP_NO_WATER;
2414
2415 // Get water level
2416 float liquid_level = _liquidMap ? _liquidMap[lx_int*_liquidWidth + ly_int] : _liquidLevel;
2417 // Get ground level (sub 0.2 for fix some errors)
2418 float ground_level = getHeight(x, y);
2419
2420 // Check water level and ground level
2421 if (liquid_level < ground_level || z < ground_level)
2422 return LIQUID_MAP_NO_WATER;
2423
2424 // All ok in water -> store data
2425 if (data)
2426 {
2427 data->entry = entry;
2428 data->type_flags = type;
2429 data->level = liquid_level;
2430 data->depth_level = ground_level;
2431 }
2432
2433 // For speed check as int values
2434 float delta = liquid_level - z;
2435
2436 if (delta > collisionHeight) // Under water
2438 if (delta > 0.0f) // In water
2439 return LIQUID_MAP_IN_WATER;
2440 if (delta > -0.1f) // Walk on water
2441 return LIQUID_MAP_WATER_WALK;
2442 // Above water
2444}
2445
2446inline GridMap* Map::GetGrid(float x, float y)
2447{
2448 // half opt method
2449 int gx=(int)(CENTER_GRID_ID - x/SIZE_OF_GRIDS); //grid x
2450 int gy=(int)(CENTER_GRID_ID - y/SIZE_OF_GRIDS); //grid y
2451
2452 // ensure GridMap is loaded
2454
2455 return GridMaps[gx][gy];
2456}
2457
2458float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/, float collisionHeight /*= DEFAULT_COLLISION_HEIGHT*/) const
2459{
2460 if (const_cast<Map*>(this)->GetGrid(x, y))
2461 {
2462 // we need ground level (including grid height version) for proper return water level in point
2463 float ground_z = GetHeight(phasemask, x, y, z + Z_OFFSET_FIND_HEIGHT, true, 50.0f);
2464 if (ground)
2465 *ground = ground_z;
2466
2467 LiquidData liquid_status;
2468
2469 ZLiquidStatus res = GetLiquidStatus(phasemask, x, y, ground_z, {}, &liquid_status, collisionHeight);
2470 switch (res)
2471 {
2473 return std::max<float>(liquid_status.level, ground_z);
2475 return ground_z;
2476 default:
2477 return liquid_status.level;
2478 }
2479 }
2480
2482}
2483
2484float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
2485{
2486 // find raw .map surface under Z coordinates
2487 float mapHeight = VMAP_INVALID_HEIGHT_VALUE;
2488 float gridHeight = GetGridHeight(x, y);
2489 if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE))
2490 mapHeight = gridHeight;
2491
2492 float vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
2493 if (checkVMap)
2494 {
2496 if (vmgr->isHeightCalcEnabled())
2497 vmapHeight = vmgr->getHeight(GetId(), x, y, z, maxSearchDist);
2498 }
2499
2500 // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT
2501 // vmapheight set for any under Z value or <= INVALID_HEIGHT
2502 if (vmapHeight > INVALID_HEIGHT)
2503 {
2504 if (mapHeight > INVALID_HEIGHT)
2505 {
2506 // we have mapheight and vmapheight and must select more appropriate
2507
2508 // vmap height above map height
2509 // or if the distance of the vmap height is less the land height distance
2510 if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
2511 return vmapHeight;
2512
2513 return mapHeight; // better use .map surface height
2514 }
2515
2516 return vmapHeight; // we have only vmapHeight (if have)
2517 }
2518
2519 return mapHeight; // explicitly use map data
2520}
2521
2522float Map::GetGridHeight(float x, float y) const
2523{
2524 if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
2525 return gmap->getHeight(x, y);
2526
2528}
2529
2530float Map::GetMinHeight(float x, float y) const
2531{
2532 if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y))
2533 return grid->getMinHeight(x, y);
2534
2535 return -500.0f;
2536}
2537
2538static inline bool IsInWMOInterior(uint32 mogpFlags)
2539{
2540 return (mogpFlags & 0x2000) != 0;
2541}
2542
2543bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
2544{
2545 float check_z = z;
2549
2550 bool hasVmapAreaInfo = vmgr->getAreaAndLiquidData(GetId(), x, y, z, {}, vdata) && vdata.areaInfo.has_value();
2551 bool hasDynamicAreaInfo = _dynamicTree.getAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value();
2552 auto useVmap = [&] { check_z = vdata.floorZ; groupId = vdata.areaInfo->groupId; adtId = vdata.areaInfo->adtId; rootId = vdata.areaInfo->rootId; flags = vdata.areaInfo->mogpFlags; };
2553 auto useDyn = [&] { check_z = ddata.floorZ; groupId = ddata.areaInfo->groupId; adtId = ddata.areaInfo->adtId; rootId = ddata.areaInfo->rootId; flags = ddata.areaInfo->mogpFlags; };
2554 if (hasVmapAreaInfo)
2555 {
2556 if (hasDynamicAreaInfo && ddata.floorZ > vdata.floorZ)
2557 useDyn();
2558 else
2559 useVmap();
2560 }
2561 else if (hasDynamicAreaInfo)
2562 {
2563 useDyn();
2564 }
2565
2566 if (hasVmapAreaInfo || hasDynamicAreaInfo)
2567 {
2568 // check if there's terrain between player height and object height
2569 if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
2570 {
2571 float mapHeight = gmap->getHeight(x, y);
2572 // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
2573 if (z + 2.0f > mapHeight && mapHeight > check_z)
2574 return false;
2575 }
2576 return true;
2577 }
2578 return false;
2579}
2580
2581uint32 Map::GetAreaId(uint32 phaseMask, float x, float y, float z) const
2582{
2583 uint32 mogpFlags;
2584 int32 adtId, rootId, groupId;
2585 float vmapZ = z;
2586 bool hasVmapArea = GetAreaInfo(phaseMask, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
2587
2588 uint32 gridAreaId = 0;
2589 float gridMapHeight = INVALID_HEIGHT;
2590 if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
2591 {
2592 gridAreaId = gmap->getArea(x, y);
2593 gridMapHeight = gmap->getHeight(x, y);
2594 }
2595
2596 uint32 areaId = 0;
2597
2598 // floor is the height we are closer to (but only if above)
2599 if (hasVmapArea && G3D::fuzzyGe(z, vmapZ - GROUND_HEIGHT_TOLERANCE) && (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapZ > gridMapHeight))
2600 {
2601 // wmo found
2602 if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
2603 areaId = wmoEntry->AreaTableID;
2604
2605 if (!areaId)
2606 areaId = gridAreaId;
2607 }
2608 else
2609 areaId = gridAreaId;
2610
2611 if (!areaId)
2612 areaId = i_mapEntry->AreaTableID;
2613
2614 return areaId;
2615}
2616
2617uint32 Map::GetZoneId(uint32 phaseMask, float x, float y, float z) const
2618{
2619 uint32 areaId = GetAreaId(phaseMask, x, y, z);
2620 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
2621 if (area->ParentAreaID)
2622 return area->ParentAreaID;
2623
2624 return areaId;
2625}
2626
2627void Map::GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, float x, float y, float z) const
2628{
2629 areaid = zoneid = GetAreaId(phaseMask, x, y, z);
2630 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
2631 if (area->ParentAreaID)
2632 zoneid = area->ParentAreaID;
2633}
2634
2635ZLiquidStatus Map::GetLiquidStatus(uint32 phaseMask, float x, float y, float z, Optional<uint8> ReqLiquidType, LiquidData* data, float collisionHeight) const
2636{
2639 VMAP::AreaAndLiquidData vmapData;
2640 bool useGridLiquid = true;
2641 if (vmgr->getAreaAndLiquidData(GetId(), x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo)
2642 {
2643 useGridLiquid = !vmapData.areaInfo || !IsInWMOInterior(vmapData.areaInfo->mogpFlags);
2644 TC_LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", vmapData.liquidInfo->level, vmapData.floorZ, vmapData.liquidInfo->type);
2645 // Check water level and ground level
2646 if (vmapData.liquidInfo->level > vmapData.floorZ && G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE))
2647 {
2648 // All ok in water -> store data
2649 if (data)
2650 {
2651 // hardcoded in client like this
2652 if (GetId() == 530 && vmapData.liquidInfo->type == 2)
2653 vmapData.liquidInfo->type = 15;
2654
2655 uint32 liquidFlagType = 0;
2656 if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(vmapData.liquidInfo->type))
2657 liquidFlagType = liq->SoundBank;
2658
2659 if (vmapData.liquidInfo->type && vmapData.liquidInfo->type < 21)
2660 {
2661 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z)))
2662 {
2663 uint32 overrideLiquid = area->LiquidTypeID[liquidFlagType];
2664 if (!overrideLiquid && area->ParentAreaID)
2665 {
2666 area = sAreaTableStore.LookupEntry(area->ParentAreaID);
2667 if (area)
2668 overrideLiquid = area->LiquidTypeID[liquidFlagType];
2669 }
2670
2671 if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
2672 {
2673 vmapData.liquidInfo->type = overrideLiquid;
2674 liquidFlagType = liq->SoundBank;
2675 }
2676 }
2677 }
2678
2679 data->level = vmapData.liquidInfo->level;
2680 data->depth_level = vmapData.floorZ;
2681
2682 data->entry = vmapData.liquidInfo->type;
2683 data->type_flags = 1 << liquidFlagType;
2684 }
2685
2686 float delta = vmapData.liquidInfo->level - z;
2687
2688 // Get position delta
2689 if (delta > collisionHeight) // Under water
2691 if (delta > 0.0f) // In water
2692 return LIQUID_MAP_IN_WATER;
2693 if (delta > -0.1f) // Walk on water
2694 return LIQUID_MAP_WATER_WALK;
2695 result = LIQUID_MAP_ABOVE_WATER;
2696 }
2697 }
2698
2699 if (useGridLiquid)
2700 {
2701 if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
2702 {
2703 LiquidData map_data;
2704 ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight);
2705 // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
2706 if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > vmapData.floorZ))
2707 {
2708 if (data)
2709 {
2710 // hardcoded in client like this
2711 if (GetId() == 530 && map_data.entry == 2)
2712 map_data.entry = 15;
2713
2714 *data = map_data;
2715 }
2716 return map_result;
2717 }
2718 }
2719 }
2720 return result;
2721}
2722
2723void Map::GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, PositionFullTerrainStatus& data, Optional<uint8> reqLiquidType, float collisionHeight) const
2724{
2726 VMAP::AreaAndLiquidData vmapData;
2728 VMAP::AreaAndLiquidData* wmoData = nullptr;
2729 GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y);
2730 vmgr->getAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData);
2731 _dynamicTree.getAreaAndLiquidData(x, y, z, phaseMask, reqLiquidType, dynData);
2732
2733 uint32 gridAreaId = 0;
2734 float gridMapHeight = INVALID_HEIGHT;
2735 if (gmap)
2736 {
2737 gridAreaId = gmap->getArea(x, y);
2738 gridMapHeight = gmap->getHeight(x, y);
2739 }
2740
2741 bool useGridLiquid = true;
2742
2743 // floor is the height we are closer to (but only if above)
2745 if (gridMapHeight > INVALID_HEIGHT && G3D::fuzzyGe(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE))
2746 data.floorZ = gridMapHeight;
2747 if (vmapData.floorZ > VMAP_INVALID_HEIGHT &&
2748 G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
2749 (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapData.floorZ > gridMapHeight))
2750 {
2751 data.floorZ = vmapData.floorZ;
2752 wmoData = &vmapData;
2753 }
2754 // NOTE: Objects will not detect a case when a wmo providing area/liquid despawns from under them
2755 // but this is fine as these kind of objects are not meant to be spawned and despawned a lot
2756 // example: Lich King platform
2757 if (dynData.floorZ > VMAP_INVALID_HEIGHT &&
2758 G3D::fuzzyGe(z, dynData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
2759 (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > gridMapHeight) &&
2760 (G3D::fuzzyLt(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > vmapData.floorZ))
2761 {
2762 data.floorZ = dynData.floorZ;
2763 wmoData = &dynData;
2764 }
2765
2766 if (wmoData)
2767 {
2768 if (wmoData->areaInfo)
2769 {
2770 data.wmoLocation.emplace(wmoData->areaInfo->groupId, wmoData->areaInfo->adtId, wmoData->areaInfo->rootId, wmoData->areaInfo->uniqueId);
2771 // wmo found
2772 WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(wmoData->areaInfo->rootId, wmoData->areaInfo->adtId, wmoData->areaInfo->groupId);
2773 data.outdoors = (wmoData->areaInfo->mogpFlags & 0x8) != 0;
2774 if (wmoEntry)
2775 {
2776 data.areaId = wmoEntry->AreaTableID;
2777 if (wmoEntry->Flags & 4)
2778 data.outdoors = true;
2779 else if (wmoEntry->Flags & 2)
2780 data.outdoors = false;
2781 }
2782
2783 if (!data.areaId)
2784 data.areaId = gridAreaId;
2785
2786 useGridLiquid = !IsInWMOInterior(wmoData->areaInfo->mogpFlags);
2787 }
2788 }
2789 else
2790 {
2791 data.outdoors = true;
2792 data.areaId = gridAreaId;
2793 if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId))
2794 data.outdoors = (areaEntry->Flags & (AREA_FLAG_INSIDE | AREA_FLAG_OUTSIDE)) != AREA_FLAG_INSIDE;
2795 }
2796
2797 if (!data.areaId)
2799
2800 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId);
2801
2802 // liquid processing
2804 if (wmoData && wmoData->liquidInfo && wmoData->liquidInfo->level > wmoData->floorZ)
2805 {
2806 uint32 liquidType = wmoData->liquidInfo->type;
2807 if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
2808 liquidType = 15;
2809
2810 uint32 liquidFlagType = 0;
2811 if (LiquidTypeEntry const* liquidData = sLiquidTypeStore.LookupEntry(liquidType))
2812 liquidFlagType = liquidData->SoundBank;
2813
2814 if (liquidType && liquidType < 21 && areaEntry)
2815 {
2816 uint32 overrideLiquid = areaEntry->LiquidTypeID[liquidFlagType];
2817 if (!overrideLiquid && areaEntry->ParentAreaID)
2818 {
2819 AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(areaEntry->ParentAreaID);
2820 if (zoneEntry)
2821 overrideLiquid = zoneEntry->LiquidTypeID[liquidFlagType];
2822 }
2823
2824 if (LiquidTypeEntry const* overrideData = sLiquidTypeStore.LookupEntry(overrideLiquid))
2825 {
2826 liquidType = overrideLiquid;
2827 liquidFlagType = overrideData->SoundBank;
2828 }
2829 }
2830
2831 data.liquidInfo.emplace();
2832 data.liquidInfo->level = wmoData->liquidInfo->level;
2833 data.liquidInfo->depth_level = wmoData->floorZ;
2834 data.liquidInfo->entry = liquidType;
2835 data.liquidInfo->type_flags = 1 << liquidFlagType;
2836
2837 float delta = wmoData->liquidInfo->level - z;
2838 if (delta > collisionHeight)
2840 else if (delta > 0.0f)
2842 else if (delta > -0.1f)
2844 else
2846 }
2847 // look up liquid data from grid map
2848 if (gmap && useGridLiquid)
2849 {
2850 LiquidData gridMapLiquid;
2851 ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid, collisionHeight);
2852 if (gridMapStatus != LIQUID_MAP_NO_WATER && (!wmoData || gridMapLiquid.level > wmoData->floorZ))
2853 {
2854 if (GetId() == 530 && gridMapLiquid.entry == 2)
2855 gridMapLiquid.entry = 15;
2856 data.liquidInfo = gridMapLiquid;
2857 data.liquidStatus = gridMapStatus;
2858 }
2859 }
2860}
2861
2862float Map::GetWaterLevel(float x, float y) const
2863{
2864 if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
2865 return gmap->getLiquidLevel(x, y);
2866 else
2867 return 0;
2868}
2869
2870bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
2871{
2872 if ((checks & LINEOFSIGHT_CHECK_VMAP)
2873 && !VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, ignoreFlags))
2874 return false;
2875 if (sWorld->getBoolConfig(CONFIG_CHECK_GOBJECT_LOS) && (checks & LINEOFSIGHT_CHECK_GOBJECT)
2876 && !_dynamicTree.isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask))
2877 return false;
2878 return true;
2879}
2880
2881bool Map::getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist)
2882{
2883 G3D::Vector3 startPos(x1, y1, z1);
2884 G3D::Vector3 dstPos(x2, y2, z2);
2885
2886 G3D::Vector3 resultPos;
2887 bool result = _dynamicTree.getObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist);
2888
2889 rx = resultPos.x;
2890 ry = resultPos.y;
2891 rz = resultPos.z;
2892 return result;
2893}
2894
2895bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, LiquidData* data) const
2896{
2897 LiquidData liquid_status;
2898 LiquidData* liquid_ptr = data ? data : &liquid_status;
2899 return (GetLiquidStatus(phaseMask, x, y, pZ, {}, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
2900}
2901
2902bool Map::IsUnderWater(uint32 phaseMask, float x, float y, float z) const
2903{
2905}
2906
2907bool Map::CheckGridIntegrity(Creature* c, bool moved) const
2908{
2909 Cell const& cur_cell = c->GetCurrentCell();
2910 Cell xy_cell(c->GetPositionX(), c->GetPositionY());
2911 if (xy_cell != cur_cell)
2912 {
2913 TC_LOG_DEBUG("maps", "Creature {} X: {} Y: {} ({}) is in grid[{}, {}]cell[{}, {}] instead of grid[{}, {}]cell[{}, {}]",
2914 c->GetGUID().ToString(),
2915 c->GetPositionX(), c->GetPositionY(), (moved ? "final" : "original"),
2916 cur_cell.GridX(), cur_cell.GridY(), cur_cell.CellX(), cur_cell.CellY(),
2917 xy_cell.GridX(), xy_cell.GridY(), xy_cell.CellX(), xy_cell.CellY());
2918 return true; // not crash at error, just output error in debug mode
2919 }
2920
2921 return true;
2922}
2923
2924char const* Map::GetMapName() const
2925{
2926 return i_mapEntry ? i_mapEntry->MapName[sWorld->GetDefaultDbcLocale()] : "UNNAMEDMAP\x0";
2927}
2928
2930{
2931 TC_LOG_DEBUG("maps", "Creating player data for himself {}", player->GetGUID().ToString());
2932
2933 WorldPacket packet;
2934 UpdateData data;
2935
2936 // attach to player data current transport data
2937 if (Transport* transport = player->GetTransport())
2938 {
2939 transport->BuildCreateUpdateBlockForPlayer(&data, player);
2940 }
2941
2942 // build data for self presence in world at own client (one time for map)
2943 player->BuildCreateUpdateBlockForPlayer(&data, player);
2944
2945 // build and send self update packet before sending to player his own auras
2946 data.BuildPacket(&packet);
2947 player->SendDirectMessage(&packet);
2948
2949 // send to player his own auras (this is needed here for timely initialization of some fields on client)
2950 player->SendAurasForTarget(player, true);
2951
2952 // clean buffers for further work
2953 packet.clear();
2954 data.Clear();
2955
2956 // build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
2957 if (Transport* transport = player->GetTransport())
2958 for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
2959 if (player != (*itr) && player->HaveAtClient(*itr))
2960 (*itr)->BuildCreateUpdateBlockForPlayer(&data, player);
2961
2962 data.BuildPacket(&packet);
2963 player->SendDirectMessage(&packet);
2964}
2965
2967{
2968 // Hack to send out transports
2969 UpdateData transData;
2970 for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
2971 if (*i != player->GetTransport())
2972 (*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
2973
2974 if (!transData.HasData())
2975 return;
2976
2977 WorldPacket packet;
2978 transData.BuildPacket(&packet);
2979 player->SendDirectMessage(&packet);
2980}
2981
2983{
2984 // Hack to send out transports
2985 UpdateData transData;
2986 for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
2987 if (*i != player->GetTransport())
2988 (*i)->BuildOutOfRangeUpdateBlock(&transData);
2989
2990 if (!transData.HasData())
2991 return;
2992
2993 WorldPacket packet;
2994 transData.BuildPacket(&packet);
2995 player->SendDirectMessage(&packet);
2996}
2997
2998inline void Map::setNGrid(NGridType *grid, uint32 x, uint32 y)
2999{
3001 {
3002 TC_LOG_ERROR("maps", "map::setNGrid() Invalid grid coordinates found: {}, {}!", x, y);
3003 ABORT();
3004 }
3005 i_grids[x][y] = grid;
3006}
3007
3009{
3010 UpdateDataMapType update_players;
3011
3012 while (!_updateObjects.empty())
3013 {
3014 Object* obj = *_updateObjects.begin();
3015 ASSERT(obj->IsInWorld());
3016
3017 _updateObjects.erase(_updateObjects.begin());
3018 obj->BuildUpdate(update_players);
3019 }
3020
3021 WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
3022 for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
3023 {
3024 iter->second.BuildPacket(&packet);
3025 iter->first->SendDirectMessage(&packet);
3026 packet.clear(); // clean the string
3027 }
3028}
3029
3030// CheckRespawn MUST do one of the following:
3031// -) return true
3032// -) set info->respawnTime to zero, which indicates the respawn time should be deleted (and will never be processed again without outside intervention)
3033// -) set info->respawnTime to a new respawn time, which must be strictly GREATER than the current time (GameTime::GetGameTime())
3035{
3036 SpawnData const* data = sObjectMgr->GetSpawnData(info->type, info->spawnId);
3037 ASSERT(data, "Invalid respawn info with type %u, spawnID %u in respawn queue.", info->type, info->spawnId);
3038
3039 // First, check if this creature's spawn group is inactive
3041 {
3042 info->respawnTime = 0;
3043 return false;
3044 }
3045
3046 // Next, check if there's already an instance of this object that would block the respawn
3047 bool alreadyExists = false;
3048 switch (info->type)
3049 {
3051 {
3052 // escort check for creatures only (if the world config boolean is set)
3053 bool const isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && data->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC);
3054
3055 auto range = _creatureBySpawnIdStore.equal_range(info->spawnId);
3056 for (auto it = range.first; it != range.second; ++it)
3057 {
3058 Creature* creature = it->second;
3059 if (!creature->IsAlive())
3060 continue;
3061 // escort NPCs are allowed to respawn as long as all other instances are already escorting
3062 if (isEscort && creature->IsEscorted())
3063 continue;
3064 alreadyExists = true;
3065 break;
3066 }
3067 break;
3068 }
3070 // gameobject check is simpler - they cannot be dead or escorting
3072 alreadyExists = true;
3073 break;
3074 default:
3075 ABORT_MSG("Invalid spawn type %u with spawnId %u on map %u", uint32(info->type), info->spawnId, GetId());
3076 return true;
3077 }
3078 if (alreadyExists)
3079 {
3080 info->respawnTime = 0;
3081 return false;
3082 }
3083
3084 // next, check linked respawn time
3085 ObjectGuid thisGUID = info->type == SPAWN_TYPE_GAMEOBJECT
3086 ? ObjectGuid::Create<HighGuid::GameObject>(info->entry, info->spawnId)
3087 : ObjectGuid::Create<HighGuid::Unit>(info->entry, info->spawnId);
3088 if (time_t linkedTime = GetLinkedRespawnTime(thisGUID))
3089 {
3090 time_t now = GameTime::GetGameTime();
3091 time_t respawnTime;
3092 if (linkedTime == std::numeric_limits<time_t>::max())
3093 respawnTime = linkedTime;
3094 else if (sObjectMgr->GetLinkedRespawnGuid(thisGUID) == thisGUID) // never respawn, save "something" in DB
3095 respawnTime = now + WEEK;
3096 else // set us to check again shortly after linked unit
3097 respawnTime = std::max<time_t>(now, linkedTime) + urand(5, 15);
3098 info->respawnTime = respawnTime;
3099 return false;
3100 }
3101 // everything ok, let's spawn
3102 return true;
3103}
3104
3106{
3107 if (info->respawnTime <= GameTime::GetGameTime())
3108 return;
3110 _respawnTimes->increase(static_cast<RespawnInfoWithHandle*>(info)->handle);
3111 SaveRespawnInfoDB(*info, dbTrans);
3112}
3113
3115{
3116 std::vector<WorldObject*> toUnload;
3117 switch (type)
3118 {
3120 for (auto const& pair : Trinity::Containers::MapEqualRange(GetCreatureBySpawnIdStore(), spawnId))
3121 toUnload.push_back(pair.second);
3122 break;
3124 for (auto const& pair : Trinity::Containers::MapEqualRange(GetGameObjectBySpawnIdStore(), spawnId))
3125 toUnload.push_back(pair.second);
3126 break;
3127 default:
3128 break;
3129 }
3130
3131 for (WorldObject* o : toUnload)
3133
3134 return toUnload.size();
3135}
3136
3138{
3139 if (!info.spawnId)
3140 {
3141 TC_LOG_ERROR("maps", "Attempt to insert respawn info for zero spawn id (type {})", uint32(info.type));
3142 return false;
3143 }
3144
3145 RespawnInfoMap& bySpawnIdMap = GetRespawnMapForType(info.type);
3146
3147 // check if we already have the maximum possible number of respawns scheduled
3148 if (SpawnData::TypeHasData(info.type))
3149 {
3150 auto it = bySpawnIdMap.find(info.spawnId);
3151 if (it != bySpawnIdMap.end()) // spawnid already has a respawn scheduled
3152 {
3153 RespawnInfo* const existing = it->second;
3154 if (info.respawnTime < existing->respawnTime) // delete existing in this case
3155 DeleteRespawnInfo(existing);
3156 else
3157 return false;
3158 }
3159 ASSERT(bySpawnIdMap.find(info.spawnId) == bySpawnIdMap.end(), "Insertion of respawn info with id (%u,%u) into spawn id map failed - state desync.", uint32(info.type), info.spawnId);
3160 }
3161 else
3162 ABORT_MSG("Invalid respawn info for spawn id (%u,%u) being inserted", uint32(info.type), info.spawnId);
3163
3165 ri->handle = _respawnTimes->push(ri);
3166 bySpawnIdMap.emplace(ri->spawnId, ri);
3167 return true;
3168}
3169
3170static void PushRespawnInfoFrom(std::vector<RespawnInfo const*>& data, RespawnInfoMap const& map)
3171{
3172 data.reserve(data.size() + map.size());
3173 for (auto const& pair : map)
3174 data.push_back(pair.second);
3175}
3176
3177void Map::GetRespawnInfo(std::vector<RespawnInfo const*>& respawnData, SpawnObjectTypeMask types) const
3178{
3179 if (types & SPAWN_TYPEMASK_CREATURE)
3181 if (types & SPAWN_TYPEMASK_GAMEOBJECT)
3183}
3184
3186{
3187 RespawnInfoMap const& map = GetRespawnMapForType(type);
3188 auto it = map.find(spawnId);
3189 if (it == map.end())
3190 return nullptr;
3191 return it->second;
3192}
3193
3194void Map::UnloadAllRespawnInfos() // delete everything from memory
3195{
3196 for (RespawnInfo* info : *_respawnTimes)
3197 delete info;
3198 _respawnTimes->clear();
3201}
3202
3204{
3205 // Delete from all relevant containers to ensure consistency
3206 ASSERT(info);
3207
3208 // spawnid store
3209 auto& spawnMap = GetRespawnMapForType(info->type);
3210 auto range = spawnMap.equal_range(info->spawnId);
3211 auto it = std::find_if(range.first, range.second, [info](RespawnInfoMap::value_type const& pair) { return (pair.second == info); });
3212 ASSERT(it != range.second, "Respawn stores inconsistent for map %u, spawnid %u (type %u)", GetId(), info->spawnId, uint32(info->type));
3213 spawnMap.erase(it);
3214
3215 // respawn heap
3216 _respawnTimes->erase(static_cast<RespawnInfoWithHandle*>(info)->handle);
3217
3218 // database
3219 DeleteRespawnInfoFromDB(info->type, info->spawnId, dbTrans);
3220
3221 // then cleanup the object
3222 delete info;
3223}
3224
3226{
3228 stmt->setUInt16(0, type);
3229 stmt->setUInt32(1, spawnId);
3230 stmt->setUInt16(2, GetId());
3231 stmt->setUInt32(3, GetInstanceId());
3232 CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
3233}
3234
3236{
3237 if (!IsGridLoaded(gridId)) // if grid isn't loaded, this will be processed in grid load handler
3238 return;
3239
3240 switch (type)
3241 {
3243 {
3244 Creature* obj = new Creature();
3245 if (!obj->LoadFromDB(spawnId, this, true, true))
3246 delete obj;
3247 break;
3248 }
3250 {
3251 GameObject* obj = new GameObject();
3252 if (!obj->LoadFromDB(spawnId, this, true))
3253 delete obj;
3254 break;
3255 }
3256 default:
3257 ABORT_MSG("Invalid spawn type %u (spawnid %u) on map %u", uint32(type), spawnId, GetId());
3258 }
3259}
3260
3262{
3263 time_t now = GameTime::GetGameTime();
3264 while (!_respawnTimes->empty())
3265 {
3266 RespawnInfoWithHandle* next = _respawnTimes->top();
3267 if (now < next->respawnTime) // done for this tick
3268 break;
3269
3270 if (uint32 poolId = sPoolMgr->IsPartOfAPool(next->type, next->spawnId)) // is this part of a pool?
3271 { // if yes, respawn will be handled by (external) pooling logic, just delete the respawn time
3272 // step 1: remove entry from maps to avoid it being reachable by outside logic
3273 _respawnTimes->pop();
3274 GetRespawnMapForType(next->type).erase(next->spawnId);
3275
3276 // step 2: tell pooling logic to do its thing
3277 sPoolMgr->UpdatePool(poolId, next->type, next->spawnId);
3278
3279 // step 3: get rid of the actual entry
3280 RemoveRespawnTime(next->type, next->spawnId, nullptr, true);
3281 delete next;
3282 }
3283 else if (CheckRespawn(next)) // see if we're allowed to respawn
3284 { // ok, respawn
3285 // step 1: remove entry from maps to avoid it being reachable by outside logic
3286 _respawnTimes->pop();
3287 GetRespawnMapForType(next->type).erase(next->spawnId);
3288
3289 // step 2: do the respawn, which involves external logic
3290 DoRespawn(next->type, next->spawnId, next->gridId);
3291
3292 // step 3: get rid of the actual entry
3293 RemoveRespawnTime(next->type, next->spawnId, nullptr, true);
3294 delete next;
3295 }
3296 else if (!next->respawnTime)
3297 { // just remove this respawn entry without rescheduling
3298 _respawnTimes->pop();
3299 GetRespawnMapForType(next->type).erase(next->spawnId);
3300 RemoveRespawnTime(next->type, next->spawnId, nullptr, true);
3301 delete next;
3302 }
3303 else
3304 { // new respawn time, update heap position
3305 ASSERT(now < next->respawnTime); // infinite loop guard
3306 _respawnTimes->decrease(next->handle);
3307 SaveRespawnInfoDB(*next);
3308 }
3309 }
3310}
3311
3312void Map::ApplyDynamicModeRespawnScaling(WorldObject const* obj, ObjectGuid::LowType spawnId, uint32& respawnDelay, uint32 mode) const
3313{
3314 ASSERT(mode == 1);
3315 ASSERT(obj->GetMap() == this);
3316
3318 return;
3319
3320 SpawnObjectType type;
3321 switch (obj->GetTypeId())
3322 {
3323 case TYPEID_UNIT:
3324 type = SPAWN_TYPE_CREATURE;
3325 break;
3326 case TYPEID_GAMEOBJECT:
3327 type = SPAWN_TYPE_GAMEOBJECT;
3328 break;
3329 default:
3330 return;
3331 }
3332
3333 SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId);
3334 if (!data)
3335 return;
3336
3338 return;
3339
3340 auto it = _zonePlayerCountMap.find(obj->GetZoneId());
3341 if (it == _zonePlayerCountMap.end())
3342 return;
3343 uint32 const playerCount = it->second;
3344 if (!playerCount)
3345 return;
3346 double const adjustFactor = sWorld->getFloatConfig(type == SPAWN_TYPE_GAMEOBJECT ? CONFIG_RESPAWN_DYNAMICRATE_GAMEOBJECT : CONFIG_RESPAWN_DYNAMICRATE_CREATURE) / playerCount;
3347 if (adjustFactor >= 1.0) // nothing to do here
3348 return;
3350 if (respawnDelay <= timeMinimum)
3351 return;
3352
3353 respawnDelay = std::max<uint32>(ceil(respawnDelay * adjustFactor), timeMinimum);
3354}
3355
3357{
3359
3360 // check if the object is on its respawn timer
3361 if (GetRespawnTime(type, spawnId))
3362 return false;
3363
3364 SpawnMetadata const* spawnData = ASSERT_NOTNULL(sObjectMgr->GetSpawnMetadata(type, spawnId));
3365 // check if the object is part of a spawn group
3366 SpawnGroupTemplateData const* spawnGroup = ASSERT_NOTNULL(spawnData->spawnGroupData);
3367 if (!(spawnGroup->flags & SPAWNGROUP_FLAG_SYSTEM))
3368 if (!IsSpawnGroupActive(spawnGroup->groupId))
3369 return false;
3370
3371 return true;
3372}
3373
3375{
3376 SpawnGroupTemplateData const* data = sObjectMgr->GetSpawnGroupData(groupId);
3377 if (data && (data->flags & SPAWNGROUP_FLAG_SYSTEM || data->mapId == GetId()))
3378 return data;
3379 return nullptr;
3380}
3381
3382bool Map::SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn, bool force, std::vector<WorldObject*>* spawnedObjects)
3383{
3384 SpawnGroupTemplateData const* groupData = GetSpawnGroupData(groupId);
3385 if (!groupData || groupData->flags & SPAWNGROUP_FLAG_SYSTEM)
3386 {
3387 TC_LOG_ERROR("maps", "Tried to spawn non-existing (or system) spawn group {} on map {}. Blocked.", groupId, GetId());
3388 return false;
3389 }
3390
3391 SetSpawnGroupActive(groupId, true); // start processing respawns for the group
3392
3393 std::vector<SpawnData const*> toSpawn;
3394 for (auto& pair : sObjectMgr->GetSpawnMetadataForGroup(groupId))
3395 {
3396 SpawnMetadata const* data = pair.second;
3397 ASSERT(groupData->mapId == data->mapId);
3398
3399 if (force || ignoreRespawn)
3400 RemoveRespawnTime(data->type, data->spawnId);
3401
3402 uint32 nRespawnTimers = GetRespawnMapForType(data->type).count(data->spawnId);
3403 if (SpawnData::TypeHasData(data->type))
3404 {
3405 // has a respawn timer
3406 if (nRespawnTimers)
3407 continue;
3408
3409 // has a spawn already active
3410 if (!force)
3411 if (WorldObject* obj = GetWorldObjectBySpawnId(data->type, data->spawnId))
3412 if ((data->type != SPAWN_TYPE_CREATURE) || obj->ToCreature()->IsAlive())
3413 continue;
3414
3415 toSpawn.push_back(ASSERT_NOTNULL(data->ToSpawnData()));
3416 }
3417 }
3418
3419 for (SpawnData const* data : toSpawn)
3420 {
3421 // don't spawn if the current map difficulty is not used by the spawn
3422 if (!(data->spawnMask & (1 << GetSpawnMode())))
3423 continue;
3424
3425 // don't spawn if the grid isn't loaded (will be handled in grid loader)
3426 if (!IsGridLoaded(data->spawnPoint))
3427 continue;
3428
3429 // now do the actual (re)spawn
3430 switch (data->type)
3431 {
3433 {
3434 Creature* creature = new Creature();
3435 if (!creature->LoadFromDB(data->spawnId, this, true, force))
3436 delete creature;
3437 else if (spawnedObjects)
3438 spawnedObjects->push_back(creature);
3439 break;
3440 }
3442 {
3443 GameObject* gameobject = new GameObject();
3444 if (!gameobject->LoadFromDB(data->spawnId, this, true))
3445 delete gameobject;
3446 else if (spawnedObjects)
3447 spawnedObjects->push_back(gameobject);
3448 break;
3449 }
3450 default:
3451 ABORT_MSG("Invalid spawn type %u with spawnId %u", uint32(data->type), data->spawnId);
3452 return false;
3453 }
3454 }
3455 return true;
3456}
3457
3458bool Map::SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes, size_t* count)
3459{
3460 SpawnGroupTemplateData const* groupData = GetSpawnGroupData(groupId);
3461 if (!groupData || groupData->flags & SPAWNGROUP_FLAG_SYSTEM)
3462 {
3463 TC_LOG_ERROR("maps", "Tried to despawn non-existing (or system) spawn group {} on map {}. Blocked.", groupId, GetId());
3464 return false;
3465 }
3466
3467 for (auto const& pair : sObjectMgr->GetSpawnMetadataForGroup(groupId))
3468 {
3469 SpawnMetadata const* data = pair.second;
3470 ASSERT(groupData->mapId == data->mapId);
3471 if (deleteRespawnTimes)
3472 RemoveRespawnTime(data->type, data->spawnId);
3473 size_t c = DespawnAll(data->type, data->spawnId);
3474 if (count)
3475 *count += c;
3476 }
3477 SetSpawnGroupActive(groupId, false); // stop processing respawns for the group, too
3478 return true;
3479}
3480
3481void Map::SetSpawnGroupActive(uint32 groupId, bool state)
3482{
3483 SpawnGroupTemplateData const* const data = GetSpawnGroupData(groupId);
3484 if (!data || data->flags & SPAWNGROUP_FLAG_SYSTEM)
3485 {
3486 TC_LOG_ERROR("maps", "Tried to set non-existing (or system) spawn group {} to {} on map {}. Blocked.", groupId, state ? "active" : "inactive", GetId());
3487 return;
3488 }
3489 if (state != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN)) // toggled
3490 _toggledSpawnGroupIds.insert(groupId);
3491 else
3492 _toggledSpawnGroupIds.erase(groupId);
3493}
3494
3496{
3497 SpawnGroupTemplateData const* const data = GetSpawnGroupData(groupId);
3498 if (!data)
3499 {
3500 TC_LOG_ERROR("maps", "Tried to query state of non-existing spawn group {} on map {}.", groupId, GetId());
3501 return false;
3502 }
3503 if (data->flags & SPAWNGROUP_FLAG_SYSTEM)
3504 return true;
3505 // either manual spawn group and toggled, or not manual spawn group and not toggled...
3506 return (_toggledSpawnGroupIds.find(groupId) != _toggledSpawnGroupIds.end()) != !(data->flags & SPAWNGROUP_FLAG_MANUAL_SPAWN);
3507}
3508
3510{
3511 auto itr = _guidGenerators.find(high);
3512 if (itr == _guidGenerators.end())
3513 itr = _guidGenerators.insert(std::make_pair(high, std::make_unique<ObjectGuidGenerator>(high))).first;
3514
3515 return *itr->second;
3516}
3517
3519{
3520 _farSpellCallbacks.Enqueue(new FarSpellCallback(std::move(callback)));
3521}
3522
3524{
3525 {
3526 FarSpellCallback* callback;
3527 while (_farSpellCallbacks.Dequeue(callback))
3528 {
3529 (*callback)(this);
3530 delete callback;
3531 }
3532 }
3533
3535 {
3536 Transport* transport = *_transportsUpdateIter;
3538
3539 if (!transport->IsInWorld())
3540 continue;
3541
3542 transport->DelayedUpdate(t_diff);
3543 }
3544
3546
3547 // 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 !
3548 // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
3549 if (!IsBattlegroundOrArena())
3550 {
3552 {
3553 NGridType *grid = i->GetSource();
3554 GridInfo* info = i->GetSource()->getGridInfoRef();
3555 ++i; // The update might delete the map and we need the next map before the iterator gets invalid
3556 ASSERT(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
3557 si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, t_diff);
3558 }
3559 }
3560}
3561
3563{
3564 ASSERT(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId());
3565
3566 obj->CleanupsBeforeDelete(false); // remove or simplify at least cross referenced links
3567
3568 i_objectsToRemove.insert(obj);
3569}
3570
3572{
3573 ASSERT(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId());
3574 // i_objectsToSwitch is iterated only in Map::RemoveAllObjectsInRemoveList() and it uses
3575 // the contained objects only if GetTypeId() == TYPEID_UNIT , so we can return in all other cases
3576 if (obj->GetTypeId() != TYPEID_UNIT && obj->GetTypeId() != TYPEID_GAMEOBJECT)
3577 return;
3578
3579 std::map<WorldObject*, bool>::iterator itr = i_objectsToSwitch.find(obj);
3580 if (itr == i_objectsToSwitch.end())
3581 i_objectsToSwitch.insert(itr, std::make_pair(obj, on));
3582 else if (itr->second != on)
3583 i_objectsToSwitch.erase(itr);
3584 else
3585 ABORT();
3586}
3587
3589{
3590 while (!i_objectsToSwitch.empty())
3591 {
3592 std::map<WorldObject*, bool>::iterator itr = i_objectsToSwitch.begin();
3593 WorldObject* obj = itr->first;
3594 bool on = itr->second;
3595 i_objectsToSwitch.erase(itr);
3596
3598 {
3599 switch (obj->GetTypeId())
3600 {
3601 case TYPEID_UNIT:
3602 SwitchGridContainers<Creature>(obj->ToCreature(), on);
3603 break;
3604 case TYPEID_GAMEOBJECT:
3605 SwitchGridContainers<GameObject>(obj->ToGameObject(), on);
3606 break;
3607 default:
3608 break;
3609 }
3610 }
3611 }
3612
3613 //TC_LOG_DEBUG("maps", "Object remover 1 check.");
3614 while (!i_objectsToRemove.empty())
3615 {
3616 std::set<WorldObject*>::iterator itr = i_objectsToRemove.begin();
3617 WorldObject* obj = *itr;
3618
3619 switch (obj->GetTypeId())
3620 {
3621 case TYPEID_CORPSE:
3622 {
3623 Corpse* corpse = ObjectAccessor::GetCorpse(*obj, obj->GetGUID());
3624 if (!corpse)
3625 TC_LOG_ERROR("maps", "Tried to delete corpse/bones {} that is not in map.", obj->GetGUID().ToString());
3626 else
3627 RemoveFromMap(corpse, true);
3628 break;
3629 }
3631 RemoveFromMap(obj->ToDynObject(), true);
3632 break;
3633 case TYPEID_GAMEOBJECT:
3634 {
3635 GameObject* go = obj->ToGameObject();
3636 if (Transport* transport = go->ToTransport())
3637 RemoveFromMap(transport, true);
3638 else
3639 RemoveFromMap(go, true);
3640 break;
3641 }
3642 case TYPEID_UNIT:
3643 // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call
3644 // make sure that like sources auras/etc removed before destructor start
3646 RemoveFromMap(obj->ToCreature(), true);
3647 break;
3648 default:
3649 TC_LOG_ERROR("maps", "Non-grid object (TypeId: {}) is in grid object remove list, ignored.", obj->GetTypeId());
3650 break;
3651 }
3652
3653 i_objectsToRemove.erase(itr);
3654 }
3655
3656 //TC_LOG_DEBUG("maps", "Object remover 2 check.");
3657}
3658
3660{
3661 uint32 count = 0;
3663 if (!itr->GetSource()->IsGameMaster())
3664 ++count;
3665 return count;
3666}
3667
3668void Map::SendToPlayers(WorldPacket const* data) const
3669{
3671 itr->GetSource()->SendDirectMessage(data);
3672}
3673
3675bool Map::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession const* self, uint32 team) const
3676{
3677 bool foundPlayerToSend = false;
3678
3679 for (MapReference const& ref : GetPlayers())
3680 {
3681 Player* player = ref.GetSource();
3682 if (player->IsInWorld() &&
3683 player->GetZoneId() == zone &&
3684 player->GetSession() != self &&
3685 (team == 0 || player->GetTeam() == team))
3686 {
3687 player->SendDirectMessage(packet);
3688 foundPlayerToSend = true;
3689 }
3690 }
3691
3692 return foundPlayerToSend;
3693}
3694
3696{
3697 CellCoord cell_min(ngrid.getX() * MAX_NUMBER_OF_CELLS, ngrid.getY() * MAX_NUMBER_OF_CELLS);
3698 CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
3699
3700 //we must find visible range in cells so we unload only non-visible cells...
3701 float viewDist = GetVisibilityRange();
3702 int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1;
3703
3704 cell_min.dec_x(cell_range);
3705 cell_min.dec_y(cell_range);
3706 cell_max.inc_x(cell_range);
3707 cell_max.inc_y(cell_range);
3708
3710 {
3711 Player* player = iter->GetSource();
3712
3714 if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
3715 (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord))
3716 return true;
3717 }
3718
3719 for (ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter)
3720 {
3721 WorldObject* obj = *iter;
3722
3724 if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
3725 (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord))
3726 return true;
3727 }
3728
3729 return false;
3730}
3731
3733{
3734 AddToActiveHelper(obj);
3735
3736 Optional<Position> respawnLocation;
3737 switch (obj->GetTypeId())
3738 {
3739 case TYPEID_UNIT:
3740 if (Creature* creature = obj->ToCreature(); !creature->IsPet() && creature->GetSpawnId())
3741 {
3742 respawnLocation.emplace();
3743 creature->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
3744 }
3745 break;
3746 case TYPEID_GAMEOBJECT:
3747 if (GameObject* gameObject = obj->ToGameObject(); gameObject->GetSpawnId())
3748 {
3749 respawnLocation.emplace();
3750 gameObject->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
3751 }
3752 break;
3753 default:
3754 break;
3755 }
3756
3757 if (respawnLocation)
3758 {
3759 GridCoord p = Trinity::ComputeGridCoord(respawnLocation->GetPositionX(), respawnLocation->GetPositionY());
3760 if (getNGrid(p.x_coord, p.y_coord))
3762 else
3763 {
3765 TC_LOG_ERROR("maps", "Active object {} added to grid[{}, {}] but spawn grid[{}, {}] was not loaded.",
3766 obj->GetGUID().ToString(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
3767 }
3768 }
3769}
3770
3772{
3774
3775 Optional<Position> respawnLocation;
3776 switch (obj->GetTypeId())
3777 {
3778 case TYPEID_UNIT:
3779 if (Creature* creature = obj->ToCreature(); !creature->IsPet() && creature->GetSpawnId())
3780 {
3781 respawnLocation.emplace();
3782 creature->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
3783 }
3784 break;
3785 case TYPEID_GAMEOBJECT:
3786 if (GameObject* gameObject = obj->ToGameObject(); gameObject->GetSpawnId())
3787 {
3788 respawnLocation.emplace();
3789 gameObject->GetRespawnPosition(respawnLocation->m_positionX, respawnLocation->m_positionY, respawnLocation->m_positionZ);
3790 }
3791 break;
3792 default:
3793 break;
3794 }
3795
3796 if (respawnLocation)
3797 {
3798 GridCoord p = Trinity::ComputeGridCoord(respawnLocation->GetPositionX(), respawnLocation->GetPositionY());
3799 if (getNGrid(p.x_coord, p.y_coord))
3801 else
3802 {
3804 TC_LOG_ERROR("maps", "Active object {} removed from grid[{}, {}] but spawn grid[{}, {}] was not loaded.",
3805 obj->GetGUID().ToString(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
3806 }
3807 }
3808}
3809
3810template TC_GAME_API bool Map::AddToMap(Corpse*);
3811template TC_GAME_API bool Map::AddToMap(Creature*);
3812template TC_GAME_API bool Map::AddToMap(GameObject*);
3814
3815template TC_GAME_API void Map::RemoveFromMap(Corpse*, bool);
3816template TC_GAME_API void Map::RemoveFromMap(Creature*, bool);
3817template TC_GAME_API void Map::RemoveFromMap(GameObject*, bool);
3818template TC_GAME_API void Map::RemoveFromMap(DynamicObject*, bool);
3819
3820/* ******* Dungeon Instance Maps ******* */
3821
3822InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent, TeamId InstanceTeam)
3823 : Map(id, expiry, InstanceId, SpawnMode, _parent),
3824 m_resetAfterUnload(false), m_unloadWhenEmpty(false),
3825 i_data(nullptr), i_script_id(0), i_script_team(InstanceTeam)
3826{
3827 //lets initialize visibility distance for dungeons
3829
3830 // the timer is started by default, and stopped when the first player joins
3831 // this make sure it gets unloaded if for some reason no player joins
3833}
3834
3836{
3837 delete i_data;
3838 i_data = nullptr;
3839}
3840
3847
3848/*
3849 Do map specific checks to see if the player can enter
3850*/
3852{
3853 if (player->GetMapRef().getTarget() == this)
3854 {
3855 TC_LOG_ERROR("maps", "InstanceMap::CannotEnter - player {} {} already in map {}, {}, {}!", player->GetName(), player->GetGUID().ToString(), GetId(), GetInstanceId(), GetSpawnMode());
3856 ABORT();
3858 }
3859
3860 // allow GM's to enter
3861 if (player->IsGameMaster())
3862 return Map::CannotEnter(player);
3863
3864 // cannot enter if the instance is full (player cap), GMs don't count
3865 uint32 maxPlayers = GetMaxPlayers();
3866 if (GetPlayersCountExceptGMs() >= maxPlayers)
3867 {
3868 TC_LOG_WARN("maps", "MAP: Instance '{}' of map '{}' cannot have more than '{}' players. Player '{}' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName());
3870 }
3871
3872 // cannot enter while an encounter is in progress (unless this is a relog, in which case it is permitted)
3873 if (!player->IsLoading() && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
3875
3876 // cannot enter if player is permanent saved to a different instance id
3877 if (InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficultyID()))
3878 if (playerBind->perm && playerBind->save)
3879 if (playerBind->save->GetInstanceId() != GetInstanceId())
3881
3882 return Map::CannotEnter(player);
3883}
3884
3885/*
3886 Do map specific checks and add the player to the map if successful.
3887*/
3889{
3891 // GMs still can teleport player in instance.
3892 // Is it needed?
3893
3894 {
3895 std::lock_guard<std::mutex> lock(_mapLock);
3896 // Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
3897 //if (!CanEnter(player))
3898 //return false;
3899
3900 // Dungeon only code
3901 if (IsDungeon())
3902 {
3903 Group* group = player->GetGroup();
3904
3905 // increase current instances (hourly limit)
3906 if (!group || !group->isLFGGroup())
3908
3909 // get or create an instance save for the map
3910 InstanceSave* mapSave = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
3911 if (!mapSave)
3912 {
3913 TC_LOG_DEBUG("maps", "InstanceMap::Add: creating instance save for map {} spawnmode {} with instance id {}", GetId(), GetSpawnMode(), GetInstanceId());
3914 mapSave = sInstanceSaveMgr->AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true);
3915 }
3916
3917 ASSERT(mapSave);
3918
3919 // check for existing instance binds
3921 if (playerBind && playerBind->perm)
3922 {
3923 // cannot enter other instances if bound permanently
3924 if (playerBind->save != mapSave)
3925 {
3926 TC_LOG_ERROR("maps", "InstanceMap::Add: player {} {} is permanently bound to instance {} {}, {}, {}, {}, {}, {} but he is being put into instance {} {}, {}, {}, {}, {}, {}", player->GetName(), player->GetGUID().ToString(), GetMapName(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset());
3927 return false;
3928 }
3929 }
3930 else
3931 {
3932 if (group)
3933 {
3934 // solo saves should have been reset when the map was loaded
3935 InstanceGroupBind* groupBind = group->GetBoundInstance(this);
3936 if (playerBind && playerBind->save != mapSave)
3937 {
3938 TC_LOG_ERROR("maps", "InstanceMap::Add: player {} {} is being put into instance {} {}, {}, {}, {}, {}, {} but he is in group {} and is bound to instance {}, {}, {}, {}, {}, {}!", player->GetName(), player->GetGUID().ToString(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficultyID()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset());
3939 if (groupBind)
3940 TC_LOG_ERROR("maps", "InstanceMap::Add: the group is bound to the instance {} {}, {}, {}, {}, {}, {}", GetMapName(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()), groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount(), groupBind->save->CanReset());
3941 //ABORT();
3942 return false;
3943 }
3944 // bind to the group or keep using the group save
3945 if (!groupBind)
3946 group->BindToInstance(mapSave, false);
3947 else
3948 {
3949 // cannot jump to a different instance without resetting it
3950 if (groupBind->save != mapSave)
3951 {
3952 TC_LOG_ERROR("maps", "InstanceMap::Add: player {} {} is being put into instance {}, {}, {} but he is in group {} which is bound to instance {}, {}, {}!", player->GetName(), player->GetGUID().ToString(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficultyID()), group->GetLeaderGUID().ToString(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficultyID()));
3953 TC_LOG_ERROR("maps", "MapSave players: {}, group count: {}", mapSave->GetPlayerCount(), mapSave->GetGroupCount());
3954 if (groupBind->save)
3955 TC_LOG_ERROR("maps", "GroupBind save players: {}, group count: {}", groupBind->save->GetPlayerCount(), groupBind->save->GetGroupCount());
3956 else
3957 TC_LOG_ERROR("maps", "GroupBind save NULL");
3958 return false;
3959 }
3960 // if the group/leader is permanently bound to the instance
3961 // players also become permanently bound when they enter
3962 if (groupBind->perm)
3963 {
3965 data << uint32(60000);
3967 data << uint8(0);
3968 player->SendDirectMessage(&data);
3969 player->SetPendingBind(mapSave->GetInstanceId(), 60000);
3970 }
3971 }
3972 }
3973 else
3974 {
3975 // set up a solo bind or continue using it
3976 if (!playerBind)
3977 player->BindToInstance(mapSave, false);
3978 else
3979 // cannot jump to a different instance without resetting it
3980 ASSERT(playerBind->save == mapSave);
3981 }
3982 }
3983 }
3984
3985 // for normal instances cancel the reset schedule when the
3986 // first player enters (no players yet)
3987 SetResetSchedule(false);
3988
3989 TC_LOG_DEBUG("maps", "MAP: Player '{}' entered instance '{}' of map '{}'", player->GetName(), GetInstanceId(), GetMapName());
3990 // initialize unload state
3991 m_unloadTimer = 0;
3992 m_resetAfterUnload = false;
3993 m_unloadWhenEmpty = false;
3994 }
3995
3996 // this will acquire the same mutex so it cannot be in the previous block
3997 Map::AddPlayerToMap(player);
3998
3999 if (i_data)
4000 i_data->OnPlayerEnter(player);
4001
4002 return true;
4003}
4004
4006{
4007 Map::Update(t_diff);
4008
4009 if (i_data)
4010 i_data->Update(t_diff);
4011}
4012
4014{
4015 TC_LOG_DEBUG("maps", "MAP: Removing player '{}' from instance '{}' of map '{}' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName());
4016
4017 if (i_data)
4018 i_data->OnPlayerLeave(player);
4019
4020 // if last player set unload timer
4021 if (!m_unloadTimer && m_mapRefManager.getSize() == 1)
4023
4024 Map::RemovePlayerFromMap(player, remove);
4025
4026 // for normal instances schedule the reset after all players have left
4027 SetResetSchedule(true);
4028 sInstanceSaveMgr->UnloadInstanceSave(GetInstanceId());
4029}
4030
4032{
4033 if (i_data != nullptr)
4034 return;
4035
4036 InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(GetId());
4037 if (mInstance)
4038 {
4039 i_script_id = mInstance->ScriptId;
4040 i_data = sScriptMgr->CreateInstanceData(this);
4041 }
4042
4043 if (!i_data)
4044 return;
4045
4046 if (load)
4047 {
4050 stmt->setUInt16(0, uint16(GetId()));
4051 stmt->setUInt32(1, i_InstanceId);
4052 PreparedQueryResult result = CharacterDatabase.Query(stmt);
4053
4054 if (result)
4055 {
4056 Field* fields = result->Fetch();
4057 std::string data = fields[0].GetString();
4058 i_data->SetCompletedEncountersMask(fields[1].GetUInt32());
4059 if (!data.empty())
4060 {
4061 TC_LOG_DEBUG("maps", "Loading instance data for `{}` with id {}", sObjectMgr->GetScriptName(i_script_id), i_InstanceId);
4062 i_data->Load(data.c_str());
4063 }
4064 }
4065 }
4066 else
4067 i_data->Create();
4068}
4069
4070/*
4071 Returns true if there are no players in the instance
4072*/
4074{
4075 // note: since the map may not be loaded when the instance needs to be reset
4076 // the instance must be deleted from the DB by InstanceSaveManager
4077
4078 if (HavePlayers())
4079 {
4080 if (method == INSTANCE_RESET_ALL || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
4081 {
4082 // notify the players to leave the instance so it can be reset
4083 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
4084 itr->GetSource()->SendResetFailedNotify(GetId());
4085 }
4086 else
4087 {
4088 bool doUnload = true;
4089 if (method == INSTANCE_RESET_GLOBAL)
4090 {
4091 // set the homebind timer for players inside (1 minute)
4092 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
4093 {
4094 InstancePlayerBind* bind = itr->GetSource()->GetBoundInstance(GetId(), GetDifficultyID());
4095 if (bind && bind->extendState && bind->save->GetInstanceId() == GetInstanceId())
4096 doUnload = false;
4097 else
4098 itr->GetSource()->m_InstanceValid = false;
4099 }
4100
4101 if (doUnload && HasPermBoundPlayers()) // check if any unloaded players have a nonexpired save to this
4102 doUnload = false;
4103 }
4104
4105 if (doUnload)
4106 {
4107 // the unload timer is not started
4108 // instead the map will unload immediately after the players have left
4109 m_unloadWhenEmpty = true;
4110 m_resetAfterUnload = true;
4111 }
4112 }
4113 }
4114 else
4115 {
4116 // unloaded at next update
4119 }
4120
4121 return m_mapRefManager.isEmpty();
4122}
4123
4124std::string const& InstanceMap::GetScriptName() const
4125{
4126 return sObjectMgr->GetScriptName(i_script_id);
4127}
4128
4130{
4131 if (!IsDungeon())
4132 return;
4133
4134 InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(GetInstanceId());
4135 if (!save)
4136 {
4137 TC_LOG_ERROR("maps", "Cannot bind players to instance map (Name: {}, Entry: {}, Difficulty: {}, ID: {}) because no instance save is available!", GetMapName(), GetId(), static_cast<uint32>(GetDifficultyID()), GetInstanceId());
4138 return;
4139 }
4140
4141 // perm bind all players that are currently inside the instance
4142 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
4143 {
4144 Player* player = itr->GetSource();
4145 // never instance bind GMs with GM mode enabled
4146 if (player->IsGameMaster())
4147 continue;
4148
4149 InstancePlayerBind* bind = player->GetBoundInstance(save->GetMapId(), save->GetDifficultyID());
4150 if (bind && bind->perm)
4151 {
4152 if (bind->save && bind->save->GetInstanceId() != save->GetInstanceId())
4153 {
4154 TC_LOG_ERROR("maps", "Player ({}, Name: {}) is in instance map (Name: {}, Entry: {}, Difficulty: {}, ID: {}) that is being bound, but already has a save for the map on ID {}!", player->GetGUID().ToString(), player->GetName(), GetMapName(), save->GetMapId(), static_cast<uint32>(save->GetDifficultyID()), save->GetInstanceId(), bind->save->GetInstanceId());
4155 }
4156 else if (!bind->save)
4157 {
4158 TC_LOG_ERROR("maps", "Player ({}, Name: {}) is in instance map (Name: {}, Entry: {}, Difficulty: {}, ID: {}) that is being bound, but already has a bind (without associated save) for the map!", player->GetGUID().ToString(), player->GetName(), GetMapName(), save->GetMapId(), static_cast<uint32>(save->GetDifficultyID()), save->GetInstanceId());
4159 }
4160 }
4161 else
4162 {
4163 player->BindToInstance(save, true);
4165 data << uint32(0);
4166 player->SendDirectMessage(&data);
4168
4169 // if group leader is in instance, group also gets bound
4170 if (Group* group = player->GetGroup())
4171 if (group->GetLeaderGUID() == player->GetGUID())
4172 group->BindToInstance(save, true);
4173 }
4174 }
4175}
4176
4178{
4179 ASSERT(!HavePlayers());
4180
4181 if (m_resetAfterUnload == true)
4182 {
4185 }
4186
4188}
4189
4191{
4193 itr->GetSource()->SendInstanceResetWarning(GetId(), GetDifficultyID(), timeLeft, false);
4194}
4195
4197{
4198 // only for normal instances
4199 // the reset time is only scheduled when there are no payers inside
4200 // it is assumed that the reset time will rarely (if ever) change while the reset is scheduled
4202 {
4203 if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(GetInstanceId()))
4204 sInstanceSaveMgr->ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId()));
4205 else
4206 TC_LOG_ERROR("maps", "InstanceMap::SetResetSchedule: cannot turn schedule {}, there is no save information for instance (map [id: {}, name: {}], instance id: {}, difficulty: {})",
4207 on ? "on" : "off", GetId(), GetMapName(), GetInstanceId(), static_cast<uint32>(GetSpawnMode()));
4208 }
4209}
4210
4215
4217{
4218 return i_mapEntry->ID;
4219}
4220
4222{
4223 return i_mapEntry && i_mapEntry->Instanceable();
4224}
4225
4227{
4228 return i_mapEntry && i_mapEntry->IsWorldMap();
4229}
4230
4231bool Map::IsDungeon() const
4232{
4233 return i_mapEntry && i_mapEntry->IsDungeon();
4234}
4235
4237{
4239}
4240
4241bool Map::IsRaid() const
4242{
4243 return i_mapEntry && i_mapEntry->IsRaid();
4244}
4245
4247{
4248 return IsRaid() || IsHeroic();
4249}
4250
4255
4257{
4258 // since 25man difficulties are 1 and 3, we can check them like that
4260}
4261
4263{
4265}
4266
4268{
4269 return i_mapEntry && i_mapEntry->IsBattleArena();
4270}
4271
4273{
4275}
4276
4277bool Map::GetEntrancePos(int32& mapid, float& x, float& y) const
4278{
4279 if (!i_mapEntry)
4280 return false;
4281 return i_mapEntry->GetEntrancePos(mapid, x, y);
4282}
4283
4285{
4287 stmt->setUInt16(0,GetInstanceId());
4288 return !!CharacterDatabase.Query(stmt);
4289}
4290
4292{
4293 MapDifficultyEntry const* mapDiff = GetMapDifficulty();
4294 if (mapDiff && mapDiff->MaxPlayers)
4295 return mapDiff->MaxPlayers;
4296
4297 return GetEntry()->MaxPlayers;
4298}
4299
4301{
4302 MapDifficultyEntry const* mapDiff = GetMapDifficulty();
4303 return mapDiff ? mapDiff->RaidDuration : 0;
4304}
4305
4306/* ******* Battleground Instance Maps ******* */
4307
4308BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode)
4309 : Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr)
4310{
4311 //lets initialize visibility distance for BG/Arenas
4313}
4314
4316{
4317 if (m_bg)
4318 {
4319 //unlink to prevent crash, always unlink all pointer reference before destruction
4320 m_bg->SetBgMap(nullptr);
4321 m_bg = nullptr;
4322 }
4323}
4324
4331
4333{
4334 if (player->GetMapRef().getTarget() == this)
4335 {
4336 TC_LOG_ERROR("maps", "BGMap::CannotEnter - player {} is already in map!", player->GetGUID().ToString());
4337 ABORT();
4339 }
4340
4341 if (player->GetBattlegroundId() != GetInstanceId())
4343
4344 // player number limit is checked in bgmgr, no need to do it here
4345
4346 return Map::CannotEnter(player);
4347}
4348
4350{
4351 {
4352 std::lock_guard<std::mutex> lock(_mapLock);
4353 //Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
4354 //if (!CanEnter(player))
4355 //return false;
4356 // reset instance validity, battleground maps do not homebind
4357 player->m_InstanceValid = true;
4358 }
4359 return Map::AddPlayerToMap(player);
4360}
4361
4363{
4364 TC_LOG_DEBUG("maps", "MAP: Removing player '{}' from bg '{}' of map '{}' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName());
4365 Map::RemovePlayerFromMap(player, remove);
4366}
4367
4372
4374{
4375 if (HavePlayers())
4376 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
4377 if (Player* player = itr->GetSource())
4378 if (!player->IsBeingTeleportedFar())
4379 player->TeleportTo(player->GetBattlegroundEntryPoint());
4380}
4381
4383{
4384 return ObjectAccessor::GetPlayer(this, guid);
4385}
4386
4388{
4389 return _objectsStore.Find<Corpse>(guid);
4390}
4391
4393{
4394 return _objectsStore.Find<Creature>(guid);
4395}
4396
4398{
4399 auto const bounds = GetCreatureBySpawnIdStore().equal_range(spawnId);
4400 if (bounds.first == bounds.second)
4401 return nullptr;
4402
4403 std::unordered_multimap<uint32, Creature*>::const_iterator creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
4404 {
4405 return pair.second->IsAlive();
4406 });
4407
4408 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
4409}
4410
4412{
4413 auto const bounds = GetGameObjectBySpawnIdStore().equal_range(spawnId);
4414 if (bounds.first == bounds.second)
4415 return nullptr;
4416
4417 std::unordered_multimap<uint32, GameObject*>::const_iterator creatureItr = std::find_if(bounds.first, bounds.second, [](Map::GameObjectBySpawnIdContainer::value_type const& pair)
4418 {
4419 return pair.second->isSpawned();
4420 });
4421
4422 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
4423}
4424
4426{
4427 return _objectsStore.Find<GameObject>(guid);
4428}
4429
4431{
4432 return _objectsStore.Find<Pet>(guid);
4433}
4434
4436{
4437 if (!guid.IsMOTransport())
4438 return nullptr;
4439
4440 GameObject* go = GetGameObject(guid);
4441 return go ? go->ToTransport() : nullptr;
4442}
4443
4448
4450{
4451 if (&*m_mapRefIter == &player->GetMapRef())
4453}
4454
4455void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans, bool startup)
4456{
4457 SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId);
4458 if (!data)
4459 {
4460 TC_LOG_ERROR("maps", "Map {} attempt to save respawn time for nonexistant spawnid ({},{}).", GetId(), type, spawnId);
4461 return;
4462 }
4463
4464 if (!respawnTime)
4465 {
4466 // Delete only
4467 RemoveRespawnTime(data->type, data->spawnId, dbTrans);
4468 return;
4469 }
4470
4471 RespawnInfo ri;
4472 ri.type = data->type;
4473 ri.spawnId = data->spawnId;
4474 ri.entry = entry;
4475 ri.respawnTime = respawnTime;
4476 ri.gridId = gridId;
4477 bool success = AddRespawnInfo(ri);
4478
4479 if (startup)
4480 {
4481 if (!success)
4482 TC_LOG_ERROR("maps", "Attempt to load saved respawn {} for ({},{}) failed - duplicate respawn? Skipped.", respawnTime, uint32(type), spawnId);
4483 }
4484 else if (success)
4485 SaveRespawnInfoDB(ri, dbTrans);
4486}
4487
4489{
4491 stmt->setUInt16(0, info.type);
4492 stmt->setUInt32(1, info.spawnId);
4493 stmt->setUInt64(2, uint64(info.respawnTime));
4494 stmt->setUInt16(3, GetId());
4495 stmt->setUInt32(4, GetInstanceId());
4496 CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
4497}
4498
4500{
4502 stmt->setUInt16(0, GetId());
4503 stmt->setUInt32(1, GetInstanceId());
4504 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
4505 {
4506 do
4507 {
4508 Field* fields = result->Fetch();
4509 SpawnObjectType type = SpawnObjectType(fields[0].GetUInt16());
4510 ObjectGuid::LowType spawnId = fields[1].GetUInt32();
4511 uint64 respawnTime = fields[2].GetUInt64();
4512
4513 if (SpawnData::TypeHasData(type))
4514 {
4515 if (SpawnData const* data = sObjectMgr->GetSpawnData(type, spawnId))
4516 SaveRespawnTime(type, spawnId, data->id, time_t(respawnTime), Trinity::ComputeGridCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId(), nullptr, true);
4517 else
4518 TC_LOG_ERROR("maps", "Loading saved respawn time of {} for spawnid ({},{}) - spawn does not exist, ignoring", respawnTime, uint32(type), spawnId);
4519 }
4520 else
4521 {
4522 TC_LOG_ERROR("maps", "Loading saved respawn time of {} for spawnid ({},{}) - invalid spawn type, ignoring", respawnTime, uint32(type), spawnId);
4523 }
4524
4525 } while (result->NextRow());
4526 }
4527}
4528
4529/*static*/ void Map::DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
4530{
4532 stmt->setUInt16(0, mapId);
4533 stmt->setUInt32(1, instanceId);
4534 CharacterDatabase.Execute(stmt);
4535}
4536
4538{
4539 ObjectGuid linkedGuid = sObjectMgr->GetLinkedRespawnGuid(guid);
4540 switch (linkedGuid.GetHigh())
4541 {
4542 case HighGuid::Unit:
4543 return GetCreatureRespawnTime(linkedGuid.GetCounter());
4545 return GetGORespawnTime(linkedGuid.GetCounter());
4546 default:
4547 break;
4548 }
4549
4550 return time_t(0);
4551}
4552
4554{
4556 stmt->setUInt32(0, GetId());
4557 stmt->setUInt32(1, GetInstanceId());
4558
4559 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
4560 // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask, guid FROM corpse WHERE mapId = ? AND instanceId = ?
4561 PreparedQueryResult result = CharacterDatabase.Query(stmt);
4562 if (!result)
4563 return;
4564
4565 do
4566 {
4567 Field* fields = result->Fetch();
4568 CorpseType type = CorpseType(fields[13].GetUInt8());
4569 ObjectGuid::LowType guid = fields[16].GetUInt32();
4570 if (type >= MAX_CORPSE_TYPE || type == CORPSE_BONES)
4571 {
4572 TC_LOG_ERROR("misc", "Corpse (guid: {}) have wrong corpse type ({}), not loading.", guid, type);
4573 continue;
4574 }
4575
4576 Corpse* corpse = new Corpse(type);
4577
4578 if (!corpse->LoadCorpseFromDB(GenerateLowGuid<HighGuid::Corpse>(), fields))
4579 {
4580 delete corpse;
4581 continue;
4582 }
4583
4584 AddCorpse(corpse);
4585
4586 } while (result->NextRow());
4587}
4588
4590{
4591 // DELETE FROM corpse WHERE mapId = ? AND instanceId = ?
4593 stmt->setUInt32(0, GetId());
4594 stmt->setUInt32(1, GetInstanceId());
4595 CharacterDatabase.Execute(stmt);
4596}
4597
4599{
4600 corpse->SetMap(this);
4601
4602 _corpsesByCell[corpse->GetCellCoord().GetId()].insert(corpse);
4603 if (corpse->GetType() != CORPSE_BONES)
4604 _corpsesByPlayer[corpse->GetOwnerGUID()] = corpse;
4605 else
4606 _corpseBones.insert(corpse);
4607}
4608
4610{
4611 ASSERT(corpse);
4612
4613 corpse->DestroyForNearbyPlayers();
4614 if (corpse->IsInGrid())
4615 RemoveFromMap(corpse, false);
4616 else
4617 {
4618 corpse->RemoveFromWorld();
4619 corpse->ResetMap();
4620 }
4621
4622 _corpsesByCell[corpse->GetCellCoord().GetId()].erase(corpse);
4623 if (corpse->GetType() != CORPSE_BONES)
4624 _corpsesByPlayer.erase(corpse->GetOwnerGUID());
4625 else
4626 _corpseBones.erase(corpse);
4627}
4628
4629Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= false*/)
4630{
4631 Corpse* corpse = GetCorpseByPlayer(ownerGuid);
4632 if (!corpse)
4633 return nullptr;
4634
4635 RemoveCorpse(corpse);
4636
4637 // remove corpse from DB
4638 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
4639 corpse->DeleteFromDB(trans);
4640 CharacterDatabase.CommitTransaction(trans);
4641
4642 Corpse* bones = nullptr;
4643
4644 // create the bones only if the map and the grid is loaded at the corpse's location
4645 // ignore bones creating option in case insignia
4646 if ((insignia ||
4648 !IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
4649 {
4650 // Create bones, don't change Corpse
4651 bones = new Corpse();
4652 bones->Create(corpse->GetGUID().GetCounter());
4653
4655 bones->SetOwnerGUID(corpse->GetOwnerGUID());
4656 bones->SetPartyGUID(corpse->GetPartyGUID());
4657 bones->SetDisplayId(corpse->GetDisplayId());
4658 bones->SetRace(corpse->GetRace());
4659 bones->SetSex(corpse->GetSex());
4660 bones->SetSkinId(corpse->GetSkinId());
4661 bones->SetFaceId(corpse->GetFaceId());
4662 bones->SetHairStyleId(corpse->GetHairStyleId());
4663 bones->SetHairColorId(corpse->GetHairColorId());
4664 bones->SetFacialStyle(corpse->GetFacialStyle());
4666
4667 bones->SetCellCoord(corpse->GetCellCoord());
4668 bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
4669
4670 bones->SetPhaseMask(corpse->GetPhaseMask(), false);
4671
4672 AddCorpse(bones);
4673
4674 // add bones in grid store if grid loaded where corpse placed
4675 AddToMap(bones);
4676 }
4677
4678 // all references to the corpse should be removed at this point
4679 delete corpse;
4680
4681 return bones;
4682}
4683
4685{
4686 time_t now = GameTime::GetGameTime();
4687
4688 std::vector<ObjectGuid> corpses;
4689 corpses.reserve(_corpsesByPlayer.size());
4690
4691 for (auto const& p : _corpsesByPlayer)
4692 if (p.second->IsExpired(now))
4693 corpses.push_back(p.first);
4694
4695 for (ObjectGuid const& ownerGuid : corpses)
4696 ConvertCorpseToBones(ownerGuid);
4697
4698 std::vector<Corpse*> expiredBones;
4699 for (Corpse* bones : _corpseBones)
4700 if (bones->IsExpired(now))
4701 expiredBones.push_back(bones);
4702
4703 for (Corpse* bones : expiredBones)
4704 {
4705 RemoveCorpse(bones);
4706 delete bones;
4707 }
4708}
4709
4710void Map::SendZoneDynamicInfo(uint32 zoneId, Player* player) const
4711{
4712 auto itr = _zoneDynamicInfo.find(zoneId);
4713 if (itr == _zoneDynamicInfo.end())
4714 return;
4715
4716 if (uint32 music = itr->second.MusicId)
4717 player->SendDirectMessage(WorldPackets::Misc::PlayMusic(music).Write());
4718
4719 SendZoneWeather(itr->second, player);
4720
4721 for (ZoneDynamicInfo::LightOverride const& lightOverride : itr->second.LightOverrides)
4722 {
4724 overrideLight.AreaLightID = lightOverride.AreaLightId;
4725 overrideLight.OverrideLightID = lightOverride.OverrideLightId;
4726 overrideLight.TransitionMilliseconds = lightOverride.TransitionMilliseconds;
4727 player->SendDirectMessage(overrideLight.Write());
4728 }
4729}
4730
4731void Map::SendZoneWeather(uint32 zoneId, Player* player) const
4732{
4733 auto itr = _zoneDynamicInfo.find(zoneId);
4734 if (itr == _zoneDynamicInfo.end())
4735 return;
4736
4737 SendZoneWeather(itr->second, player);
4738}
4739
4740void Map::SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const
4741{
4742 if (WeatherState weatherId = zoneDynamicInfo.WeatherId)
4743 {
4744 WorldPackets::Misc::Weather weather(weatherId, zoneDynamicInfo.Intensity);
4745 player->SendDirectMessage(weather.Write());
4746 }
4747 else if (zoneDynamicInfo.DefaultWeather)
4748 {
4749 zoneDynamicInfo.DefaultWeather->SendWeatherUpdateToPlayer(player);
4750 }
4751 else
4753}
4754
4756void Map::SendZoneText(uint32 zoneId, char const* text, WorldSession const* self, uint32 team) const
4757{
4759 packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text);
4760 SendZoneMessage(zoneId, packet.Write(), self, team);
4761}
4762
4763void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
4764{
4765 _zoneDynamicInfo[zoneId].MusicId = musicId;
4766
4767 WorldPackets::Misc::PlayMusic playMusic(musicId);
4768 SendZoneMessage(zoneId, WorldPackets::Misc::PlayMusic(musicId).Write());
4769}
4770
4772{
4773 WeatherData const* weatherData = WeatherMgr::GetWeatherData(zoneId);
4774 if (!weatherData)
4775 return nullptr;
4776
4777 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4778 if (!info.DefaultWeather)
4779 {
4780 info.DefaultWeather = std::make_unique<Weather>(this, zoneId, weatherData);
4781 info.DefaultWeather->ReGenerate();
4782 info.DefaultWeather->UpdateWeather();
4783 }
4784
4785 return info.DefaultWeather.get();
4786}
4787
4788void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float intensity)
4789{
4790 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4791 info.WeatherId = weatherId;
4792 info.Intensity = intensity;
4793
4794 SendZoneMessage(zoneId, WorldPackets::Misc::Weather(weatherId, intensity).Write());
4795}
4796
4797void Map::SetZoneOverrideLight(uint32 zoneId, uint32 areaLightId, uint32 overrideLightId, Milliseconds transitionTime)
4798{
4799 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4800 // client can support only one override for each light (zone independent)
4801 info.LightOverrides.erase(std::remove_if(info.LightOverrides.begin(), info.LightOverrides.end(), [areaLightId](ZoneDynamicInfo::LightOverride const& lightOverride)
4802 {
4803 return lightOverride.AreaLightId == areaLightId;
4804 }), info.LightOverrides.end());
4805
4806 // set new override (if any)
4807 if (overrideLightId)
4808 {
4809 ZoneDynamicInfo::LightOverride& lightOverride = info.LightOverrides.emplace_back();
4810 lightOverride.AreaLightId = areaLightId;
4811 lightOverride.OverrideLightId = overrideLightId;
4812 lightOverride.TransitionMilliseconds = static_cast<uint32>(transitionTime.count());
4813 }
4814
4816 overrideLight.AreaLightID = areaLightId;
4817 overrideLight.OverrideLightID = overrideLightId;
4818 overrideLight.TransitionMilliseconds = static_cast<uint32>(transitionTime.count());
4819 SendZoneMessage(zoneId, overrideLight.Write());
4820}
4821
4823{
4824 Map::PlayerList const& players = GetPlayers();
4825 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
4826 {
4827 if (Player* player = itr->GetSource())
4828 {
4829 if (player->IsInWorld())
4830 {
4831 player->UpdateAreaDependentAuras(player->GetAreaId());
4832 player->UpdateZoneDependentAuras(player->GetZoneId());
4833 }
4834 }
4835 }
4836}
4837
4838std::string Map::GetDebugInfo() const
4839{
4840 std::stringstream sstr;
4841 sstr << std::boolalpha
4842 << "Id: " << GetId() << " InstanceId: " << GetInstanceId() << " Difficulty: " << std::to_string(GetDifficultyID())
4843 << " HasPlayers: " << HavePlayers();
4844 return sstr.str();
4845}
4846
4847std::string InstanceMap::GetDebugInfo() const
4848{
4849 std::stringstream sstr;
4850 sstr << Map::GetDebugInfo() << "\n"
4851 << std::boolalpha
4852 << "ScriptId: " << GetScriptId() << " ScriptName: " << GetScriptName();
4853 return sstr.str();
4854}
4855
@ CHAR_DEL_ALL_RESPAWNS
@ CHAR_REP_RESPAWN
@ CHAR_SEL_INSTANCE
@ CHAR_SEL_PERM_BIND_BY_INSTANCE
@ 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
CorpseType
Definition Corpse.h:28
@ CORPSE_BONES
Definition Corpse.h:29
@ CORPSE_FLAG_BONES
Definition Corpse.h:41
#define MAX_CORPSE_TYPE
Definition Corpse.h:33
Difficulty
Definition DBCEnums.h:279
@ RAID_DIFFICULTY_25MAN_HEROIC
Definition DBCEnums.h:289
@ RAID_DIFFICULTY_25MAN_NORMAL
Definition DBCEnums.h:287
@ DUNGEON_DIFFICULTY_HEROIC
Definition DBCEnums.h:283
@ RAID_DIFFICULTY_10MAN_HEROIC
Definition DBCEnums.h:288
@ AREA_FLAG_OUTSIDE
Definition DBCEnums.h:273
@ AREA_FLAG_INSIDE
Definition DBCEnums.h:272
MapDifficultyEntry const * GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
DBCStorage< AreaTableEntry > sAreaTableStore(AreaTableEntryfmt)
DBCStorage< LiquidTypeEntry > sLiquidTypeStore(LiquidTypefmt)
WMOAreaTableEntry const * GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
#define TC_GAME_API
Definition Define.h:114
uint8_t uint8
Definition Define.h:135
int16_t int16
Definition Define.h:130
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
uint16 flags
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#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:34
#define MAP_RESOLUTION
Definition GridDefines.h:53
#define TOTAL_NUMBER_OF_CELLS_PER_MAP
Definition GridDefines.h:51
#define SIZE_OF_GRIDS
Definition GridDefines.h:38
CoordPair< MAX_NUMBER_OF_GRIDS > GridCoord
#define MAX_NUMBER_OF_GRIDS
Definition GridDefines.h:36
#define CENTER_GRID_CELL_ID
Definition GridDefines.h:48
#define SIZE_OF_GRID_CELL
Definition GridDefines.h:46
#define CENTER_GRID_ID
Definition GridDefines.h:39
#define CENTER_GRID_OFFSET
Definition GridDefines.h:41
#define MAP_HALFSIZE
Definition GridDefines.h:56
NGrid< MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes > NGridType
Definition GridDefines.h:86
#define VMAP_INVALID_HEIGHT_VALUE
#define VMAP_INVALID_HEIGHT
#define sInstanceSaveMgr
@ 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:74
@ LIQUID_MAP_UNDER_WATER
Definition MapDefines.h:79
@ LIQUID_MAP_NO_WATER
Definition MapDefines.h:75
@ LIQUID_MAP_IN_WATER
Definition MapDefines.h:78
@ LIQUID_MAP_ABOVE_WATER
Definition MapDefines.h:76
@ LIQUID_MAP_WATER_WALK
Definition MapDefines.h:77
#define sMapMgr
Definition MapManager.h:211
@ 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 uint16 const holetab_h[4]
Definition Map.cpp:62
uint32 MapVersionMagic
Definition Map.cpp:57
static uint16 const holetab_v[4]
Definition Map.cpp:63
u_map_magic MapMagic
Definition Map.cpp:56
u_map_magic MapLiquidMagic
Definition Map.cpp:60
static bool IsInWMOInterior(uint32 mogpFlags)
Definition Map.cpp:2538
static void PushRespawnInfoFrom(std::vector< RespawnInfo const * > &data, RespawnInfoMap const &map)
Definition Map.cpp:3170
GridState * si_GridStates[MAX_GRID_STATE]
Definition Map.cpp:69
u_map_magic MapHeightMagic
Definition Map.cpp:59
u_map_magic MapAreaMagic
Definition Map.cpp:58
#define MIN_UNLOAD_DELAY
Definition Map.h:265
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS
Definition Map.h:139
#define MAP_HEIGHT_AS_INT8
Definition Map.h:138
#define MAP_AREA_NO_AREA
Definition Map.h:127
std::unordered_map< ObjectGuid::LowType, RespawnInfo * > RespawnInfoMap
Definition Map.h:275
#define MAP_LIQUID_NO_TYPE
Definition Map.h:149
#define MAP_LIQUID_NO_HEIGHT
Definition Map.h:150
#define MAP_LIQUID_TYPE_WATER
Definition Map.h:166
#define MAP_LIQUID_TYPE_DARK_WATER
Definition Map.h:173
#define MAP_LIQUID_TYPE_OCEAN
Definition Map.h:167
@ INSTANCE_RESET_CHANGE_DIFFICULTY
Definition Map.h:888
@ INSTANCE_RESET_GLOBAL
Definition Map.h:889
@ INSTANCE_RESET_ALL
Definition Map.h:887
#define MAP_HEIGHT_NO_HEIGHT
Definition Map.h:136
#define MAP_INVALID_ZONE
Definition Map.h:266
#define INVALID_HEIGHT
Definition Map.h:262
#define MAP_HEIGHT_AS_INT16
Definition Map.h:137
#define TC_METRIC_VALUE(category, value,...)
Definition Metric.h:203
#define TC_METRIC_TAG(name, value)
Definition Metric.h:169
@ GRID_STATE_REMOVAL
Definition NGrid.h:61
@ GRID_STATE_INVALID
Definition NGrid.h:58
@ GRID_STATE_IDLE
Definition NGrid.h:60
@ GRID_STATE_ACTIVE
Definition NGrid.h:59
@ MAX_GRID_STATE
Definition NGrid.h:62
#define DEFAULT_VISIBILITY_NOTIFY_PERIOD
Definition NGrid.h:29
#define MAX_VISIBILITY_DISTANCE
#define DEFAULT_VISIBILITY_DISTANCE
@ TYPEID_DYNAMICOBJECT
Definition ObjectGuid.h:41
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:40
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_CORPSE
Definition ObjectGuid.h:42
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
HighGuid
Definition ObjectGuid.h:63
#define sObjectMgr
Definition ObjectMgr.h:1721
std::unordered_map< Player *, UpdateData > UpdateDataMapType
Definition Object.h:63
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ PET_SAVE_NOT_IN_SLOT
Definition PetDefines.h:45
#define sPoolMgr
Definition PoolMgr.h:148
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
#define sScriptMgr
Definition ScriptMgr.h:1168
@ LANG_UNIVERSAL
TeamId
float const GROUND_HEIGHT_TOLERANCE
@ CHAT_MSG_SYSTEM
LineOfSightChecks
@ LINEOFSIGHT_CHECK_VMAP
@ LINEOFSIGHT_CHECK_GOBJECT
constexpr float Z_OFFSET_FIND_HEIGHT
@ SPAWNGROUP_FLAG_DYNAMIC_SPAWN_RATE
Definition SpawnData.h:52
@ SPAWNGROUP_FLAG_MANUAL_SPAWN
Definition SpawnData.h:51
@ SPAWNGROUP_FLAG_SYSTEM
Definition SpawnData.h:49
@ SPAWNGROUP_FLAG_ESCORTQUESTNPC
Definition SpawnData.h:53
SpawnObjectTypeMask
Definition SpawnData.h:38
@ SPAWN_TYPEMASK_CREATURE
Definition SpawnData.h:39
@ SPAWN_TYPEMASK_GAMEOBJECT
Definition SpawnData.h:40
SpawnObjectType
Definition SpawnData.h:30
@ SPAWN_TYPE_GAMEOBJECT
Definition SpawnData.h:32
@ SPAWN_TYPE_CREATURE
Definition SpawnData.h:31
bool AddPlayerToMap(Player *) override
Definition Map.cpp:4349
BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map *_parent, uint8 spawnMode)
Definition Map.cpp:4308
void SetUnload()
Definition Map.cpp:4368
void RemoveAllPlayers() override
Definition Map.cpp:4373
EnterState CannotEnter(Player *player) override
Definition Map.cpp:4332
Battleground * m_bg
Definition Map.h:951
void RemovePlayerFromMap(Player *, bool) override
Definition Map.cpp:4362
virtual void InitVisibilityDistance() override
Definition Map.cpp:4325
void SetBgMap(BattlegroundMap *map)
void clear()
Definition ByteBuffer.h:126
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
void SetHairStyleId(uint8 hairStyle)
Definition Corpse.h:102
uint32 GetDisplayId() const
Definition Corpse.h:87
uint8 GetHairColorId() const
Definition Corpse.h:103
void SetRace(uint8 race)
Definition Corpse.h:90
ObjectGuid GetPartyGUID() const
Definition Corpse.h:83
uint8 GetRace() const
Definition Corpse.h:89
bool Create(ObjectGuid::LowType guidlow)
Definition Corpse.cpp:64
void SetSex(uint8 sex)
Definition Corpse.h:92
uint8 GetSkinId() const
Definition Corpse.h:97
void ReplaceAllCorpseDynamicFlags(CorpseDynFlags flag)
Definition Corpse.h:79
void SetDisplayId(uint32 displayId)
Definition Corpse.h:88
CorpseDynFlags GetCorpseDynamicFlags() const
Definition Corpse.h:75
void ReplaceAllCorpseFlags(CorpseFlags flags)
Definition Corpse.h:73
void RemoveFromWorld() override
Definition Corpse.cpp:55
void SetOwnerGUID(ObjectGuid owner)
Definition Corpse.h:82
void SetPartyGUID(ObjectGuid partyGuid)
Definition Corpse.h:84
void SetFacialStyle(uint8 facialStyle)
Definition Corpse.h:106
uint8 GetHairStyleId() const
Definition Corpse.h:101
CellCoord const & GetCellCoord() const
Definition Corpse.h:112
CorpseFlags GetCorpseFlags() const
Definition Corpse.h:69
ObjectGuid GetOwnerGUID() const override
Definition Corpse.h:81
void SetFaceId(uint8 face)
Definition Corpse.h:100
bool LoadCorpseFromDB(ObjectGuid::LowType guid, Field *fields)
Definition Corpse.cpp:154
void SetCellCoord(CellCoord const &cellCoord)
Definition Corpse.h:113
uint8 GetSex() const
Definition Corpse.h:91
uint8 GetFacialStyle() const
Definition Corpse.h:105
CorpseType GetType() const
Definition Corpse.h:110
void SetHairColorId(uint8 hairColor)
Definition Corpse.h:104
uint8 GetFaceId() const
Definition Corpse.h:99
void DeleteFromDB(CharacterDatabaseTransaction trans)
Definition Corpse.cpp:128
void SetSkinId(uint8 skin)
Definition Corpse.h:98
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr, float *dist=nullptr) const
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
bool IsEscorted() const
bool m_isTempWorldObject
Definition Creature.h:346
bool getAreaAndLiquidData(float x, float y, float z, uint32 phasemask, Optional< uint8 > reqLiquidType, VMAP::AreaAndLiquidData &data) const
bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const
void update(uint32 diff)
bool getObjectHitPos(uint32 phasemask, const G3D::Vector3 &pPos1, const G3D::Vector3 &pPos2, G3D::Vector3 &pResultHitPos, float pModifyDist) const
Class used to access individual fields of database query result.
Definition Field.h:92
std::string GetString() const
Definition Field.cpp:125
uint64 GetUInt64() const
Definition Field.cpp:77
uint32 GetUInt32() const
Definition Field.cpp:61
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr) const
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool=true)
void RemoveFromWorld() override
ObjectGuid::LowType GetSpawnId() const
Definition GameObject.h:112
void UpdateModelPosition()
Transport * ToTransport()
Definition GameObject.h:291
void AddToWorld() override
PeriodicTimer & getRelocationTimer()
Definition NGrid.h:46
Definition Map.h:176
bool loadAreaData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:1894
float getHeightFromFlat(float x, float y) const
Definition Map.cpp:2060
void unloadData()
Definition Map.cpp:1873
float getMinHeight(float x, float y) const
Definition Map.cpp:2305
bool isHole(int row, int col) const
Definition Map.cpp:2290
uint8 * m_uint8_V8
Definition Map.h:186
GridMap()
Definition Map.cpp:1784
float _liquidLevel
Definition Map.h:197
uint16 * m_uint16_V8
Definition Map.h:185
~GridMap()
Definition Map.cpp:1811
uint16 getArea(float x, float y) const
Definition Map.cpp:2048
uint16 * _liquidEntry
Definition Map.h:198
float getHeightFromFloat(float x, float y) const
Definition Map.cpp:2065
uint8 _liquidGlobalFlags
Definition Map.h:203
float getHeightFromUint16(float x, float y) const
Definition Map.cpp:2220
bool loadData(char const *filename)
Definition Map.cpp:1816
ZLiquidStatus GetLiquidStatus(float x, float y, float z, Optional< uint8 > ReqLiquidType, LiquidData *data=0, float collisionHeight=2.03128f)
Definition Map.cpp:2355
uint8 _liquidOffY
Definition Map.h:205
uint16 _liquidGlobalEntry
Definition Map.h:202
uint8 _liquidOffX
Definition Map.h:204
uint8 * m_uint8_V9
Definition Map.h:181
float * _liquidMap
Definition Map.h:200
uint32 _flags
Definition Map.h:177
bool loadHolesData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:2036
uint8 _liquidHeight
Definition Map.h:207
uint16 * _areaMap
Definition Map.h:194
float _gridIntHeightMultiplier
Definition Map.h:191
uint8 _liquidWidth
Definition Map.h:206
uint8 * _liquidFlags
Definition Map.h:199
float getLiquidLevel(float x, float y) const
Definition Map.cpp:2335
float * m_V9
Definition Map.h:179
G3D::Plane * _minHeightPlanes
Definition Map.h:188
uint16 _gridArea
Definition Map.h:201
uint16 * m_uint16_V9
Definition Map.h:180
float getHeightFromUint8(float x, float y) const
Definition Map.cpp:2150
float getHeight(float x, float y) const
Definition Map.h:232
bool loadHeightData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:1912
float _gridHeight
Definition Map.h:190
GetHeightPtr _gridGetHeight
Definition Map.h:219
bool loadLiquidData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:2001
uint16 * _holes
Definition Map.h:209
float * m_V8
Definition Map.h:184
void RemoveFromGrid()
Definition GridObject.h:15
bool IsInGrid() const
Definition GridObject.h:13
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:165
bool isLFGGroup() const
Definition Group.cpp:2397
InstanceGroupBind * BindToInstance(InstanceSave *save, bool permanent, bool load=false)
Definition Group.cpp:2275
ObjectGuid GetLeaderGUID() const
Definition Group.cpp:2422
InstanceGroupBind * GetBoundInstance(Player *player)
Definition Group.cpp:2242
bool AddPlayerToMap(Player *) override
Definition Map.cpp:3888
bool m_resetAfterUnload
Definition Map.h:927
void Update(uint32) override
Definition Map.cpp:4005
void CreateInstanceData(bool load)
Definition Map.cpp:4031
bool m_unloadWhenEmpty
Definition Map.h:928
bool Reset(uint8 method)
Definition Map.cpp:4073
InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map *_parent, TeamId InstanceTeam)
Definition Map.cpp:3822
void SendResetWarnings(uint32 timeLeft) const
Definition Map.cpp:4190
uint32 GetMaxPlayers() const
Definition Map.cpp:4291
virtual void InitVisibilityDistance() override
Definition Map.cpp:3841
uint32 GetScriptId() const
Definition Map.h:905
void RemovePlayerFromMap(Player *, bool) override
Definition Map.cpp:4013
void PermBindAllPlayers()
Definition Map.cpp:4129
uint32 GetMaxResetDelay() const
Definition Map.cpp:4300
bool HasPermBoundPlayers() const
Definition Map.cpp:4284
EnterState CannotEnter(Player *player) override
Definition Map.cpp:3851
InstanceScript * i_data
Definition Map.h:929
void UnloadAll() override
Definition Map.cpp:4177
std::string const & GetScriptName() const
Definition Map.cpp:4124
void SetResetSchedule(bool on)
Definition Map.cpp:4196
std::string GetDebugInfo() const override
Definition Map.cpp:4847
uint32 i_script_id
Definition Map.h:930
InstanceScript * GetInstanceScript()
Definition Map.h:907
~InstanceMap()
Definition Map.cpp:3835
uint8 GetPlayerCount() const
uint8 GetGroupCount() const
Difficulty GetDifficultyID() const
uint32 GetInstanceId() const
uint32 GetMapId() const
bool CanReset() const
uint32 GetCompletedEncounterMask() const
virtual void Load(char const *data)
virtual void OnPlayerLeave(Player *)
virtual void Create()
virtual void OnPlayerEnter(Player *)
virtual void Update(uint32)
void SetCompletedEncountersMask(uint32 newMask)
bool isEmpty() const
Definition LinkedList.h:108
uint32 getSize() const
Definition LinkedList.h:126
static MMapManager * createOrGetMMapManager()
bool unloadMap(uint32 mapId, int32 x, int32 y)
bool loadMapInstance(std::string const &basePath, uint32 mapId, uint32 instanceId)
bool loadMap(std::string const &basePath, uint32 mapId, int32 x, int32 y)
bool unloadMapInstance(uint32 mapId, uint32 instanceId)
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()
iterator begin()
MapReference const * nocheck_prev() const
Definition Map.h:302
MapEntry const * i_mapEntry
Definition Map.h:694
uint8 i_spawnMode
Definition Map.h:695
void DynamicObjectRelocation(DynamicObject *go, float x, float y, float z, float orientation)
Definition Map.cpp:1174
bool _creatureToMoveLock
Definition Map.h:660
std::map< WorldObject *, bool > i_objectsToSwitch
Definition Map.h:743
WorldObject * GetWorldObjectBySpawnId(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition Map.h:493
std::unordered_map< uint32, uint32 > _zonePlayerCountMap
Definition Map.h:865
float GetWaterLevel(float x, float y) const
Definition Map.cpp:2862
std::vector< Creature * > _creaturesToMove
Definition Map.h:661
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition Map.cpp:3518
void GameObjectRelocation(GameObject *go, float x, float y, float z, float orientation, bool respawnRelocationOnFail=true)
Definition Map.cpp:1140
void AddGameObjectToMoveList(GameObject *go, float x, float y, float z, float ang)
Definition Map.cpp:1226
void RemoveDynamicObjectFromMoveList(DynamicObject *go)
Definition Map.cpp:1255
bool IsDungeon() const
Definition Map.cpp:4231
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition Map.cpp:1108
void SetZoneMusic(uint32 zoneId, uint32 musicId)
Definition Map.cpp:4763
bool IsBattlegroundOrArena() const
Definition Map.cpp:4272
bool UnloadGrid(NGridType &ngrid, bool pForce)
Definition Map.cpp:1649
std::unordered_map< ObjectGuid, Corpse * > _corpsesByPlayer
Definition Map.h:877
void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float intensity)
Definition Map.cpp:4788
Pet * GetPet(ObjectGuid const &guid)
Definition Map.cpp:4430
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:509
TransportsContainer::iterator _transportsUpdateIter
Definition Map.h:714
void InitializeObject(T *obj)
Definition Map.cpp:615
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
Definition Map.cpp:4529
bool IsWorldMap() const
Definition Map.cpp:4226
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition Map.cpp:3382
void SwitchGridContainers(T *obj, bool on)
Definition Map.cpp:373
void AddObjectToRemoveList(WorldObject *obj)
Definition Map.cpp:3562
void SendZoneWeather(uint32 zoneId, Player *player) const
Definition Map.cpp:4731
virtual void RemovePlayerFromMap(Player *, bool)
Definition Map.cpp:1002
void MoveAllGameObjectsInMoveList()
Definition Map.cpp:1321
Creature * GetCreatureBySpawnId(ObjectGuid::LowType spawnId) const
Definition Map.cpp:4397
void RemoveFromActiveHelper(WorldObject *obj)
Definition Map.h:817
void DeleteRespawnInfoFromDB(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:3225
size_t DespawnAll(SpawnObjectType type, ObjectGuid::LowType spawnId)
Definition Map.cpp:3114
std::function< void(Map *)> FarSpellCallback
Definition Map.h:801
void SetSpawnGroupActive(uint32 groupId, bool state)
Definition Map.cpp:3481
void LoadGrid(float x, float y)
Definition Map.cpp:578
void SendZoneDynamicInfo(uint32 zoneId, Player *player) const
Definition Map.cpp:4710
void RemoveFromActive(WorldObject *obj)
Definition Map.cpp:3771
MapDifficultyEntry const * GetMapDifficulty() const
Definition Map.cpp:4211
void SendZoneText(uint32 zoneId, const char *text, WorldSession const *self=nullptr, uint32 team=0) const
Send a System Message to all players in the zone (except self if mentioned)
Definition Map.cpp:4756
bool AddToMap(T *)
Definition Map.cpp:630
float GetHeight(float x, float y, float z, bool checkVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH) const
Definition Map.cpp:2484
bool getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float &rx, float &ry, float &rz, float modifyDist)
Definition Map.cpp:2881
void DeleteCorpseData()
Definition Map.cpp:4589
void EnsureGridCreated(GridCoord const &)
Definition Map.cpp:485
void DeleteRespawnTimes()
Definition Map.h:582
Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map *_parent=nullptr)
Definition Map.cpp:272
void RemoveUpdateObject(Object *obj)
Definition Map.h:625
RespawnInfoMap _gameObjectRespawnTimesBySpawnId
Definition Map.h:835
NGridType * i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
Definition Map.h:733
void ProcessRespawns()
Definition Map.cpp:3261
Weather * GetOrGenerateZoneDefaultWeather(uint32 zoneId)
Definition Map.cpp:4771
uint32 m_unloadTimer
Definition Map.h:698
virtual void DelayedUpdate(uint32 diff)
Definition Map.cpp:3523
Player * GetPlayer(ObjectGuid const &guid)
Definition Map.cpp:4382
uint8 GetSpawnMode() const
Definition Map.h:409
bool IsNonRaidDungeon() const
Definition Map.cpp:4236
time_t GetLinkedRespawnTime(ObjectGuid guid) const
Definition Map.cpp:4537
void AddCorpse(Corpse *corpse)
Definition Map.cpp:4598
bool IsBattleground() const
Definition Map.cpp:4262
void LoadMMap(int gx, int gy)
Definition Map.cpp:165
void UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone)
Definition Map.cpp:747
IntervalTimer _weatherUpdateTimer
Definition Map.h:868
bool CheckRespawn(RespawnInfo *info)
Definition Map.cpp:3034
Map * m_parentMap
Definition Map.h:731
bool IsRaid() const
Definition Map.cpp:4241
void ProcessRelocationNotifies(const uint32 diff)
Definition Map.cpp:925
void UnloadAllRespawnInfos()
Definition Map.cpp:3194
virtual void UnloadAll()
Definition Map.cpp:1745
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr, bool alwaysDeleteFromDB=false)
Definition Map.h:773
bool _dynamicObjectsToMoveLock
Definition Map.h:666
NGridType * getNGrid(uint32 x, uint32 y) const
Definition Map.h:677
bool Is25ManRaid() const
Definition Map.cpp:4256
void AddToActiveHelper(WorldObject *obj)
Definition Map.h:812
bool _gameObjectsToMoveLock
Definition Map.h:663
void RemoveOldCorpses()
Definition Map.cpp:4684
uint32 _respawnCheckTimer
Definition Map.h:864
Corpse * ConvertCorpseToBones(ObjectGuid const &ownerGuid, bool insignia=false)
Definition Map.cpp:4629
bool HavePlayers() const
Definition Map.h:457
bool IsRemovalGrid(float x, float y) const
Definition Map.h:344
std::unordered_map< uint32, std::unordered_set< Corpse * > > _corpsesByCell
Definition Map.h:876
MapRefManager m_mapRefManager
Definition Map.h:702
void resetMarkedCells()
Definition Map.h:453
bool ActiveObjectsNearGrid(NGridType const &ngrid) const
Definition Map.cpp:3695
void RemoveCreatureFromMoveList(Creature *c)
Definition Map.cpp:1217
void ScriptsProcess()
Process queued scripts.
void Visit(Cell const &cell, TypeContainerVisitor< T, CONTAINER > &visitor)
Definition Map.h:955
ScriptScheduleMap m_scriptSchedule
Definition Map.h:747
float GetMinHeight(float x, float y) const
Definition Map.cpp:2530
void AddWorldObject(WorldObject *obj)
Definition Map.h:461
void ResetGridExpiry(NGridType &grid, float factor=1) const
Definition Map.h:364
DynamicMapTree _dynamicTree
Definition Map.h:700
std::vector< GameObject * > _gameObjectsToMove
Definition Map.h:664
void DeleteRespawnInfo(RespawnInfo *info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:3203
uint32 GetZoneId(uint32 phaseMask, float x, float y, float z) const
Definition Map.cpp:2617
void ApplyDynamicModeRespawnScaling(WorldObject const *obj, ObjectGuid::LowType spawnId, uint32 &respawnDelay, uint32 mode) const
Definition Map.cpp:3312
void LoadRespawnTimes()
Definition Map.cpp:4499
bool GameObjectRespawnRelocation(GameObject *go, bool diffGridOnly)
Definition Map.cpp:1623
time_t i_gridExpiry
Definition Map.h:727
int32 m_VisibilityNotifyPeriod
Definition Map.h:705
std::unordered_set< Corpse * > _corpseBones
Definition Map.h:878
void EnsureGridLoadedForActiveObject(Cell const &, WorldObject *object)
Definition Map.cpp:517
void LoadMap(int gx, int gy, bool reload=false)
Definition Map.cpp:198
MPSCQueue< FarSpellCallback > _farSpellCallbacks
Definition Map.h:882
void LoadVMap(int gx, int gy)
Definition Map.cpp:178
time_t GetGORespawnTime(ObjectGuid::LowType spawnId) const
Definition Map.h:575
bool i_scriptLock
Definition Map.h:741
void SendInitSelf(Player *player)
Definition Map.cpp:2929
void DoRespawn(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 gridId)
Definition Map.cpp:3235
virtual void RemoveAllPlayers()
Definition Map.cpp:1728
RespawnInfoMap & GetRespawnMapForType(SpawnObjectType type)
Definition Map.h:836
std::unordered_set< uint32 > _toggledSpawnGroupIds
Definition Map.h:862
bool isCellMarked(uint32 pCellId)
Definition Map.h:454
SpawnGroupTemplateData const * GetSpawnGroupData(uint32 groupId) const
Definition Map.cpp:3374
bool GameObjectCellRelocation(GameObject *go, Cell new_cell)
Definition Map.cpp:1470
void SendToPlayers(WorldPacket const *data) const
Definition Map.cpp:3668
time_t GetCreatureRespawnTime(ObjectGuid::LowType spawnId) const
Definition Map.h:574
float GetGridHeight(float x, float y) const
Definition Map.cpp:2522
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:4425
bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition Map.cpp:2870
void SetZoneOverrideLight(uint32 zoneId, uint32 areaLightId, uint32 overrideLightId, Milliseconds transitionTime)
Definition Map.cpp:4797
GridMap * GetGrid(float x, float y)
Definition Map.cpp:2446
virtual std::string GetDebugInfo() const
Definition Map.cpp:4838
static void DeleteStateMachine()
Definition Map.cpp:264
void SaveRespawnInfoDB(RespawnInfo const &info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:4488
bool IsSpawnGroupActive(uint32 groupId) const
Definition Map.cpp:3495
MapRefManager::iterator m_mapRefIter
Definition Map.h:703
bool CreatureCellRelocation(Creature *creature, Cell new_cell)
Definition Map.cpp:1406
void LoadCorpseData()
Definition Map.cpp:4553
std::unique_ptr< RespawnListContainer > _respawnTimes
Definition Map.h:833
virtual EnterState CannotEnter(Player *)
Definition Map.h:429
Corpse * GetCorpse(ObjectGuid const &guid)
Definition Map.cpp:4387
time_t GetRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition Map.h:568
void Balance()
Definition Map.h:554
virtual void Update(uint32)
Definition Map.cpp:762
ZoneDynamicInfoMap _zoneDynamicInfo
Definition Map.h:867
virtual ~Map()
Definition Map.cpp:88
DynamicObject * GetDynamicObject(ObjectGuid const &guid)
Definition Map.cpp:4444
void RemoveGameObjectFromMoveList(GameObject *go)
Definition Map.cpp:1236
void GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, PositionFullTerrainStatus &data, Optional< uint8 > reqLiquidType={}, float collisionHeight=2.03128f) const
Definition Map.cpp:2723
void RemoveWorldObject(WorldObject *obj)
Definition Map.h:462
std::set< WorldObject * > i_worldObjects
Definition Map.h:744
Difficulty GetDifficultyID() const
Definition Map.h:433
ActiveNonPlayers m_activeNonPlayers
Definition Map.h:708
void SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans=nullptr, bool startup=false)
Definition Map.cpp:4455
ZLiquidStatus GetLiquidStatus(uint32 phaseMask, float x, float y, float z, Optional< uint8 > ReqLiquidType, LiquidData *data=nullptr, float collisionHeight=2.03128f) const
Definition Map.cpp:2635
void UpdateIteratorBack(Player *player)
Definition Map.cpp:4449
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition Map.h:516
bool Instanceable() const
Definition Map.cpp:4221
ObjectGuidGenerator & GetGuidSequenceGenerator(HighGuid high)
Definition Map.cpp:3509
void AddDynamicObjectToMoveList(DynamicObject *go, float x, float y, float z, float ang)
Definition Map.cpp:1245
void LoadMapAndVMap(int gx, int gy)
Definition Map.cpp:238
std::unordered_set< Object * > _updateObjects
Definition Map.h:880
void buildNGridLinkage(NGridType *pNGridType)
Definition Map.h:675
MapEntry const * GetEntry() const
Definition Map.h:308
std::set< WorldObject * > i_objectsToRemove
Definition Map.h:742
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes=false, size_t *count=nullptr)
Definition Map.cpp:3458
MapStoredObjectTypesContainer _objectsStore
Definition Map.h:873
void AddToGrid(T *object, Cell const &cell)
Definition Map.cpp:311
void MoveAllDynamicObjectsInMoveList()
Definition Map.cpp:1367
void EnsureGridCreated_i(GridCoord const &)
Definition Map.cpp:493
uint32 GetPlayersCountExceptGMs() const
Definition Map.cpp:3659
void DeleteFromWorld(T *)
Definition Map.cpp:464
void UpdateAreaDependentAuras()
Definition Map.cpp:4822
uint32 GetId() const
Definition Map.cpp:4216
void SendInitTransports(Player *player)
Definition Map.cpp:2966
float m_VisibleDistance
Definition Map.h:699
float GetVisibilityRange() const
Definition Map.h:332
bool IsRaidOrHeroicDungeon() const
Definition Map.cpp:4246
void GetZoneAndAreaId(uint32 phaseMask, uint32 &zoneid, uint32 &areaid, float x, float y, float z) const
Definition Map.cpp:2627
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f) const
Definition Map.cpp:2458
bool CheckGridIntegrity(Creature *c, bool moved) const
Definition Map.cpp:2907
char const * GetMapName() const
Definition Map.cpp:2924
Corpse * GetCorpseByPlayer(ObjectGuid const &ownerGuid) const
Definition Map.h:528
void RemoveAllObjectsInRemoveList()
Definition Map.cpp:3588
void MoveAllCreaturesInMoveList()
Definition Map.cpp:1264
bool IsGridLoaded(uint32 gridId) const
Definition Map.h:351
void markCell(uint32 pCellId)
Definition Map.h:455
void VisitNearbyCellsOf(WorldObject *obj, TypeContainerVisitor< Trinity::ObjectUpdater, GridTypeMapContainer > &gridVisitor, TypeContainerVisitor< Trinity::ObjectUpdater, WorldTypeMapContainer > &worldVisitor)
Definition Map.cpp:718
std::mutex _mapLock
Definition Map.h:691
void AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang)
Definition Map.cpp:1207
void GridUnmarkNoUnload(uint32 x, uint32 y)
Definition Map.cpp:568
CreatureBySpawnIdContainer & GetCreatureBySpawnIdStore()
Definition Map.h:512
uint32 GetAreaId(uint32 phaseMask, float x, float y, float z) const
Definition Map.cpp:2581
virtual void InitVisibilityDistance()
Definition Map.cpp:302
bool IsHeroic() const
Definition Map.cpp:4251
RespawnInfo * GetRespawnInfo(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition Map.cpp:3185
void SendObjectUpdates()
Definition Map.cpp:3008
bool EnsureGridLoaded(Cell const &)
Definition Map.cpp:533
void RemoveFromMap(T *, bool)
Definition Map.cpp:1027
virtual bool AddPlayerToMap(Player *)
Definition Map.cpp:583
std::vector< DynamicObject * > _dynamicObjectsToMove
Definition Map.h:667
uint32 GetInstanceId() const
Definition Map.h:408
bool GetEntrancePos(int32 &mapid, float &x, float &y) const
Definition Map.cpp:4277
TransportsContainer _transports
Definition Map.h:713
void SendRemoveTransports(Player *player)
Definition Map.cpp:2982
PlayerList const & GetPlayers() const
Definition Map.h:468
void AddToActive(WorldObject *obj)
Definition Map.cpp:3732
bool IsInWater(uint32 phaseMask, float x, float y, float z, LiquidData *data=nullptr) const
Definition Map.cpp:2895
static void InitStateMachine()
Definition Map.cpp:256
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition Map.cpp:1081
RespawnInfoMap _creatureRespawnTimesBySpawnId
Definition Map.h:834
bool CreatureRespawnRelocation(Creature *c, bool diffGridOnly)
Definition Map.cpp:1592
static bool ExistVMap(uint32 mapid, int gx, int gy)
Definition Map.cpp:138
CreatureBySpawnIdContainer _creatureBySpawnIdStore
Definition Map.h:874
void AddObjectToSwitchList(WorldObject *obj, bool on)
Definition Map.cpp:3571
uint32 i_InstanceId
Definition Map.h:696
bool AddRespawnInfo(RespawnInfo const &info)
Definition Map.cpp:3137
bool SendZoneMessage(uint32 zone, WorldPacket const *packet, WorldSession const *self=nullptr, uint32 team=0) const
Send a packet to all players (or players selected team) in the zone (except self if mentioned)
Definition Map.cpp:3675
bool IsUnderWater(uint32 phaseMask, float x, float y, float z) const
Definition Map.cpp:2902
EnterState
Definition Map.h:415
@ CANNOT_ENTER_MAX_PLAYERS
Definition Map.h:425
@ CANNOT_ENTER_ZONE_IN_COMBAT
Definition Map.h:426
@ CANNOT_ENTER_ALREADY_IN_MAP
Definition Map.h:417
@ CANNOT_ENTER_INSTANCE_BIND_MISMATCH
Definition Map.h:423
ActiveNonPlayers::iterator m_activeNonPlayersIter
Definition Map.h:709
void RemoveCorpse(Corpse *corpse)
Definition Map.cpp:4609
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:4392
Transport * GetTransport(ObjectGuid const &guid)
Definition Map.cpp:4435
std::map< HighGuid, std::unique_ptr< ObjectGuidGenerator > > _guidGenerators
Definition Map.h:872
bool GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const
Definition Map.cpp:2543
void LoadAllCells()
Definition Map.cpp:249
GameObject * GetGameObjectBySpawnId(ObjectGuid::LowType spawnId) const
Definition Map.cpp:4411
static bool ExistMap(uint32 mapid, int gx, int gy)
Definition Map.cpp:109
GridMap * GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
Definition Map.h:734
void GridMarkNoUnload(uint32 x, uint32 y)
Definition Map.cpp:555
bool DynamicObjectCellRelocation(DynamicObject *go, Cell new_cell)
Definition Map.cpp:1531
std::mutex _gridLock
Definition Map.h:692
GameObjectBySpawnIdContainer _gameobjectBySpawnIdStore
Definition Map.h:875
void Respawn(RespawnInfo *info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:3105
void setNGrid(NGridType *grid, uint32 x, uint32 y)
Definition Map.cpp:2998
bool IsBattleArena() const
Definition Map.cpp:4267
bool ShouldBeSpawnedOnGridLoad(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition Map.cpp:3356
Definition NGrid.h:73
bool isGridObjectDataLoaded() const
Definition NGrid.h:103
int32 getX() const
Definition NGrid.h:96
grid_state_t GetGridState(void) const
Definition NGrid.h:94
void decUnloadActiveLock()
Definition NGrid.h:112
void setGridObjectDataLoaded(bool pLoaded)
Definition NGrid.h:104
uint32 GetWorldObjectCountInNGrid() const
Definition NGrid.h:168
void SetGridState(grid_state_t s)
Definition NGrid.h:95
void setUnloadExplicitLock(bool on)
Definition NGrid.h:109
GridType & GetGridType(const uint32 x, const uint32 y)
Definition NGrid.h:81
void incUnloadActiveLock()
Definition NGrid.h:111
GridInfo * getGridInfoRef()
Definition NGrid.h:106
int32 getY() const
Definition NGrid.h:97
void VisitAllGrids(TypeContainerVisitor< T, TypeMapContainer< TT > > &visitor)
Definition NGrid.h:140
LowType GetCounter() const
Definition ObjectGuid.h:156
bool IsMOTransport() const
Definition ObjectGuid.h:186
bool IsPlayer() const
Definition ObjectGuid.h:179
std::string ToString() const
uint32 LowType
Definition ObjectGuid.h:142
HighGuid GetHigh() const
Definition ObjectGuid.h:154
static Creature * ToCreature(Object *o)
Definition Object.h:189
static GameObject * ToGameObject(Object *o)
Definition Object.h:201
bool IsInWorld() const
Definition Object.h:73
TypeID GetTypeId() const
Definition Object.h:93
virtual void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
Definition Object.cpp:162
virtual void BuildUpdate(UpdateDataMapType &)
Definition Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void BuildOutOfRangeUpdateBlock(UpdateData *data) const
Definition Object.cpp:218
static DynamicObject * ToDynObject(Object *o)
Definition Object.h:213
Definition Pet.h:40
bool HaveAtClient(Object const *u) const
Definition Player.cpp:22065
uint32 GetTeam() const
Definition Player.h:1818
bool m_InstanceValid
Definition Player.h:2132
float m_homebindZ
Definition Player.h:2077
bool IsBeingTeleportedFar() const
Definition Player.h:1808
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
uint32 m_homebindMapId
Definition Player.h:2073
void SendAurasForTarget(Unit *target, bool force=false) const
Definition Player.cpp:22885
void Update(uint32 time) override
Definition Player.cpp:920
void UpdateZone(uint32 newZone, uint32 newArea)
Definition Player.cpp:6805
GuidUnorderedSet m_clientGUIDs
Definition Player.h:2083
bool IsLoading() const override
Definition Player.cpp:16881
WorldSession * GetSession() const
Definition Player.h:1705
void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const override
Definition Player.cpp:3819
WorldObject * GetViewpoint() const
Definition Player.cpp:24160
float m_homebindY
Definition Player.h:2076
Group * GetGroup()
Definition Player.h:2159
bool IsGameMaster() const
Definition Player.h:976
void SetPendingBind(uint32 instanceId, uint32 bindTimer)
Definition Player.cpp:18704
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:1539
MapReference & GetMapRef()
Definition Player.h:2182
uint32 GetBattlegroundId() const
Definition Player.h:1971
void AddToWorld() override
Definition Player.cpp:1831
void UpdateObjectVisibility(bool forced=true) override
Definition Player.cpp:22294
void SetMap(Map *map) override
Definition Player.cpp:25517
InstancePlayerBind * BindToInstance(InstanceSave *save, bool permanent, BindExtensionState extendState=EXTEND_STATE_NORMAL, bool load=false)
Definition Player.cpp:18622
void RemoveFromWorld() override
Definition Player.cpp:1843
InstancePlayerBind * GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired=false)
Definition Player.cpp:18567
float m_homebindX
Definition Player.h:2075
void setUInt16(uint8 index, uint16 value)
void setUInt32(uint8 index, uint32 value)
void setUInt64(uint8 index, uint64 value)
TO * getTarget() const
Definition Reference.h:94
FROM * GetSource() const
Definition Reference.h:96
void DelayedUpdate(uint32 diff)
SPECIFIC_TYPE * Find(KEY_TYPE const &handle)
Definition Unit.h:783
bool IsVehicle() const
Definition Unit.h:901
void UpdateObjectVisibility(bool forced=true) override
Definition Unit.cpp:12151
MotionMaster * GetMotionMaster()
Definition Unit.h:1683
bool IsPet() const
Definition Unit.h:898
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Unit.cpp:9656
bool IsAlive() const
Definition Unit.h:1247
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1273
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5633
CombatManager & GetCombatManager()
Definition Unit.h:1144
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1351
Vehicle * GetVehicleKit() const
Definition Unit.h:1751
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT]
Definition Unit.h:1500
bool IsInCombat() const
Definition Unit.h:1158
bool HasData() const
Definition UpdateData.h:69
bool BuildPacket(WorldPacket *packet)
virtual float getHeight(unsigned int pMapId, float x, float y, float z, float maxSearchDist)=0
bool isHeightCalcEnabled() const
virtual bool getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, Optional< uint8 > reqLiquidType, AreaAndLiquidData &data) const =0
static VMapManager2 * createOrGetVMapManager()
void unloadMap(unsigned int mapId, int x, int y) override
int loadMap(char const *pBasePath, unsigned int mapId, int x, int y) override
void RelocatePassengers()
Relocate passengers. Must be called after m_base::Relocate.
Definition Vehicle.cpp:554
Weather for one zone.
Definition Weather.h:67
uint32 GetMapId() const
Definition Position.h:193
virtual void SetPhaseMask(uint32 newPhaseMask, bool update)
Definition Object.cpp:3416
uint32 GetPhaseMask() const
Definition Object.h:370
Map * GetMap() const
Definition Object.h:451
virtual void ResetMap()
Definition Object.cpp:1827
Map * FindMap() const
Definition Object.h:452
void RemoveFromWorld() override
Definition Object.cpp:1067
float GetGridActivationRange() const
Definition Object.cpp:1477
bool isActiveObject() const
Definition Object.h:553
uint32 GetInstanceId() const
Definition Object.h:367
std::string const & GetName() const
Definition Object.h:384
virtual void SetMap(Map *map)
Definition Object.cpp:1809
void DestroyForNearbyPlayers()
Definition Object.cpp:3448
Transport * GetTransport() const
Definition Object.h:566
void UpdatePositionData()
Definition Object.cpp:1043
bool IsStoredInWorldObjectGridContainer() const
Definition Object.cpp:981
uint32 GetZoneId() const
Definition Object.h:375
bool IsAlwaysStoredInWorldObjectGridContainer() const
Definition Object.h:560
virtual void Update(uint32 diff)
Definition Object.cpp:961
virtual void UpdateObjectVisibility(bool forced=true)
Definition Object.cpp:3481
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition Object.cpp:1032
void Initialize(ChatMsg chatType, Language language, WorldObject const *sender, WorldObject const *receiver, std::string_view message, uint32 achievementId=0, std::string_view channelName="", LocaleConstant locale=DEFAULT_LOCALE, std::string_view addonPrefix="")
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Player session in the World.
bool Update(uint32 diff, PacketFilter &updater)
Update the WorldSession (triggered by World update)
void SendCalendarRaidLockoutAdded(InstanceSave const *save)
void AddInstanceEnterTime(uint32 instanceId, SystemTimePoint enterTime)
static float GetMaxVisibleDistanceInInstances()
Definition World.h:742
static int32 GetVisibilityNotifyPeriodOnContinents()
Definition World.h:746
static float GetMaxVisibleDistanceInBG()
Definition World.h:743
static int32 GetVisibilityNotifyPeriodInArenas()
Definition World.h:749
static int32 GetVisibilityNotifyPeriodInBG()
Definition World.h:748
static int32 GetVisibilityNotifyPeriodInInstances()
Definition World.h:747
static float GetMaxVisibleDistanceOnContinents()
Definition World.h:741
static float GetMaxVisibleDistanceInArenas()
Definition World.h:744
@ SMSG_INSTANCE_LOCK_WARNING_QUERY
Definition Opcodes.h:356
@ SMSG_INSTANCE_SAVE_CREATED
Definition Opcodes.h:744
#define sWorld
Definition World.h:901
WeatherState
Definition Weather.h:47
WeatherData const * GetWeatherData(uint32 zone_id)
static void SendFineWeatherUpdateToPlayer(Player *player)
Definition Weather.cpp:200
@ CONFIG_RESPAWN_DYNAMICMINIMUM_CREATURE
Definition World.h:400
@ CONFIG_INSTANCE_UNLOAD_DELAY
Definition World.h:250
@ CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT
Definition World.h:401
@ CONFIG_RESPAWN_MINCHECKINTERVALMS
Definition World.h:395
@ WEATHER_STATE_FINE
Definition Weather.h:48
@ CONFIG_RESPAWN_DYNAMICRATE_CREATURE
Definition World.h:205
@ CONFIG_RESPAWN_DYNAMICRATE_GAMEOBJECT
Definition World.h:206
@ CONFIG_CHECK_GOBJECT_LOS
Definition World.h:177
@ CONFIG_GRID_UNLOAD
Definition World.h:94
@ CONFIG_DEATH_BONES_BG_OR_ARENA
Definition World.h:121
@ CONFIG_RESPAWN_DYNAMIC_ESCORTNPC
Definition World.h:178
@ CONFIG_DEATH_BONES_WORLD
Definition World.h:120
bool IsPathfindingEnabled(uint32 mapId)
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition GameTime.cpp:52
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
void RemoveObject(T *object)
TC_GAME_API Corpse * GetCorpse(WorldObject const &u, ObjectGuid const &guid)
auto MapEqualRange(M &map, typename M::key_type const &key)
GridCoord ComputeGridCoordSimple(float x, float y)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
GridCoord ComputeGridCoord(float x, float y)
CellCoord ComputeCellCoord(float x, float y)
@ VMAP_LOAD_RESULT_ERROR
@ VMAP_LOAD_RESULT_OK
@ VMAP_LOAD_RESULT_IGNORED
STL namespace.
uint32 LiquidTypeID[4]
CellCoord high_bound
Definition Cell.h:43
CellCoord low_bound
Definition Cell.h:42
Definition Cell.h:47
uint32 GridX() const
Definition Cell.h:72
void SetNoCreate()
Definition Cell.h:75
union Cell::@256 data
uint8 grid_x
Definition Cell.h:89
struct Cell::@256::@257 Part
uint32 GridY() const
Definition Cell.h:73
bool DiffGrid(Cell const &cell) const
Definition Cell.h:64
bool DiffCell(Cell const &cell) const
Definition Cell.h:58
uint32 CellX() const
Definition Cell.h:70
uint32 CellY() const
Definition Cell.h:71
static CellArea CalculateCellArea(float x, float y, float radius)
Definition CellImpl.h:35
uint8 grid_y
Definition Cell.h:90
bool IsCoordValid() const
uint32 x_coord
void inc_y(uint32 val)
void dec_x(uint32 val)
void inc_x(uint32 val)
uint32 y_coord
uint32 GetId() const
void dec_y(uint32 val)
InstanceSave * save
Definition Group.h:155
InstanceSave * save
Definition Player.h:760
BindExtensionState extendState
Definition Player.h:769
void SetInterval(time_t interval)
Definition Timer.h:94
time_t GetInterval() const
Definition Timer.h:99
bool Passed()
Definition Timer.h:78
void Update(time_t diff)
Definition Timer.h:71
void Reset()
Definition Timer.h:83
uint32 entry
Definition MapDefines.h:88
float depth_level
Definition MapDefines.h:90
uint32 type_flags
Definition MapDefines.h:87
float level
Definition MapDefines.h:89
bool IsBattleground() const
bool GetEntrancePos(int32 &mapid, float &x, float &y) const
uint32 MaxPlayers
bool IsNonRaidDungeon() const
char const * MapName[16]
bool IsWorldMap() const
bool IsBattlegroundOrArena() const
bool IsDungeon() const
bool IsRaid() const
bool IsBattleArena() const
bool Instanceable() const
uint32 AreaTableID
void TUpdate(int32 diff)
Definition Timer.h:180
bool TPassed() const
Definition Timer.h:181
void TReset(int32 diff, int32 period)
Definition Timer.h:182
Optional< LiquidData > liquidInfo
Definition MapDefines.h:113
Optional< WmoLocation > wmoLocation
Definition MapDefines.h:112
ZLiquidStatus liquidStatus
Definition MapDefines.h:111
float m_positionX
Definition Position.h:56
float GetPositionZ() const
Definition Position.h:81
float m_positionY
Definition Position.h:57
float GetOrientation() const
Definition Position.h:82
bool IsPositionValid() const
Definition Position.cpp:44
float GetPositionX() const
Definition Position.h:79
float GetPositionY() const
Definition Position.h:80
void Relocate(float x, float y)
Definition Position.h:66
void resetNotify(GridRefManager< T > &m)
Definition Map.cpp:915
void Visit(PlayerMapType &m)
Definition Map.cpp:922
void Visit(GridRefManager< T > &)
Definition Map.cpp:920
void Visit(CreatureMapType &m)
Definition Map.cpp:921
RespawnInfoWithHandle(RespawnInfo const &other)
Definition Map.cpp:83
RespawnListContainer::handle_type handle
Definition Map.cpp:85
uint32 gridId
Definition Map.h:284
ObjectGuid::LowType spawnId
Definition Map.h:281
time_t respawnTime
Definition Map.h:283
virtual ~RespawnInfo()
uint32 entry
Definition Map.h:282
SpawnObjectType type
Definition Map.h:280
SpawnGroupFlags flags
Definition SpawnData.h:63
SpawnObjectType const type
Definition SpawnData.h:84
uint32 spawnId
Definition SpawnData.h:85
static constexpr bool TypeHasData(SpawnObjectType type)
Definition SpawnData.h:77
SpawnGroupTemplateData const * spawnGroupData
Definition SpawnData.h:88
SpawnData const * ToSpawnData() const
Definition SpawnData.h:82
uint32 mapId
Definition SpawnData.h:86
Optional< AreaInfo > areaInfo
Optional< LiquidInfo > liquidInfo
ZoneDynamicInfo()
Definition Map.cpp:71
std::vector< LightOverride > LightOverrides
Definition Map.h:256
WeatherState WeatherId
Definition Map.h:247
std::unique_ptr< Weather > DefaultWeather
Definition Map.h:246
float Intensity
Definition Map.h:248
uint32 fourcc
Definition Map.h:131
uint16 gridArea
Definition Map.h:133
uint16 flags
Definition Map.h:132
u_map_magic mapMagic
Definition Map.h:114
uint32 holesSize
Definition Map.h:124
uint32 liquidMapSize
Definition Map.h:122
uint32 areaMapOffset
Definition Map.h:117
uint32 heightMapSize
Definition Map.h:120
uint32 heightMapOffset
Definition Map.h:119
uint32 holesOffset
Definition Map.h:123
uint32 versionMagic
Definition Map.h:115
uint32 liquidMapOffset
Definition Map.h:121
uint32 areaMapSize
Definition Map.h:118
float gridMaxHeight
Definition Map.h:146
uint32 flags
Definition Map.h:144
float gridHeight
Definition Map.h:145
uint32 fourcc
Definition Map.h:143
uint8 offsetX
Definition Map.h:158
uint32 fourcc
Definition Map.h:154
uint8 liquidFlags
Definition Map.h:156
uint8 width
Definition Map.h:160
uint8 height
Definition Map.h:161
uint8 flags
Definition Map.h:155
uint16 liquidType
Definition Map.h:157
uint8 offsetY
Definition Map.h:159
float liquidLevel
Definition Map.h:162
Represents a map magic value of 4 bytes (used in versions)
Definition Map.h:104
char asChar[4]
Definition Map.h:105
uint32 asUInt
‍Non-null terminated string
Definition Map.h:106