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 "Chat.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() && IsRaid() && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
3875
3876 // cannot enter if player is permanent saved to a different instance id
3877 if (InstancePlayerBind* playerBind = player->GetBoundInstance(GetId(), GetDifficulty()))
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->GetDifficulty()), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset(), GetMapName(), mapSave->GetMapId(), mapSave->GetInstanceId(), static_cast<uint32>(mapSave->GetDifficulty()), 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->GetDifficulty()), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), group->GetLeaderGUID().ToString(), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), static_cast<uint32>(playerBind->save->GetDifficulty()), 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->GetDifficulty()), 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->GetDifficulty()), group->GetLeaderGUID().ToString(), groupBind->save->GetMapId(), groupBind->save->GetInstanceId(), static_cast<uint32>(groupBind->save->GetDifficulty()));
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(), GetDifficulty());
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>(GetDifficulty()), 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->GetDifficulty());
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->GetDifficulty()), 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->GetDifficulty()), 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(), itr->GetSource()->GetDifficulty(IsRaid()), 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{
4224}
4225
4227{
4228 return i_mapEntry && i_mapEntry->Instanceable();
4229}
4230
4232{
4233 return i_mapEntry && i_mapEntry->IsWorldMap();
4234}
4235
4236bool Map::IsDungeon() const
4237{
4238 return i_mapEntry && i_mapEntry->IsDungeon();
4239}
4240
4242{
4244}
4245
4246bool Map::IsRaid() const
4247{
4248 return i_mapEntry && i_mapEntry->IsRaid();
4249}
4250
4252{
4254}
4255
4260
4262{
4263 // since 25man difficulties are 1 and 3, we can check them like that
4265}
4266
4268{
4270}
4271
4273{
4274 return i_mapEntry && i_mapEntry->IsBattleArena();
4275}
4276
4278{
4280}
4281
4282bool Map::GetEntrancePos(int32& mapid, float& x, float& y) const
4283{
4284 if (!i_mapEntry)
4285 return false;
4286 return i_mapEntry->GetEntrancePos(mapid, x, y);
4287}
4288
4290{
4292 stmt->setUInt16(0,GetInstanceId());
4293 return !!CharacterDatabase.Query(stmt);
4294}
4295
4297{
4298 MapDifficulty const* mapDiff = GetMapDifficulty();
4299 if (mapDiff && mapDiff->maxPlayers)
4300 return mapDiff->maxPlayers;
4301
4302 return GetEntry()->MaxPlayers;
4303}
4304
4306{
4307 MapDifficulty const* mapDiff = GetMapDifficulty();
4308 return mapDiff ? mapDiff->resetTime : 0;
4309}
4310
4311/* ******* Battleground Instance Maps ******* */
4312
4313BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode)
4314 : Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr)
4315{
4316 //lets initialize visibility distance for BG/Arenas
4318}
4319
4321{
4322 if (m_bg)
4323 {
4324 //unlink to prevent crash, always unlink all pointer reference before destruction
4325 m_bg->SetBgMap(nullptr);
4326 m_bg = nullptr;
4327 }
4328}
4329
4336
4338{
4339 if (player->GetMapRef().getTarget() == this)
4340 {
4341 TC_LOG_ERROR("maps", "BGMap::CannotEnter - player {} is already in map!", player->GetGUID().ToString());
4342 ABORT();
4344 }
4345
4346 if (player->GetBattlegroundId() != GetInstanceId())
4348
4349 // player number limit is checked in bgmgr, no need to do it here
4350
4351 return Map::CannotEnter(player);
4352}
4353
4355{
4356 {
4357 std::lock_guard<std::mutex> lock(_mapLock);
4358 //Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
4359 //if (!CanEnter(player))
4360 //return false;
4361 // reset instance validity, battleground maps do not homebind
4362 player->m_InstanceValid = true;
4363 }
4364 return Map::AddPlayerToMap(player);
4365}
4366
4368{
4369 TC_LOG_DEBUG("maps", "MAP: Removing player '{}' from bg '{}' of map '{}' before relocating to another map", player->GetName(), GetInstanceId(), GetMapName());
4370 Map::RemovePlayerFromMap(player, remove);
4371}
4372
4377
4379{
4380 if (HavePlayers())
4381 for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
4382 if (Player* player = itr->GetSource())
4383 if (!player->IsBeingTeleportedFar())
4384 player->TeleportTo(player->GetBattlegroundEntryPoint());
4385}
4386
4388{
4389 return ObjectAccessor::GetPlayer(this, guid);
4390}
4391
4393{
4394 return _objectsStore.Find<Corpse>(guid);
4395}
4396
4398{
4399 return _objectsStore.Find<Creature>(guid);
4400}
4401
4403{
4404 auto const bounds = GetCreatureBySpawnIdStore().equal_range(spawnId);
4405 if (bounds.first == bounds.second)
4406 return nullptr;
4407
4408 std::unordered_multimap<uint32, Creature*>::const_iterator creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
4409 {
4410 return pair.second->IsAlive();
4411 });
4412
4413 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
4414}
4415
4417{
4418 auto const bounds = GetGameObjectBySpawnIdStore().equal_range(spawnId);
4419 if (bounds.first == bounds.second)
4420 return nullptr;
4421
4422 std::unordered_multimap<uint32, GameObject*>::const_iterator creatureItr = std::find_if(bounds.first, bounds.second, [](Map::GameObjectBySpawnIdContainer::value_type const& pair)
4423 {
4424 return pair.second->isSpawned();
4425 });
4426
4427 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
4428}
4429
4431{
4432 return _objectsStore.Find<GameObject>(guid);
4433}
4434
4436{
4437 return _objectsStore.Find<Pet>(guid);
4438}
4439
4441{
4442 if (!guid.IsMOTransport())
4443 return nullptr;
4444
4445 GameObject* go = GetGameObject(guid);
4446 return go ? go->ToTransport() : nullptr;
4447}
4448
4453
4455{
4456 if (&*m_mapRefIter == &player->GetMapRef())
4458}
4459
4460void Map::SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans, bool startup)
4461{
4462 SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(type, spawnId);
4463 if (!data)
4464 {
4465 TC_LOG_ERROR("maps", "Map {} attempt to save respawn time for nonexistant spawnid ({},{}).", GetId(), type, spawnId);
4466 return;
4467 }
4468
4469 if (!respawnTime)
4470 {
4471 // Delete only
4472 RemoveRespawnTime(data->type, data->spawnId, dbTrans);
4473 return;
4474 }
4475
4476 RespawnInfo ri;
4477 ri.type = data->type;
4478 ri.spawnId = data->spawnId;
4479 ri.entry = entry;
4480 ri.respawnTime = respawnTime;
4481 ri.gridId = gridId;
4482 bool success = AddRespawnInfo(ri);
4483
4484 if (startup)
4485 {
4486 if (!success)
4487 TC_LOG_ERROR("maps", "Attempt to load saved respawn {} for ({},{}) failed - duplicate respawn? Skipped.", respawnTime, uint32(type), spawnId);
4488 }
4489 else if (success)
4490 SaveRespawnInfoDB(ri, dbTrans);
4491}
4492
4494{
4496 stmt->setUInt16(0, info.type);
4497 stmt->setUInt32(1, info.spawnId);
4498 stmt->setUInt64(2, uint64(info.respawnTime));
4499 stmt->setUInt16(3, GetId());
4500 stmt->setUInt32(4, GetInstanceId());
4501 CharacterDatabase.ExecuteOrAppend(dbTrans, stmt);
4502}
4503
4505{
4507 stmt->setUInt16(0, GetId());
4508 stmt->setUInt32(1, GetInstanceId());
4509 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
4510 {
4511 do
4512 {
4513 Field* fields = result->Fetch();
4514 SpawnObjectType type = SpawnObjectType(fields[0].GetUInt16());
4515 ObjectGuid::LowType spawnId = fields[1].GetUInt32();
4516 uint64 respawnTime = fields[2].GetUInt64();
4517
4518 if (SpawnData::TypeHasData(type))
4519 {
4520 if (SpawnData const* data = sObjectMgr->GetSpawnData(type, spawnId))
4521 SaveRespawnTime(type, spawnId, data->id, time_t(respawnTime), Trinity::ComputeGridCoord(data->spawnPoint.GetPositionX(), data->spawnPoint.GetPositionY()).GetId(), nullptr, true);
4522 else
4523 TC_LOG_ERROR("maps", "Loading saved respawn time of {} for spawnid ({},{}) - spawn does not exist, ignoring", respawnTime, uint32(type), spawnId);
4524 }
4525 else
4526 {
4527 TC_LOG_ERROR("maps", "Loading saved respawn time of {} for spawnid ({},{}) - invalid spawn type, ignoring", respawnTime, uint32(type), spawnId);
4528 }
4529
4530 } while (result->NextRow());
4531 }
4532}
4533
4534/*static*/ void Map::DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
4535{
4537 stmt->setUInt16(0, mapId);
4538 stmt->setUInt32(1, instanceId);
4539 CharacterDatabase.Execute(stmt);
4540}
4541
4543{
4544 ObjectGuid linkedGuid = sObjectMgr->GetLinkedRespawnGuid(guid);
4545 switch (linkedGuid.GetHigh())
4546 {
4547 case HighGuid::Unit:
4548 return GetCreatureRespawnTime(linkedGuid.GetCounter());
4550 return GetGORespawnTime(linkedGuid.GetCounter());
4551 default:
4552 break;
4553 }
4554
4555 return time_t(0);
4556}
4557
4559{
4561 stmt->setUInt32(0, GetId());
4562 stmt->setUInt32(1, GetInstanceId());
4563
4564 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
4565 // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask, guid FROM corpse WHERE mapId = ? AND instanceId = ?
4566 PreparedQueryResult result = CharacterDatabase.Query(stmt);
4567 if (!result)
4568 return;
4569
4570 do
4571 {
4572 Field* fields = result->Fetch();
4573 CorpseType type = CorpseType(fields[13].GetUInt8());
4574 ObjectGuid::LowType guid = fields[16].GetUInt32();
4575 if (type >= MAX_CORPSE_TYPE || type == CORPSE_BONES)
4576 {
4577 TC_LOG_ERROR("misc", "Corpse (guid: {}) have wrong corpse type ({}), not loading.", guid, type);
4578 continue;
4579 }
4580
4581 Corpse* corpse = new Corpse(type);
4582
4583 if (!corpse->LoadCorpseFromDB(GenerateLowGuid<HighGuid::Corpse>(), fields))
4584 {
4585 delete corpse;
4586 continue;
4587 }
4588
4589 AddCorpse(corpse);
4590
4591 } while (result->NextRow());
4592}
4593
4595{
4596 // DELETE FROM corpse WHERE mapId = ? AND instanceId = ?
4598 stmt->setUInt32(0, GetId());
4599 stmt->setUInt32(1, GetInstanceId());
4600 CharacterDatabase.Execute(stmt);
4601}
4602
4604{
4605 corpse->SetMap(this);
4606
4607 _corpsesByCell[corpse->GetCellCoord().GetId()].insert(corpse);
4608 if (corpse->GetType() != CORPSE_BONES)
4609 _corpsesByPlayer[corpse->GetOwnerGUID()] = corpse;
4610 else
4611 _corpseBones.insert(corpse);
4612}
4613
4615{
4616 ASSERT(corpse);
4617
4618 corpse->DestroyForNearbyPlayers();
4619 if (corpse->IsInGrid())
4620 RemoveFromMap(corpse, false);
4621 else
4622 {
4623 corpse->RemoveFromWorld();
4624 corpse->ResetMap();
4625 }
4626
4627 _corpsesByCell[corpse->GetCellCoord().GetId()].erase(corpse);
4628 if (corpse->GetType() != CORPSE_BONES)
4629 _corpsesByPlayer.erase(corpse->GetOwnerGUID());
4630 else
4631 _corpseBones.erase(corpse);
4632}
4633
4634Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= false*/)
4635{
4636 Corpse* corpse = GetCorpseByPlayer(ownerGuid);
4637 if (!corpse)
4638 return nullptr;
4639
4640 RemoveCorpse(corpse);
4641
4642 // remove corpse from DB
4643 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
4644 corpse->DeleteFromDB(trans);
4645 CharacterDatabase.CommitTransaction(trans);
4646
4647 Corpse* bones = nullptr;
4648
4649 // create the bones only if the map and the grid is loaded at the corpse's location
4650 // ignore bones creating option in case insignia
4651 if ((insignia ||
4653 !IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
4654 {
4655 // Create bones, don't change Corpse
4656 bones = new Corpse();
4657 bones->Create(corpse->GetGUID().GetCounter());
4658
4659 for (uint8 i = OBJECT_FIELD_TYPE + 1; i < CORPSE_END; ++i) // don't overwrite guid and object type
4660 bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
4661
4662 bones->SetCellCoord(corpse->GetCellCoord());
4663 bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
4664 bones->SetPhaseMask(corpse->GetPhaseMask(), false);
4665
4668
4669 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
4670 if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
4671 bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
4672
4673 AddCorpse(bones);
4674
4675 // add bones in grid store if grid loaded where corpse placed
4676 AddToMap(bones);
4677 }
4678
4679 // all references to the corpse should be removed at this point
4680 delete corpse;
4681
4682 return bones;
4683}
4684
4686{
4687 time_t now = GameTime::GetGameTime();
4688
4689 std::vector<ObjectGuid> corpses;
4690 corpses.reserve(_corpsesByPlayer.size());
4691
4692 for (auto const& p : _corpsesByPlayer)
4693 if (p.second->IsExpired(now))
4694 corpses.push_back(p.first);
4695
4696 for (ObjectGuid const& ownerGuid : corpses)
4697 ConvertCorpseToBones(ownerGuid);
4698
4699 std::vector<Corpse*> expiredBones;
4700 for (Corpse* bones : _corpseBones)
4701 if (bones->IsExpired(now))
4702 expiredBones.push_back(bones);
4703
4704 for (Corpse* bones : expiredBones)
4705 {
4706 RemoveCorpse(bones);
4707 delete bones;
4708 }
4709}
4710
4711void Map::SendZoneDynamicInfo(uint32 zoneId, Player* player) const
4712{
4713 auto itr = _zoneDynamicInfo.find(zoneId);
4714 if (itr == _zoneDynamicInfo.end())
4715 return;
4716
4717 if (uint32 music = itr->second.MusicId)
4718 player->SendDirectMessage(WorldPackets::Misc::PlayMusic(music).Write());
4719
4720 SendZoneWeather(itr->second, player);
4721
4722 for (ZoneDynamicInfo::LightOverride const& lightOverride : itr->second.LightOverrides)
4723 {
4725 overrideLight.AreaLightID = lightOverride.AreaLightId;
4726 overrideLight.OverrideLightID = lightOverride.OverrideLightId;
4727 overrideLight.TransitionMilliseconds = lightOverride.TransitionMilliseconds;
4728 player->SendDirectMessage(overrideLight.Write());
4729 }
4730}
4731
4732void Map::SendZoneWeather(uint32 zoneId, Player* player) const
4733{
4734 auto itr = _zoneDynamicInfo.find(zoneId);
4735 if (itr == _zoneDynamicInfo.end())
4736 return;
4737
4738 SendZoneWeather(itr->second, player);
4739}
4740
4741void Map::SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const
4742{
4743 if (WeatherState weatherId = zoneDynamicInfo.WeatherId)
4744 {
4745 WorldPackets::Misc::Weather weather(weatherId, zoneDynamicInfo.Intensity);
4746 player->SendDirectMessage(weather.Write());
4747 }
4748 else if (zoneDynamicInfo.DefaultWeather)
4749 {
4750 zoneDynamicInfo.DefaultWeather->SendWeatherUpdateToPlayer(player);
4751 }
4752 else
4754}
4755
4757void Map::SendZoneText(uint32 zoneId, char const* text, WorldSession const* self, uint32 team) const
4758{
4759 WorldPacket data;
4760 ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text);
4761 SendZoneMessage(zoneId, &data, self, team);
4762}
4763
4764void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
4765{
4766 _zoneDynamicInfo[zoneId].MusicId = musicId;
4767
4768 WorldPackets::Misc::PlayMusic playMusic(musicId);
4769 SendZoneMessage(zoneId, WorldPackets::Misc::PlayMusic(musicId).Write());
4770}
4771
4773{
4774 WeatherData const* weatherData = WeatherMgr::GetWeatherData(zoneId);
4775 if (!weatherData)
4776 return nullptr;
4777
4778 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4779 if (!info.DefaultWeather)
4780 {
4781 info.DefaultWeather = std::make_unique<Weather>(this, zoneId, weatherData);
4782 info.DefaultWeather->ReGenerate();
4783 info.DefaultWeather->UpdateWeather();
4784 }
4785
4786 return info.DefaultWeather.get();
4787}
4788
4789void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float intensity)
4790{
4791 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4792 info.WeatherId = weatherId;
4793 info.Intensity = intensity;
4794
4795 SendZoneMessage(zoneId, WorldPackets::Misc::Weather(weatherId, intensity).Write());
4796}
4797
4798void Map::SetZoneOverrideLight(uint32 zoneId, uint32 areaLightId, uint32 overrideLightId, Milliseconds transitionTime)
4799{
4800 ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
4801 // client can support only one override for each light (zone independent)
4802 info.LightOverrides.erase(std::remove_if(info.LightOverrides.begin(), info.LightOverrides.end(), [areaLightId](ZoneDynamicInfo::LightOverride const& lightOverride)
4803 {
4804 return lightOverride.AreaLightId == areaLightId;
4805 }), info.LightOverrides.end());
4806
4807 // set new override (if any)
4808 if (overrideLightId)
4809 {
4810 ZoneDynamicInfo::LightOverride& lightOverride = info.LightOverrides.emplace_back();
4811 lightOverride.AreaLightId = areaLightId;
4812 lightOverride.OverrideLightId = overrideLightId;
4813 lightOverride.TransitionMilliseconds = static_cast<uint32>(transitionTime.count());
4814 }
4815
4817 overrideLight.AreaLightID = areaLightId;
4818 overrideLight.OverrideLightID = overrideLightId;
4819 overrideLight.TransitionMilliseconds = static_cast<uint32>(transitionTime.count());
4820 SendZoneMessage(zoneId, overrideLight.Write());
4821}
4822
4824{
4825 Map::PlayerList const& players = GetPlayers();
4826 for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
4827 {
4828 if (Player* player = itr->GetSource())
4829 {
4830 if (player->IsInWorld())
4831 {
4832 player->UpdateAreaDependentAuras(player->GetAreaId());
4833 player->UpdateZoneDependentAuras(player->GetZoneId());
4834 }
4835 }
4836 }
4837}
4838
4839std::string Map::GetDebugInfo() const
4840{
4841 std::stringstream sstr;
4842 sstr << std::boolalpha
4843 << "Id: " << GetId() << " InstanceId: " << GetInstanceId() << " Difficulty: " << std::to_string(GetDifficulty())
4844 << " HasPlayers: " << HavePlayers();
4845 return sstr.str();
4846}
4847
4848std::string InstanceMap::GetDebugInfo() const
4849{
4850 std::stringstream sstr;
4851 sstr << Map::GetDebugInfo() << "\n"
4852 << std::boolalpha
4853 << "ScriptId: " << GetScriptId() << " ScriptName: " << GetScriptName();
4854 return sstr.str();
4855}
4856
@ 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
@ CORPSE_FLAG_UNK2
Definition Corpse.h:43
#define MAX_CORPSE_TYPE
Definition Corpse.h:33
Difficulty
Definition DBCEnums.h:279
@ DUNGEON_DIFFICULTY_NORMAL
Definition DBCEnums.h:282
@ REGULAR_DIFFICULTY
Definition DBCEnums.h:280
@ DUNGEON_DIFFICULTY_HEROIC
Definition DBCEnums.h:283
@ RAID_DIFFICULTY_10MAN_HEROIC
Definition DBCEnums.h:288
#define RAID_DIFFICULTY_MASK_25MAN
Definition DBCEnums.h:292
@ AREA_FLAG_OUTSIDE
Definition DBCEnums.h:273
@ AREA_FLAG_INSIDE
Definition DBCEnums.h:272
MapDifficulty 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:244
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS
Definition Map.h:118
#define MAP_HEIGHT_AS_INT8
Definition Map.h:117
#define MAP_AREA_NO_AREA
Definition Map.h:106
std::unordered_map< ObjectGuid::LowType, RespawnInfo * > RespawnInfoMap
Definition Map.h:254
#define MAP_LIQUID_NO_TYPE
Definition Map.h:128
#define MAP_LIQUID_NO_HEIGHT
Definition Map.h:129
#define MAP_LIQUID_TYPE_WATER
Definition Map.h:145
#define MAP_LIQUID_TYPE_DARK_WATER
Definition Map.h:152
#define MAP_LIQUID_TYPE_OCEAN
Definition Map.h:146
@ INSTANCE_RESET_CHANGE_DIFFICULTY
Definition Map.h:868
@ INSTANCE_RESET_GLOBAL
Definition Map.h:869
@ INSTANCE_RESET_ALL
Definition Map.h:867
#define MAP_HEIGHT_NO_HEIGHT
Definition Map.h:115
#define MAP_INVALID_ZONE
Definition Map.h:245
#define INVALID_HEIGHT
Definition Map.h:241
#define MAP_HEIGHT_AS_INT16
Definition Map.h:116
#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
@ EQUIPMENT_SLOT_END
Definition Player.h:571
#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
@ CORPSE_FIELD_FLAGS
@ CORPSE_END
@ CORPSE_FIELD_ITEM
@ CORPSE_FIELD_OWNER
@ OBJECT_FIELD_TYPE
bool AddPlayerToMap(Player *) override
Definition Map.cpp:4354
BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map *_parent, uint8 spawnMode)
Definition Map.cpp:4313
void SetUnload()
Definition Map.cpp:4373
void RemoveAllPlayers() override
Definition Map.cpp:4378
EnterState CannotEnter(Player *player) override
Definition Map.cpp:4337
Battleground * m_bg
Definition Map.h:931
void RemovePlayerFromMap(Player *, bool) override
Definition Map.cpp:4367
virtual void InitVisibilityDistance() override
Definition Map.cpp:4330
void SetBgMap(BattlegroundMap *map)
void clear()
Definition ByteBuffer.h:123
static size_t BuildChatPacket(WorldPacket &data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag, std::string const &senderName="", std::string const &receiverName="", uint32 achievementId=0, bool gmMessage=false, std::string const &channelName="")
Definition Chat.cpp:193
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
bool Create(ObjectGuid::LowType guidlow)
Definition Corpse.cpp:66
void RemoveFromWorld() override
Definition Corpse.cpp:57
CellCoord const & GetCellCoord() const
Definition Corpse.h:74
ObjectGuid GetOwnerGUID() const override
Definition Corpse.h:67
bool LoadCorpseFromDB(ObjectGuid::LowType guid, Field *fields)
Definition Corpse.cpp:152
void SetCellCoord(CellCoord const &cellCoord)
Definition Corpse.h:75
CorpseType GetType() const
Definition Corpse.h:72
void DeleteFromDB(CharacterDatabaseTransaction trans)
Definition Corpse.cpp:126
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:337
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:155
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:165
GridMap()
Definition Map.cpp:1784
float _liquidLevel
Definition Map.h:176
uint16 * m_uint16_V8
Definition Map.h:164
~GridMap()
Definition Map.cpp:1811
uint16 getArea(float x, float y) const
Definition Map.cpp:2048
uint16 * _liquidEntry
Definition Map.h:177
float getHeightFromFloat(float x, float y) const
Definition Map.cpp:2065
uint8 _liquidGlobalFlags
Definition Map.h:182
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:184
uint16 _liquidGlobalEntry
Definition Map.h:181
uint8 _liquidOffX
Definition Map.h:183
uint8 * m_uint8_V9
Definition Map.h:160
float * _liquidMap
Definition Map.h:179
uint32 _flags
Definition Map.h:156
bool loadHolesData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:2036
uint8 _liquidHeight
Definition Map.h:186
uint16 * _areaMap
Definition Map.h:173
float _gridIntHeightMultiplier
Definition Map.h:170
uint8 _liquidWidth
Definition Map.h:185
uint8 * _liquidFlags
Definition Map.h:178
float getLiquidLevel(float x, float y) const
Definition Map.cpp:2335
float * m_V9
Definition Map.h:158
G3D::Plane * _minHeightPlanes
Definition Map.h:167
uint16 _gridArea
Definition Map.h:180
uint16 * m_uint16_V9
Definition Map.h:159
float getHeightFromUint8(float x, float y) const
Definition Map.cpp:2150
float getHeight(float x, float y) const
Definition Map.h:211
bool loadHeightData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:1912
float _gridHeight
Definition Map.h:169
GetHeightPtr _gridGetHeight
Definition Map.h:198
bool loadLiquidData(FILE *in, uint32 offset, uint32 size)
Definition Map.cpp:2001
uint16 * _holes
Definition Map.h:188
float * m_V8
Definition Map.h:163
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:2443
InstanceGroupBind * BindToInstance(InstanceSave *save, bool permanent, bool load=false)
Definition Group.cpp:2321
ObjectGuid GetLeaderGUID() const
Definition Group.cpp:2468
InstanceGroupBind * GetBoundInstance(Player *player)
Definition Group.cpp:2286
bool AddPlayerToMap(Player *) override
Definition Map.cpp:3888
bool m_resetAfterUnload
Definition Map.h:907
void Update(uint32) override
Definition Map.cpp:4005
void CreateInstanceData(bool load)
Definition Map.cpp:4031
bool m_unloadWhenEmpty
Definition Map.h:908
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:4296
virtual void InitVisibilityDistance() override
Definition Map.cpp:3841
uint32 GetScriptId() const
Definition Map.h:885
void RemovePlayerFromMap(Player *, bool) override
Definition Map.cpp:4013
void PermBindAllPlayers()
Definition Map.cpp:4129
uint32 GetMaxResetDelay() const
Definition Map.cpp:4305
bool HasPermBoundPlayers() const
Definition Map.cpp:4289
EnterState CannotEnter(Player *player) override
Definition Map.cpp:3851
InstanceScript * i_data
Definition Map.h:909
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:4848
uint32 i_script_id
Definition Map.h:910
InstanceScript * GetInstanceScript()
Definition Map.h:887
~InstanceMap()
Definition Map.cpp:3835
uint8 GetPlayerCount() const
uint8 GetGroupCount() const
uint32 GetInstanceId() const
uint32 GetMapId() const
Difficulty GetDifficulty() 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:281
MapEntry const * i_mapEntry
Definition Map.h:674
uint8 i_spawnMode
Definition Map.h:675
void DynamicObjectRelocation(DynamicObject *go, float x, float y, float z, float orientation)
Definition Map.cpp:1174
bool _creatureToMoveLock
Definition Map.h:640
std::map< WorldObject *, bool > i_objectsToSwitch
Definition Map.h:723
WorldObject * GetWorldObjectBySpawnId(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition Map.h:473
std::unordered_map< uint32, uint32 > _zonePlayerCountMap
Definition Map.h:845
float GetWaterLevel(float x, float y) const
Definition Map.cpp:2862
std::vector< Creature * > _creaturesToMove
Definition Map.h:641
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:4236
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:4764
bool IsBattlegroundOrArena() const
Definition Map.cpp:4277
bool UnloadGrid(NGridType &ngrid, bool pForce)
Definition Map.cpp:1649
std::unordered_map< ObjectGuid, Corpse * > _corpsesByPlayer
Definition Map.h:857
void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float intensity)
Definition Map.cpp:4789
Pet * GetPet(ObjectGuid const &guid)
Definition Map.cpp:4435
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:489
TransportsContainer::iterator _transportsUpdateIter
Definition Map.h:694
void InitializeObject(T *obj)
Definition Map.cpp:615
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId)
Definition Map.cpp:4534
bool IsWorldMap() const
Definition Map.cpp:4231
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:4732
virtual void RemovePlayerFromMap(Player *, bool)
Definition Map.cpp:1002
void MoveAllGameObjectsInMoveList()
Definition Map.cpp:1321
Creature * GetCreatureBySpawnId(ObjectGuid::LowType spawnId) const
Definition Map.cpp:4402
void RemoveFromActiveHelper(WorldObject *obj)
Definition Map.h:797
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:781
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:4711
void RemoveFromActive(WorldObject *obj)
Definition Map.cpp:3771
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:4757
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:4594
void EnsureGridCreated(GridCoord const &)
Definition Map.cpp:485
void DeleteRespawnTimes()
Definition Map.h:562
Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map *_parent=nullptr)
Definition Map.cpp:272
void RemoveUpdateObject(Object *obj)
Definition Map.h:605
RespawnInfoMap _gameObjectRespawnTimesBySpawnId
Definition Map.h:815
NGridType * i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
Definition Map.h:713
void ProcessRespawns()
Definition Map.cpp:3261
Weather * GetOrGenerateZoneDefaultWeather(uint32 zoneId)
Definition Map.cpp:4772
uint32 m_unloadTimer
Definition Map.h:678
virtual void DelayedUpdate(uint32 diff)
Definition Map.cpp:3523
Player * GetPlayer(ObjectGuid const &guid)
Definition Map.cpp:4387
uint8 GetSpawnMode() const
Definition Map.h:388
MapDifficulty const * GetMapDifficulty() const
Definition Map.cpp:4211
bool IsNonRaidDungeon() const
Definition Map.cpp:4241
time_t GetLinkedRespawnTime(ObjectGuid guid) const
Definition Map.cpp:4542
void AddCorpse(Corpse *corpse)
Definition Map.cpp:4603
bool IsBattleground() const
Definition Map.cpp:4267
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:848
bool CheckRespawn(RespawnInfo *info)
Definition Map.cpp:3034
Map * m_parentMap
Definition Map.h:711
bool IsRaid() const
Definition Map.cpp:4246
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:753
bool _dynamicObjectsToMoveLock
Definition Map.h:646
NGridType * getNGrid(uint32 x, uint32 y) const
Definition Map.h:657
bool Is25ManRaid() const
Definition Map.cpp:4261
void AddToActiveHelper(WorldObject *obj)
Definition Map.h:792
bool _gameObjectsToMoveLock
Definition Map.h:643
void RemoveOldCorpses()
Definition Map.cpp:4685
uint32 _respawnCheckTimer
Definition Map.h:844
Corpse * ConvertCorpseToBones(ObjectGuid const &ownerGuid, bool insignia=false)
Definition Map.cpp:4634
bool HavePlayers() const
Definition Map.h:437
bool IsRemovalGrid(float x, float y) const
Definition Map.h:323
std::unordered_map< uint32, std::unordered_set< Corpse * > > _corpsesByCell
Definition Map.h:856
MapRefManager m_mapRefManager
Definition Map.h:682
void resetMarkedCells()
Definition Map.h:433
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:935
ScriptScheduleMap m_scriptSchedule
Definition Map.h:727
float GetMinHeight(float x, float y) const
Definition Map.cpp:2530
void AddWorldObject(WorldObject *obj)
Definition Map.h:441
void ResetGridExpiry(NGridType &grid, float factor=1) const
Definition Map.h:343
DynamicMapTree _dynamicTree
Definition Map.h:680
std::vector< GameObject * > _gameObjectsToMove
Definition Map.h:644
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:4504
bool GameObjectRespawnRelocation(GameObject *go, bool diffGridOnly)
Definition Map.cpp:1623
time_t i_gridExpiry
Definition Map.h:707
int32 m_VisibilityNotifyPeriod
Definition Map.h:685
std::unordered_set< Corpse * > _corpseBones
Definition Map.h:858
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:862
void LoadVMap(int gx, int gy)
Definition Map.cpp:178
time_t GetGORespawnTime(ObjectGuid::LowType spawnId) const
Definition Map.h:555
bool i_scriptLock
Definition Map.h:721
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:816
std::unordered_set< uint32 > _toggledSpawnGroupIds
Definition Map.h:842
bool isCellMarked(uint32 pCellId)
Definition Map.h:434
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:554
float GetGridHeight(float x, float y) const
Definition Map.cpp:2522
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:4430
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:4798
GridMap * GetGrid(float x, float y)
Definition Map.cpp:2446
virtual std::string GetDebugInfo() const
Definition Map.cpp:4839
static void DeleteStateMachine()
Definition Map.cpp:264
void SaveRespawnInfoDB(RespawnInfo const &info, CharacterDatabaseTransaction dbTrans=nullptr)
Definition Map.cpp:4493
bool IsSpawnGroupActive(uint32 groupId) const
Definition Map.cpp:3495
MapRefManager::iterator m_mapRefIter
Definition Map.h:683
bool CreatureCellRelocation(Creature *creature, Cell new_cell)
Definition Map.cpp:1406
void LoadCorpseData()
Definition Map.cpp:4558
std::unique_ptr< RespawnListContainer > _respawnTimes
Definition Map.h:813
virtual EnterState CannotEnter(Player *)
Definition Map.h:408
Corpse * GetCorpse(ObjectGuid const &guid)
Definition Map.cpp:4392
time_t GetRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId) const
Definition Map.h:548
void Balance()
Definition Map.h:534
virtual void Update(uint32)
Definition Map.cpp:762
ZoneDynamicInfoMap _zoneDynamicInfo
Definition Map.h:847
virtual ~Map()
Definition Map.cpp:88
DynamicObject * GetDynamicObject(ObjectGuid const &guid)
Definition Map.cpp:4449
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:442
std::set< WorldObject * > i_worldObjects
Definition Map.h:724
ActiveNonPlayers m_activeNonPlayers
Definition Map.h:688
void SaveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, uint32 entry, time_t respawnTime, uint32 gridId, CharacterDatabaseTransaction dbTrans=nullptr, bool startup=false)
Definition Map.cpp:4460
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:4454
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition Map.h:496
bool Instanceable() const
Definition Map.cpp:4226
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:860
void buildNGridLinkage(NGridType *pNGridType)
Definition Map.h:655
MapEntry const * GetEntry() const
Definition Map.h:287
bool IsRegularDifficulty() const
Definition Map.cpp:4221
std::set< WorldObject * > i_objectsToRemove
Definition Map.h:722
bool SpawnGroupDespawn(uint32 groupId, bool deleteRespawnTimes=false, size_t *count=nullptr)
Definition Map.cpp:3458
MapStoredObjectTypesContainer _objectsStore
Definition Map.h:853
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:4823
uint32 GetId() const
Definition Map.cpp:4216
void SendInitTransports(Player *player)
Definition Map.cpp:2966
float m_VisibleDistance
Definition Map.h:679
float GetVisibilityRange() const
Definition Map.h:311
bool IsRaidOrHeroicDungeon() const
Definition Map.cpp:4251
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:508
void RemoveAllObjectsInRemoveList()
Definition Map.cpp:3588
void MoveAllCreaturesInMoveList()
Definition Map.cpp:1264
bool IsGridLoaded(uint32 gridId) const
Definition Map.h:330
Difficulty GetDifficulty() const
Definition Map.h:412
void markCell(uint32 pCellId)
Definition Map.h:435
void VisitNearbyCellsOf(WorldObject *obj, TypeContainerVisitor< Trinity::ObjectUpdater, GridTypeMapContainer > &gridVisitor, TypeContainerVisitor< Trinity::ObjectUpdater, WorldTypeMapContainer > &worldVisitor)
Definition Map.cpp:718
std::mutex _mapLock
Definition Map.h:671
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:492
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:4256
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:647
uint32 GetInstanceId() const
Definition Map.h:387
bool GetEntrancePos(int32 &mapid, float &x, float &y) const
Definition Map.cpp:4282
TransportsContainer _transports
Definition Map.h:693
void SendRemoveTransports(Player *player)
Definition Map.cpp:2982
PlayerList const & GetPlayers() const
Definition Map.h:448
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:814
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:854
void AddObjectToSwitchList(WorldObject *obj, bool on)
Definition Map.cpp:3571
uint32 i_InstanceId
Definition Map.h:676
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:394
@ CANNOT_ENTER_MAX_PLAYERS
Definition Map.h:404
@ CANNOT_ENTER_ZONE_IN_COMBAT
Definition Map.h:405
@ CANNOT_ENTER_ALREADY_IN_MAP
Definition Map.h:396
@ CANNOT_ENTER_INSTANCE_BIND_MISMATCH
Definition Map.h:402
ActiveNonPlayers::iterator m_activeNonPlayersIter
Definition Map.h:689
void RemoveCorpse(Corpse *corpse)
Definition Map.cpp:4614
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:4397
Transport * GetTransport(ObjectGuid const &guid)
Definition Map.cpp:4440
std::map< HighGuid, std::unique_ptr< ObjectGuidGenerator > > _guidGenerators
Definition Map.h:852
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:4416
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:714
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:672
GameObjectBySpawnIdContainer _gameobjectBySpawnIdStore
Definition Map.h:855
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:4272
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
static ObjectGuid const Empty
Definition ObjectGuid.h:140
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:186
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:249
static GameObject * ToGameObject(Object *o)
Definition Object.h:198
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:170
void SetGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:699
virtual void BuildUpdate(UpdateDataMapType &)
Definition Object.h:158
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void BuildOutOfRangeUpdateBlock(UpdateData *data) const
Definition Object.cpp:226
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:585
static DynamicObject * ToDynObject(Object *o)
Definition Object.h:210
Definition Pet.h:40
bool HaveAtClient(Object const *u) const
Definition Player.cpp:22068
uint32 GetTeam() const
Definition Player.h:1832
bool m_InstanceValid
Definition Player.h:2144
float m_homebindZ
Definition Player.h:2089
bool IsBeingTeleportedFar() const
Definition Player.h:1822
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
uint32 m_homebindMapId
Definition Player.h:2085
void SendAurasForTarget(Unit *target, bool force=false) const
Definition Player.cpp:22909
void Update(uint32 time) override
Definition Player.cpp:916
void UpdateZone(uint32 newZone, uint32 newArea)
Definition Player.cpp:6804
GuidUnorderedSet m_clientGUIDs
Definition Player.h:2095
bool IsLoading() const override
Definition Player.cpp:16870
WorldSession * GetSession() const
Definition Player.h:1719
void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const override
Definition Player.cpp:3791
WorldObject * GetViewpoint() const
Definition Player.cpp:24185
float m_homebindY
Definition Player.h:2088
Group * GetGroup()
Definition Player.h:2171
bool IsGameMaster() const
Definition Player.h:998
void SetPendingBind(uint32 instanceId, uint32 bindTimer)
Definition Player.cpp:18700
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:1524
MapReference & GetMapRef()
Definition Player.h:2194
uint32 GetBattlegroundId() const
Definition Player.h:1984
void AddToWorld() override
Definition Player.cpp:1815
void UpdateObjectVisibility(bool forced=true) override
Definition Player.cpp:22297
void SetMap(Map *map) override
Definition Player.cpp:25563
InstancePlayerBind * BindToInstance(InstanceSave *save, bool permanent, BindExtensionState extendState=EXTEND_STATE_NORMAL, bool load=false)
Definition Player.cpp:18618
void RemoveFromWorld() override
Definition Player.cpp:1827
InstancePlayerBind * GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired=false)
Definition Player.cpp:18564
float m_homebindX
Definition Player.h:2087
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:769
bool IsVehicle() const
Definition Unit.h:887
void UpdateObjectVisibility(bool forced=true) override
Definition Unit.cpp:12180
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool IsPet() const
Definition Unit.h:884
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Unit.cpp:9679
bool IsAlive() const
Definition Unit.h:1234
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1260
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5691
CombatManager & GetCombatManager()
Definition Unit.h:1130
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1338
Vehicle * GetVehicleKit() const
Definition Unit.h:1735
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT]
Definition Unit.h:1487
bool IsInCombat() const
Definition Unit.h:1144
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:3417
uint32 GetPhaseMask() const
Definition Object.h:368
Map * GetMap() const
Definition Object.h:449
virtual void ResetMap()
Definition Object.cpp:1826
Map * FindMap() const
Definition Object.h:450
void RemoveFromWorld() override
Definition Object.cpp:1066
float GetGridActivationRange() const
Definition Object.cpp:1476
bool isActiveObject() const
Definition Object.h:551
uint32 GetInstanceId() const
Definition Object.h:365
std::string const & GetName() const
Definition Object.h:382
virtual void SetMap(Map *map)
Definition Object.cpp:1808
void DestroyForNearbyPlayers()
Definition Object.cpp:3449
Transport * GetTransport() const
Definition Object.h:564
void UpdatePositionData()
Definition Object.cpp:1042
bool IsStoredInWorldObjectGridContainer() const
Definition Object.cpp:980
uint32 GetZoneId() const
Definition Object.h:373
bool IsAlwaysStoredInWorldObjectGridContainer() const
Definition Object.h:558
virtual void Update(uint32 diff)
Definition Object.cpp:960
virtual void UpdateObjectVisibility(bool forced=true)
Definition Object.cpp:3482
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition Object.cpp:1031
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:741
static int32 GetVisibilityNotifyPeriodOnContinents()
Definition World.h:745
static float GetMaxVisibleDistanceInBG()
Definition World.h:742
static int32 GetVisibilityNotifyPeriodInArenas()
Definition World.h:748
static int32 GetVisibilityNotifyPeriodInBG()
Definition World.h:747
static int32 GetVisibilityNotifyPeriodInInstances()
Definition World.h:746
static float GetMaxVisibleDistanceOnContinents()
Definition World.h:740
static float GetMaxVisibleDistanceInArenas()
Definition World.h:743
@ SMSG_INSTANCE_LOCK_WARNING_QUERY
Definition Opcodes.h:356
@ SMSG_INSTANCE_SAVE_CREATED
Definition Opcodes.h:744
#define sWorld
Definition World.h:900
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:399
@ CONFIG_INSTANCE_UNLOAD_DELAY
Definition World.h:249
@ CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT
Definition World.h:400
@ CONFIG_RESPAWN_MINCHECKINTERVALMS
Definition World.h:394
@ WEATHER_STATE_FINE
Definition Weather.h:48
@ CONFIG_RESPAWN_DYNAMICRATE_CREATURE
Definition World.h:204
@ CONFIG_RESPAWN_DYNAMICRATE_GAMEOBJECT
Definition World.h:205
@ 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:782
BindExtensionState extendState
Definition Player.h:791
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:263
ObjectGuid::LowType spawnId
Definition Map.h:260
time_t respawnTime
Definition Map.h:262
virtual ~RespawnInfo()
uint32 entry
Definition Map.h:261
SpawnObjectType type
Definition Map.h:259
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:235
WeatherState WeatherId
Definition Map.h:226
std::unique_ptr< Weather > DefaultWeather
Definition Map.h:225
float Intensity
Definition Map.h:227
uint32 fourcc
Definition Map.h:110
uint16 gridArea
Definition Map.h:112
uint16 flags
Definition Map.h:111
u_map_magic mapMagic
Definition Map.h:93
uint32 holesSize
Definition Map.h:103
uint32 liquidMapSize
Definition Map.h:101
uint32 areaMapOffset
Definition Map.h:96
uint32 heightMapSize
Definition Map.h:99
uint32 heightMapOffset
Definition Map.h:98
uint32 holesOffset
Definition Map.h:102
uint32 versionMagic
Definition Map.h:94
uint32 liquidMapOffset
Definition Map.h:100
uint32 areaMapSize
Definition Map.h:97
float gridMaxHeight
Definition Map.h:125
uint32 flags
Definition Map.h:123
float gridHeight
Definition Map.h:124
uint32 fourcc
Definition Map.h:122
uint8 offsetX
Definition Map.h:137
uint32 fourcc
Definition Map.h:133
uint8 liquidFlags
Definition Map.h:135
uint8 width
Definition Map.h:139
uint8 height
Definition Map.h:140
uint8 flags
Definition Map.h:134
uint16 liquidType
Definition Map.h:136
uint8 offsetY
Definition Map.h:138
float liquidLevel
Definition Map.h:141
Represents a map magic value of 4 bytes (used in versions)
Definition Map.h:83
char asChar[4]
Definition Map.h:84
uint32 asUInt
‍Non-null terminated string
Definition Map.h:85