From ee69a569c404594ab52304e78a13682662538470 Mon Sep 17 00:00:00 2001 From: Takenbacon Date: Fri, 14 Feb 2025 13:11:27 -0800 Subject: [PATCH] fix(Core/Grids): Grid improvements (#20955) --- src/common/Collision/Maps/MapDefines.h | 1 + .../game/Achievements/AchievementMgr.cpp | 5 - .../game/Entities/Creature/CreatureGroups.cpp | 1 + .../game/Entities/Item/ItemEnchantmentMgr.cpp | 1 + src/server/game/Entities/Object/Object.cpp | 11 +- .../game/Entities/Transport/Transport.h | 1 + src/server/game/Entities/Unit/Unit.cpp | 2 + src/server/game/Globals/ObjectMgr.cpp | 18 +- src/server/game/Globals/ObjectMgr.h | 4 +- src/server/game/Grids/Cells/Cell.h | 24 +- src/server/game/Grids/Cells/CellImpl.h | 59 +- src/server/game/Grids/Grid.h | 131 -- src/server/game/Grids/GridCell.h | 75 ++ src/server/game/Grids/GridDefines.h | 16 +- src/server/game/Grids/GridLoader.h | 76 -- src/server/game/Grids/GridObjectLoader.cpp | 138 ++ ...{ObjectGridLoader.h => GridObjectLoader.h} | 45 +- src/server/game/Grids/GridTerrainData.cpp | 617 +++++++++ src/server/game/Grids/GridTerrainData.h | 255 ++++ src/server/game/Grids/GridTerrainLoader.cpp | 160 +++ src/server/game/Grids/GridTerrainLoader.h | 59 + src/server/game/Grids/MapGrid.h | 154 +++ src/server/game/Grids/MapGridManager.cpp | 129 ++ src/server/game/Grids/MapGridManager.h | 62 + src/server/game/Grids/NGrid.h | 113 -- .../game/Grids/Notifiers/GridNotifiers.h | 2 +- src/server/game/Grids/ObjectGridLoader.cpp | 245 ---- src/server/game/Handlers/ChatHandler.cpp | 8 +- src/server/game/Loot/LootItemStorage.cpp | 1 + src/server/game/Maps/Map.cpp | 1147 +++-------------- src/server/game/Maps/Map.h | 252 +--- src/server/game/Maps/MapInstanced.cpp | 9 +- src/server/game/Maps/MapMgr.cpp | 11 +- src/server/game/Maps/MapMgr.h | 1 + .../game/Movement/Waypoints/WaypointMgr.cpp | 1 + .../Scripting/ScriptDefines/AllMapScript.cpp | 5 +- src/server/game/Scripting/ScriptMgr.h | 4 +- src/server/game/Scripting/ScriptObject.h | 4 +- src/server/game/Scripting/ScriptObjectFwd.h | 2 +- src/server/game/Spells/Spell.cpp | 4 - src/server/game/World/World.cpp | 2 +- src/server/scripts/Commands/cs_debug.cpp | 17 +- src/server/scripts/Commands/cs_misc.cpp | 9 +- .../Karazhan/boss_nightbane.cpp | 1 - .../Stratholme/instance_stratholme.cpp | 6 - .../SunkenTemple/instance_sunken_temple.cpp | 1 - .../instance_sunwell_plateau.cpp | 2 - .../EasternKingdoms/ZulGurub/boss_hakkar.cpp | 20 - .../Events/firework_show/firework_show.cpp | 1 + .../instance_culling_of_stratholme.cpp | 13 - .../instance_old_hillsbrad.cpp | 16 - .../instance_the_black_morass.cpp | 1 - .../Kalimdor/DireMaul/instance_dire_maul.cpp | 3 - .../RuinsOfAhnQiraj/boss_kurinnaxx.cpp | 3 - .../instance_ruins_of_ahnqiraj.cpp | 1 - .../instance_wailing_caverns.cpp | 2 - .../RubySanctum/instance_ruby_sanctum.cpp | 1 - .../instance_halls_of_reflection.cpp | 3 - .../PitOfSaron/instance_pit_of_saron.cpp | 1 - .../IcecrownCitadel/boss_sindragosa.cpp | 1 - .../IcecrownCitadel/icecrown_citadel.cpp | 2 - .../instance_icecrown_citadel.cpp | 2 - .../Naxxramas/instance_naxxramas.cpp | 4 - .../Ulduar/Ulduar/instance_ulduar.cpp | 6 - .../scripts/OutdoorPvP/OutdoorPvPNA.cpp | 2 +- .../BloodFurnace/boss_kelidan_the_breaker.cpp | 1 - .../instance_shattered_halls.cpp | 1 - 67 files changed, 1952 insertions(+), 2023 deletions(-) delete mode 100644 src/server/game/Grids/Grid.h create mode 100644 src/server/game/Grids/GridCell.h delete mode 100644 src/server/game/Grids/GridLoader.h create mode 100644 src/server/game/Grids/GridObjectLoader.cpp rename src/server/game/Grids/{ObjectGridLoader.h => GridObjectLoader.h} (55%) create mode 100644 src/server/game/Grids/GridTerrainData.cpp create mode 100644 src/server/game/Grids/GridTerrainData.h create mode 100644 src/server/game/Grids/GridTerrainLoader.cpp create mode 100644 src/server/game/Grids/GridTerrainLoader.h create mode 100644 src/server/game/Grids/MapGrid.h create mode 100644 src/server/game/Grids/MapGridManager.cpp create mode 100644 src/server/game/Grids/MapGridManager.h delete mode 100644 src/server/game/Grids/NGrid.h delete mode 100644 src/server/game/Grids/ObjectGridLoader.cpp diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h index 6772a20c7021ec..7f28fc8b2a36f0 100644 --- a/src/common/Collision/Maps/MapDefines.h +++ b/src/common/Collision/Maps/MapDefines.h @@ -22,6 +22,7 @@ #include "DetourNavMesh.h" #define MAX_NUMBER_OF_GRIDS 64 +#define MAX_NUMBER_OF_CELLS 8 #define SIZE_OF_GRIDS 533.3333f #define MMAP_MAGIC 0x4d4d4150 // 'MMAP' diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 03662165614158..404305b785633f 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -751,11 +751,6 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) // if player is in world he can tell his friends about new achievement else if (GetPlayer()->IsInWorld()) { - CellCoord p = Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); - - Cell cell(p); - cell.SetNoCreate(); - Acore::BroadcastTextBuilder _builder(GetPlayer(), CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, GetPlayer()->getGender(), GetPlayer(), achievement->ID); Acore::LocalizedPacketDo _localizer(_builder); Acore::PlayerDistWorker> _worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer); diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 759d38fa178d8e..c4ef53ae60622e 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -22,6 +22,7 @@ #include "MoveSplineInit.h" #include "ObjectMgr.h" #include "QueryResult.h" +#include "Timer.h" #include "WaypointMgr.h" FormationMgr::~FormationMgr() diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index f82d42f8742195..dd781062ea115c 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -21,6 +21,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "QueryResult.h" +#include "Timer.h" #include "Util.h" #include #include diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index fe37ea46c92f95..f790f4297db6ef 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3098,18 +3098,9 @@ void WorldObject::BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& play void WorldObject::GetCreaturesWithEntryInRange(std::list& creatureList, float radius, uint32 entry) { - CellCoord pair(Acore::ComputeCellCoord(this->GetPositionX(), this->GetPositionY())); - Cell cell(pair); - cell.SetNoCreate(); - Acore::AllCreaturesOfEntryInRange check(this, entry, radius); Acore::CreatureListSearcher searcher(this, creatureList, check); - - TypeContainerVisitor, WorldTypeMapContainer> world_visitor(searcher); - cell.Visit(pair, world_visitor, *(this->GetMap()), *this, radius); - - TypeContainerVisitor, GridTypeMapContainer> grid_visitor(searcher); - cell.Visit(pair, grid_visitor, *(this->GetMap()), *this, radius); + Cell::VisitAllObjects(this, searcher, radius); } void WorldObject::AddToObjectUpdate() diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 75fc9f9ee6b507..2387b3b9899e46 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -19,6 +19,7 @@ #define TRANSPORTS_H #include "GameObject.h" +#include "Timer.h" #include "TransportMgr.h" #include "VehicleDefines.h" #include "ZoneScript.h" diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f1fd084122d0e0..43b2568dc1f79d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -20535,6 +20535,8 @@ void Unit::ExecuteDelayedUnitRelocationEvent() } } + GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE); + Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS); relocateNoLarge.SendToSelf(); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index aa39808ce47b94..9b04949b133504 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2341,8 +2341,8 @@ void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const* { if (mask & 1) { - CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()]; + GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY); + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()]; cell_guids.creatures.insert(guid); } } @@ -2355,8 +2355,8 @@ void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData co { if (mask & 1) { - CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()]; + GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY); + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()]; cell_guids.creatures.erase(guid); } } @@ -2454,7 +2454,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 mapId, float x, float y, float AddCreatureToGrid(spawnId, &data); // Spawn if necessary (loaded grids only) - if (!map->Instanceable() && !map->IsRemovalGrid(x, y)) + if (!map->Instanceable() && !map->IsGridCreated(x, y)) { Creature* creature = new Creature(); if (!creature->LoadCreatureFromDB(spawnId, map, true, true)) @@ -2644,8 +2644,8 @@ void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData con { if (mask & 1) { - CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()]; + GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY); + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()]; cell_guids.gameobjects.insert(guid); } } @@ -2658,8 +2658,8 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat { if (mask & 1) { - CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY); - CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()]; + GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY); + CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()]; cell_guids.gameobjects.erase(guid); } } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 3541637b9a44ef..3e1a15f8bf578f 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1150,12 +1150,12 @@ class ObjectMgr return nullptr; } - CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id) + CellObjectGuids const& GetGridObjectGuids(uint16 mapid, uint8 spawnMode, uint32 gridId) { MapObjectGuids::const_iterator itr1 = _mapObjectGuidsStore.find(MAKE_PAIR32(mapid, spawnMode)); if (itr1 != _mapObjectGuidsStore.end()) { - CellObjectGuidsMap::const_iterator itr2 = itr1->second.find(cell_id); + CellObjectGuidsMap::const_iterator itr2 = itr1->second.find(gridId); if (itr2 != itr1->second.end()) return itr2->second; } diff --git a/src/server/game/Grids/Cells/Cell.h b/src/server/game/Grids/Cells/Cell.h index 86ce107b17ba4c..b3c5747a7783de 100644 --- a/src/server/game/Grids/Cells/Cell.h +++ b/src/server/game/Grids/Cells/Cell.h @@ -70,8 +70,6 @@ struct Cell [[nodiscard]] uint32 CellY() const { return data.Part.cell_y; } [[nodiscard]] uint32 GridX() const { return data.Part.grid_x; } [[nodiscard]] uint32 GridY() const { return data.Part.grid_y; } - [[nodiscard]] bool NoCreate() const { return data.Part.nocreate; } - void SetNoCreate() { data.Part.nocreate = 1; } [[nodiscard]] CellCoord GetCellCoord() const { @@ -92,12 +90,10 @@ struct Cell { struct { - unsigned grid_x : 6; - unsigned grid_y : 6; - unsigned cell_x : 6; - unsigned cell_y : 6; - unsigned nocreate : 1; - unsigned reserved : 7; + unsigned grid_x : 8; + unsigned grid_y : 8; + unsigned cell_x : 8; + unsigned cell_y : 8; } Part; uint32 All; } data; @@ -107,13 +103,13 @@ struct Cell static CellArea CalculateCellArea(float x, float y, float radius); - template static void VisitGridObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true); - template static void VisitWorldObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true); - template static void VisitAllObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true); + template static void VisitGridObjects(WorldObject const* obj, T& visitor, float radius); + template static void VisitWorldObjects(WorldObject const* obj, T& visitor, float radius); + template static void VisitAllObjects(WorldObject const* obj, T& visitor, float radius); - template static void VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true); - template static void VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true); - template static void VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true); + template static void VisitGridObjects(float x, float y, Map* map, T& visitor, float radius); + template static void VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius); + template static void VisitAllObjects(float x, float y, Map* map, T& visitor, float radius); private: template void VisitCircle(TypeContainerVisitor&, Map&, CellCoord const&, CellCoord const&) const; diff --git a/src/server/game/Grids/Cells/CellImpl.h b/src/server/game/Grids/Cells/CellImpl.h index f8cf0ed08b56cf..ec6e6e93aa5904 100644 --- a/src/server/game/Grids/Cells/CellImpl.h +++ b/src/server/game/Grids/Cells/CellImpl.h @@ -28,8 +28,6 @@ inline Cell::Cell(CellCoord const& p) data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS; data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS; data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS; - data.Part.nocreate = 0; - data.Part.reserved = 0; } inline Cell::Cell(float x, float y) @@ -39,8 +37,6 @@ inline Cell::Cell(float x, float y) data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS; data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS; data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS; - data.Part.nocreate = 0; - data.Part.reserved = 0; } inline CellArea Cell::CalculateCellArea(float x, float y, float radius) @@ -66,7 +62,8 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor -inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor& visitor, Map& map, float x_off, float y_off, float radius) const{ +inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor& visitor, Map& map, float x_off, float y_off, float radius) const +{ if (!standing_cell.IsCoordValid()) return; @@ -101,23 +98,14 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitordata.Part.nocreate; - map.Visit(r_zone, visitor); - } + Cell r_zone(cellCoord); + map.Visit(r_zone, visitor); } } } @@ -138,7 +126,6 @@ inline void Cell::VisitCircle(TypeContainerVisitor& visitor, Map& { CellCoord cellCoord(x, y); Cell r_zone(cellCoord); - r_zone.data.Part.nocreate = this->data.Part.nocreate; map.Visit(r_zone, visitor); } } @@ -162,55 +149,41 @@ inline void Cell::VisitCircle(TypeContainerVisitor& visitor, Map& //e.g. filling 2 trapezoids after filling central cell strip... CellCoord cellCoord_left(x_start - step, y); Cell r_zone_left(cellCoord_left); - r_zone_left.data.Part.nocreate = this->data.Part.nocreate; map.Visit(r_zone_left, visitor); //right trapezoid cell visit CellCoord cellCoord_right(x_end + step, y); Cell r_zone_right(cellCoord_right); - r_zone_right.data.Part.nocreate = this->data.Part.nocreate; map.Visit(r_zone_right, visitor); } } } template -inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/) +inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius) { CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY())); Cell cell(p); - if (dont_load) - { - cell.SetNoCreate(); - } TypeContainerVisitor gnotifier(visitor); cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius); } template -inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/) +inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius) { CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY())); Cell cell(p); - if (dont_load) - { - cell.SetNoCreate(); - } TypeContainerVisitor wnotifier(visitor); cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius); } template -inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/) +inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius) { CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY())); Cell cell(p); - if (dont_load) - { - cell.SetNoCreate(); - } TypeContainerVisitor wnotifier(visitor); cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius); @@ -219,42 +192,30 @@ inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, flo } template -inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/) +inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius) { CellCoord p(Acore::ComputeCellCoord(x, y)); Cell cell(p); - if (dont_load) - { - cell.SetNoCreate(); - } TypeContainerVisitor gnotifier(visitor); cell.Visit(p, gnotifier, *map, x, y, radius); } template -inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/) +inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius) { CellCoord p(Acore::ComputeCellCoord(x, y)); Cell cell(p); - if (dont_load) - { - cell.SetNoCreate(); - } TypeContainerVisitor wnotifier(visitor); cell.Visit(p, wnotifier, *map, x, y, radius); } template -inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/) +inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius) { CellCoord p(Acore::ComputeCellCoord(x, y)); Cell cell(p); - if (dont_load) - { - cell.SetNoCreate(); - } TypeContainerVisitor wnotifier(visitor); cell.Visit(p, wnotifier, *map, x, y, radius); diff --git a/src/server/game/Grids/Grid.h b/src/server/game/Grids/Grid.h deleted file mode 100644 index b9cafdbe0cd487..00000000000000 --- a/src/server/game/Grids/Grid.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef ACORE_GRID_H -#define ACORE_GRID_H - -/* - @class Grid - Grid is a logical segment of the game world represented inside TrinIty. - Grid is bind at compile time to a particular type of object which - we call it the object of interested. There are many types of loader, - specially, dynamic loader, static loader, or on-demand loader. There's - a subtle difference between dynamic loader and on-demand loader but - this is implementation specific to the loader class. From the - Grid's perspective, the loader meets its API requirement is suffice. -*/ - -#include "Define.h" -#include "TypeContainer.h" -#include "TypeContainerVisitor.h" - -// forward declaration -template class GridLoader; - -template -< - class ACTIVE_OBJECT, - class WORLD_OBJECT_TYPES, - class GRID_OBJECT_TYPES - > -class Grid -{ - // allows the GridLoader to access its internals - template friend class GridLoader; -public: - /** destructor to clean up its resources. This includes unloading the - grid if it has not been unload. - */ - ~Grid() = default; - - /** an object of interested enters the grid - */ - template void AddWorldObject(SPECIFIC_OBJECT* obj) - { - i_objects.template insert(obj); - ASSERT(obj->IsInGrid()); - } - - /** an object of interested exits the grid - */ - //Actually an unlink is enough, no need to go through the container - //template void RemoveWorldObject(SPECIFIC_OBJECT *obj) - //{ - // ASSERT(obj->GetGridRef().isValid()); - // i_objects.template remove(obj); - // ASSERT(!obj->GetGridRef().isValid()); - //} - - /** Refreshes/update the grid. This required for remote grids. - */ - //void RefreshGrid(void) { /* TBI */} - - /** Locks a grid. Any object enters must wait until the grid is unlock. - */ - //void LockGrid(void) { /* TBI */ } - - /** Unlocks the grid. - */ - //void UnlockGrid(void) { /* TBI */ } - - // Visit grid objects - template - void Visit(TypeContainerVisitor >& visitor) - { - visitor.Visit(i_container); - } - - // Visit world objects - template - void Visit(TypeContainerVisitor >& visitor) - { - visitor.Visit(i_objects); - } - - /** Inserts a container type object into the grid. - */ - template void AddGridObject(SPECIFIC_OBJECT* obj) - { - i_container.template insert(obj); - ASSERT(obj->IsInGrid()); - } - - /** Removes a containter type object from the grid - */ - //template void RemoveGridObject(SPECIFIC_OBJECT *obj) - //{ - // ASSERT(obj->GetGridRef().isValid()); - // i_container.template remove(obj); - // ASSERT(!obj->GetGridRef().isValid()); - //} - - /*bool NoWorldObjectInGrid() const - { - return i_objects.GetElements().IsEmpty(); - } - - bool NoGridObjectInGrid() const - { - return i_container.GetElements().IsEmpty(); - }*/ -private: - TypeMapContainer i_container; - TypeMapContainer i_objects; - //typedef std::set ActiveGridObjects; - //ActiveGridObjects m_activeGridObjects; -}; -#endif diff --git a/src/server/game/Grids/GridCell.h b/src/server/game/Grids/GridCell.h new file mode 100644 index 00000000000000..c0ccfdbba1d10d --- /dev/null +++ b/src/server/game/Grids/GridCell.h @@ -0,0 +1,75 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef ACORE_GRID_CELL_H +#define ACORE_GRID_CELL_H + +/* + @class GridCell + Grid is a logical segment of the game world represented inside TrinIty. + Grid is bind at compile time to a particular type of object which + we call it the object of interested. There are many types of loader, + specially, dynamic loader, static loader, or on-demand loader. There's + a subtle difference between dynamic loader and on-demand loader but + this is implementation specific to the loader class. From the + Grid's perspective, the loader meets its API requirement is suffice. +*/ + +#include "Define.h" +#include "TypeContainer.h" +#include "TypeContainerVisitor.h" + +template +< + class WORLD_OBJECT_TYPES, + class GRID_OBJECT_TYPES +> +class GridCell +{ +public: + ~GridCell() = default; + + template void AddWorldObject(SPECIFIC_OBJECT* obj) + { + _worldObjects.template insert(obj); + ASSERT(obj->IsInGrid()); + } + + template void AddGridObject(SPECIFIC_OBJECT* obj) + { + _gridObjects.template insert(obj); + ASSERT(obj->IsInGrid()); + } + + // Visit grid objects + template + void Visit(TypeContainerVisitor >& visitor) + { + visitor.Visit(_gridObjects); + } + + // Visit world objects + template + void Visit(TypeContainerVisitor >& visitor) + { + visitor.Visit(_worldObjects); + } +private: + TypeMapContainer _gridObjects; + TypeMapContainer _worldObjects; +}; +#endif diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 0e72af22e26fd7..62d1a6f500f0bd 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -20,7 +20,8 @@ #include "Common.h" #include "MapDefines.h" -#include "NGrid.h" +#include "GridCell.h" +#include "MapGrid.h" // Forward class definitions class Corpse; @@ -31,8 +32,6 @@ class Pet; class Player; class ObjectGuid; -#define MAX_NUMBER_OF_CELLS 8 - #define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2) #define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2) @@ -73,8 +72,8 @@ enum GridMapTypeMask GRID_MAP_TYPE_MASK_ALL = 0x1F }; -typedef Grid GridType; -typedef NGrid NGridType; +typedef GridCell GridCellType; +typedef MapGrid MapGridType; typedef TypeMapContainer GridTypeMapContainer; typedef TypeMapContainer WorldTypeMapContainer; @@ -187,6 +186,13 @@ namespace Acore return Compute(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS); } + inline GridCoord ComputeGridCoordSimple(float x, float y) + { + int gx = (int)(CENTER_GRID_ID - x / SIZE_OF_GRIDS); + int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS); + return GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy); + } + inline CellCoord ComputeCellCoord(float x, float y) { return Compute(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL); diff --git a/src/server/game/Grids/GridLoader.h b/src/server/game/Grids/GridLoader.h deleted file mode 100644 index 00081281c8a040..00000000000000 --- a/src/server/game/Grids/GridLoader.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef ACORE_GRIDLOADER_H -#define ACORE_GRIDLOADER_H - -/** - @class GridLoader - The GridLoader is working in conjuction with the Grid and responsible - for loading and unloading object-types (one or more) when objects - enters a grid. Unloading is scheduled and might be canceled if - an interested object re-enters. GridLoader does not do the actuall - loading and unloading but implements as a template pattern that - delicate its loading and unloading for the actualy loader and unloader. - GridLoader manages the grid (both local and remote). - */ - -//I cannot see why this cannot be replaced by a Grid::Visit -/* -#include "Define.h" -#include "Grid.h" -#include "TypeContainerVisitor.h" - -template -< -class ACTIVE_OBJECT, -class WORLD_OBJECT_TYPES, -class GRID_OBJECT_TYPES -> -class GridLoader -{ - public: - - // Loads the grid - template - void Load(Grid &grid, LOADER &loader) - { - grid.LockGrid(); - loader.Load(grid); - grid.UnlockGrid(); - } - - // Stop the grid - template - void Stop(Grid &grid, STOPER &stoper) - { - grid.LockGrid(); - stoper.Stop(grid); - grid.UnlockGrid(); - } - - // Unloads the grid - template - void Unload(Grid &grid, UNLOADER &unloader) - { - grid.LockGrid(); - unloader.Unload(grid); - grid.UnlockGrid(); - } -}; -*/ -#endif diff --git a/src/server/game/Grids/GridObjectLoader.cpp b/src/server/game/Grids/GridObjectLoader.cpp new file mode 100644 index 00000000000000..09550ab9061702 --- /dev/null +++ b/src/server/game/Grids/GridObjectLoader.cpp @@ -0,0 +1,138 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "GridObjectLoader.h" +#include "CellImpl.h" +#include "Corpse.h" +#include "Creature.h" +#include "DynamicObject.h" +#include "GameObject.h" +#include "GridNotifiers.h" +#include "Transport.h" + +template +void GridObjectLoader::AddObjectHelper(Map* map, T* obj) +{ + CellCoord cellCoord = Acore::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY()); + Cell cell(cellCoord); + + map->AddToGrid(obj, cell); + obj->AddToWorld(); + if (obj->isActiveObject()) + map->AddToActive(obj); +} + +void GridObjectLoader::LoadCreatures(CellGuidSet const& guid_set, Map* map) +{ + for (ObjectGuid::LowType const& guid : guid_set) + { + Creature* obj = new Creature(); + if (!obj->LoadFromDB(guid, map)) + { + delete obj; + continue; + } + + AddObjectHelper(map, obj); + + if (!obj->IsMoveInLineOfSightDisabled() && obj->GetDefaultMovementType() == IDLE_MOTION_TYPE && !obj->isNeedNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION)) + { + if (obj->IsAlive() && !obj->HasUnitState(UNIT_STATE_SIGHTLESS) && obj->HasReactState(REACT_AGGRESSIVE) && !obj->IsImmuneToNPC()) + { + // call MoveInLineOfSight for nearby grid creatures + Acore::AIRelocationNotifier notifier(*obj); + Cell::VisitGridObjects(obj, notifier, 60.f); + } + } + } +} + +void GridObjectLoader::LoadGameObjects(CellGuidSet const& guid_set, Map* map) +{ + for (ObjectGuid::LowType const& guid : guid_set) + { + GameObjectData const* data = sObjectMgr->GetGameObjectData(guid); + GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject(); + + if (!obj->LoadFromDB(guid, map)) + { + delete obj; + continue; + } + + AddObjectHelper(map, obj); + } +} + +void GridObjectLoader::LoadAllCellsInGrid() +{ + CellObjectGuids const& cell_guids = sObjectMgr->GetGridObjectGuids(_map->GetId(), _map->GetSpawnMode(), _grid.GetId()); + LoadGameObjects(cell_guids.gameobjects, _map); + LoadCreatures(cell_guids.creatures, _map); + + if (std::unordered_set const* corpses = _map->GetCorpsesInCell(_grid.GetId())) + { + for (Corpse* corpse : *corpses) + { + if (corpse->IsInGrid()) + continue; + + CellCoord cellCoord = Acore::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY()); + Cell cell(cellCoord); + + if (corpse->IsWorldObject()) + _grid.AddWorldObject(cell.CellX(), cell.CellY(), corpse); + else + _grid.AddGridObject(cell.CellX(), cell.CellY(), corpse); + } + } +} + +template +void GridObjectUnloader::Visit(GridRefMgr& m) +{ + while (!m.IsEmpty()) + { + T* obj = m.getFirst()->GetSource(); + // if option set then object already saved at this moment + //if (!sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) + // obj->SaveRespawnTime(); + //Some creatures may summon other temp summons in CleanupsBeforeDelete() + //So we need this even after cleaner (maybe we can remove cleaner) + //Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted + //TODO: Check if that script has the correct logic. Do we really need to summons something before deleting? + obj->CleanupsBeforeDelete(); + ///- object will get delinked from the manager when deleted + delete obj; + } +} + +template +void GridObjectCleaner::Visit(GridRefMgr& m) +{ + for (typename GridRefMgr::iterator iter = m.begin(); iter != m.end(); ++iter) + iter->GetSource()->CleanupsBeforeDelete(); +} + +template void GridObjectUnloader::Visit(CreatureMapType&); +template void GridObjectUnloader::Visit(GameObjectMapType&); +template void GridObjectUnloader::Visit(DynamicObjectMapType&); + +template void GridObjectCleaner::Visit(CreatureMapType&); +template void GridObjectCleaner::Visit(GameObjectMapType&); +template void GridObjectCleaner::Visit(DynamicObjectMapType&); +template void GridObjectCleaner::Visit(CorpseMapType&); diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/GridObjectLoader.h similarity index 55% rename from src/server/game/Grids/ObjectGridLoader.h rename to src/server/game/Grids/GridObjectLoader.h index d6029ac7bfcb3f..101f489bfb4a71 100644 --- a/src/server/game/Grids/ObjectGridLoader.h +++ b/src/server/game/Grids/GridObjectLoader.h @@ -15,51 +15,42 @@ * with this program. If not, see . */ -#ifndef ACORE_OBJECTGRIDLOADER_H -#define ACORE_OBJECTGRIDLOADER_H +#ifndef ACORE_GRID_OBJECT_LOADER_H +#define ACORE_GRID_OBJECT_LOADER_H #include "Cell.h" #include "Define.h" #include "GridDefines.h" +#include "ObjectMgr.h" -class ObjectWorldLoader; - -class ObjectGridLoader +class GridObjectLoader { - friend class ObjectWorldLoader; - public: - ObjectGridLoader(NGridType& grid, Map* map, const Cell& cell) - : i_cell(cell), i_grid(grid), i_map(map), i_gameObjects(0), i_creatures(0), i_corpses (0) - {} + GridObjectLoader(MapGridType& grid, Map* map) + : _grid(grid), _map(map) { } - void Visit(GameObjectMapType& m); - void Visit(CreatureMapType& m); - void Visit(CorpseMapType&) const {} - void Visit(DynamicObjectMapType&) const {} + void LoadAllCellsInGrid(); - void LoadN(void); +private: + template + void AddObjectHelper(Map* map, T* obj); - template static void SetObjectCell(T* obj, CellCoord const& cellCoord); + void LoadCreatures(CellGuidSet const& guid_set, Map* map); + void LoadGameObjects(CellGuidSet const& guid_set, Map* map); -private: - Cell i_cell; - NGridType& i_grid; - Map* i_map; - uint32 i_gameObjects; - uint32 i_creatures; - uint32 i_corpses; + MapGridType& _grid; + Map* _map; }; -//Clean up and remove from world -class ObjectGridCleaner +// Clean up and remove from world +class GridObjectCleaner { public: template void Visit(GridRefMgr&); }; -//Delete objects before deleting NGrid -class ObjectGridUnloader +// Delete objects before deleting NGrid +class GridObjectUnloader { public: void Visit(CorpseMapType&) { } // corpses are deleted with Map diff --git a/src/server/game/Grids/GridTerrainData.cpp b/src/server/game/Grids/GridTerrainData.cpp new file mode 100644 index 00000000000000..e2439dc2e5f1d7 --- /dev/null +++ b/src/server/game/Grids/GridTerrainData.cpp @@ -0,0 +1,617 @@ +#include "DBCStores.h" +#include "GridDefines.h" +#include "GridTerrainData.h" +#include "Log.h" +#include "MapDefines.h" +#include +#include + +uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 }; +uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 }; + +GridTerrainData::GridTerrainData() +{ + _gridGetHeight = &GridTerrainData::getHeightFromFlat; +} + +TerrainMapDataReadResult GridTerrainData::Load(std::string const& mapFileName) +{ + // Check if file exists, we do this first as we need to + // differentiate between file existing and any other file errors + if (!std::filesystem::exists(mapFileName)) + return TerrainMapDataReadResult::NotFound; + + // Start the input stream and check for any errors + std::ifstream fileStream(mapFileName, std::ios::binary); + if (fileStream.fail()) + return TerrainMapDataReadResult::ReadError; + + // Read the map header + map_fileheader header; + if (!fileStream.read(reinterpret_cast(&header), sizeof(header))) + return TerrainMapDataReadResult::ReadError; + + // Check for valid map and version magics + if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic) + return TerrainMapDataReadResult::InvalidMagic; + + // Load area data + if (header.areaMapOffset && !LoadAreaData(fileStream, header.areaMapOffset)) + return TerrainMapDataReadResult::InvalidAreaData; + + // Load height data + if (header.heightMapOffset && !LoadHeightData(fileStream, header.heightMapOffset)) + return TerrainMapDataReadResult::InvalidHeightData; + + // Load liquid data + if (header.liquidMapOffset && !LoadLiquidData(fileStream, header.liquidMapOffset)) + return TerrainMapDataReadResult::InvalidLiquidData; + + // Load hole data + if (header.holesSize && !LoadHolesData(fileStream, header.holesOffset)) + return TerrainMapDataReadResult::InvalidHoleData; + + return TerrainMapDataReadResult::Success; +} + +bool GridTerrainData::LoadAreaData(std::ifstream& fileStream, uint32 const offset) +{ + fileStream.seekg(offset); + + map_areaHeader header; + if (!fileStream.read(reinterpret_cast(&header), sizeof(header)) || header.fourcc != MapAreaMagic.asUInt) + return false; + + _loadedAreaData = std::make_unique(); + _loadedAreaData->gridArea = header.gridArea; + if (!(header.flags & MAP_AREA_NO_AREA)) + { + _loadedAreaData->areaMap = std::make_unique(); + if (!fileStream.read(reinterpret_cast(_loadedAreaData->areaMap.get()), sizeof(LoadedAreaData::AreaMapType))) + return false; + } + return true; +} + +bool GridTerrainData::LoadHeightData(std::ifstream& fileStream, uint32 const offset) +{ + fileStream.seekg(offset); + + map_heightHeader header; + if (!fileStream.read(reinterpret_cast(&header), sizeof(header)) || header.fourcc != MapHeightMagic.asUInt) + return false; + + _loadedHeightData = std::make_unique(); + _loadedHeightData->gridHeight = header.gridHeight; + if (!(header.flags & MAP_HEIGHT_NO_HEIGHT)) + { + if ((header.flags & MAP_HEIGHT_AS_INT16)) + { + _loadedHeightData->uint16HeightData = std::make_unique(); + if (!fileStream.read(reinterpret_cast(&_loadedHeightData->uint16HeightData->v9), sizeof(_loadedHeightData->uint16HeightData->v9)) + || !fileStream.read(reinterpret_cast(&_loadedHeightData->uint16HeightData->v8), sizeof(_loadedHeightData->uint16HeightData->v8))) + return false; + + _loadedHeightData->uint16HeightData->gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; + _gridGetHeight = &GridTerrainData::getHeightFromUint16; + } + else if ((header.flags & MAP_HEIGHT_AS_INT8)) + { + _loadedHeightData->uint8HeightData = std::make_unique(); + if (!fileStream.read(reinterpret_cast(&_loadedHeightData->uint8HeightData->v9), sizeof(_loadedHeightData->uint8HeightData->v9)) + || !fileStream.read(reinterpret_cast(&_loadedHeightData->uint8HeightData->v8), sizeof(_loadedHeightData->uint8HeightData->v8))) + return false; + + _loadedHeightData->uint8HeightData->gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255; + _gridGetHeight = &GridTerrainData::getHeightFromUint8; + } + else + { + _loadedHeightData->floatHeightData = std::make_unique(); + if (!fileStream.read(reinterpret_cast(&_loadedHeightData->floatHeightData->v9), sizeof(_loadedHeightData->floatHeightData->v9)) + || !fileStream.read(reinterpret_cast(&_loadedHeightData->floatHeightData->v8), sizeof(_loadedHeightData->floatHeightData->v8))) + return false; + + _gridGetHeight = &GridTerrainData::getHeightFromFloat; + } + } + else + _gridGetHeight = &GridTerrainData::getHeightFromFlat; + + if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + std::array maxHeights; + std::array minHeights; + if (!fileStream.read(reinterpret_cast(maxHeights.data()), sizeof(maxHeights)) || + !fileStream.read(reinterpret_cast(minHeights.data()), sizeof(minHeights))) + return false; + + static uint32 constexpr indices[8][3] = + { + { 3, 0, 4 }, + { 0, 1, 4 }, + { 1, 2, 4 }, + { 2, 5, 4 }, + { 5, 8, 4 }, + { 8, 7, 4 }, + { 7, 6, 4 }, + { 6, 3, 4 } + }; + + static float constexpr boundGridCoords[9][2] = + { + { 0.0f, 0.0f }, + { 0.0f, -266.66666f }, + { 0.0f, -533.33331f }, + { -266.66666f, 0.0f }, + { -266.66666f, -266.66666f }, + { -266.66666f, -533.33331f }, + { -533.33331f, 0.0f }, + { -533.33331f, -266.66666f }, + { -533.33331f, -533.33331f } + }; + + _loadedHeightData->minHeightPlanes = std::make_unique(); + for (uint32 quarterIndex = 0; quarterIndex < _loadedHeightData->minHeightPlanes->size(); ++quarterIndex) + _loadedHeightData->minHeightPlanes->at(quarterIndex) = G3D::Plane( + G3D::Vector3(boundGridCoords[indices[quarterIndex][0]][0], boundGridCoords[indices[quarterIndex][0]][1], minHeights[indices[quarterIndex][0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex][1]][0], boundGridCoords[indices[quarterIndex][1]][1], minHeights[indices[quarterIndex][1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex][2]][0], boundGridCoords[indices[quarterIndex][2]][1], minHeights[indices[quarterIndex][2]]) + ); + } + + return true; +} + +bool GridTerrainData::LoadLiquidData(std::ifstream& fileStream, uint32 const offset) +{ + fileStream.seekg(offset); + + map_liquidHeader header; + if (!fileStream.read(reinterpret_cast(&header), sizeof(header)) || header.fourcc != MapLiquidMagic.asUInt) + return false; + + _loadedLiquidData = std::make_unique(); + _loadedLiquidData->liquidGlobalEntry = header.liquidType; + _loadedLiquidData->liquidGlobalFlags = header.liquidFlags; + _loadedLiquidData->liquidOffX = header.offsetX; + _loadedLiquidData->liquidOffY = header.offsetY; + _loadedLiquidData->liquidWidth = header.width; + _loadedLiquidData->liquidHeight = header.height; + _loadedLiquidData->liquidLevel = header.liquidLevel; + + if (!(header.flags & MAP_LIQUID_NO_TYPE)) + { + _loadedLiquidData->liquidEntry = std::make_unique(); + if (!fileStream.read(reinterpret_cast(_loadedLiquidData->liquidEntry.get()), sizeof(LoadedLiquidData::LiquidEntryType))) + return false; + + _loadedLiquidData->liquidFlags = std::make_unique(); + if (!fileStream.read(reinterpret_cast(_loadedLiquidData->liquidFlags.get()), sizeof(LoadedLiquidData::LiquidFlagsType))) + return false; + } + if (!(header.flags & MAP_LIQUID_NO_HEIGHT)) + { + _loadedLiquidData->liquidMap = std::make_unique(); + _loadedLiquidData->liquidMap->resize(_loadedLiquidData->liquidWidth * _loadedLiquidData->liquidHeight); + if (!fileStream.read(reinterpret_cast(_loadedLiquidData->liquidMap->data()), _loadedLiquidData->liquidMap->size() * sizeof(float))) + return false; + } + return true; +} + +bool GridTerrainData::LoadHolesData(std::ifstream& fileStream, uint32 const offset) +{ + fileStream.seekg(offset); + + _loadedHoleData = std::make_unique(); + if (!fileStream.read(reinterpret_cast(&_loadedHoleData->holes), sizeof(_loadedHoleData->holes))) + return false; + + return true; +} + +uint16 GridTerrainData::getArea(float x, float y) const +{ + if (!_loadedAreaData) + return 0; + + if (!_loadedAreaData->areaMap) + return _loadedAreaData->gridArea; + + x = 16 * (32 - x / SIZE_OF_GRIDS); + y = 16 * (32 - y / SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return _loadedAreaData->areaMap->at(lx * 16 + ly); +} + +float GridTerrainData::getHeightFromFlat(float /*x*/, float /*y*/) const +{ + if (!_loadedHeightData) + return INVALID_HEIGHT; + + return _loadedHeightData->gridHeight; +} + +float GridTerrainData::getHeightFromFloat(float x, float y) const +{ + if (!_loadedHeightData || !_loadedHeightData->floatHeightData) + return INVALID_HEIGHT; + + x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int &= (MAP_RESOLUTION - 1); + y_int &= (MAP_RESOLUTION - 1); + + if (isHole(x_int, y_int)) + return INVALID_HEIGHT; + + // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid + // +--------------> X + // | h1-------h2 Coordinates is: + // | | \ 1 / | h1 0, 0 + // | | \ / | h2 0, 1 + // | | 2 h5 3 | h3 1, 0 + // | | / \ | h4 1, 1 + // | | / 4 \ | h5 1/2, 1/2 + // | h3-------h4 + // V Y + // For find height need + // 1 - detect triangle + // 2 - solve linear equation from triangle points + // Calculate coefficients for solve h = a*x + b*y + c + + float a, b, c; + // Select triangle: + if (x + y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + float h1 = _loadedHeightData->floatHeightData->v9[(x_int) * 129 + y_int]; + float h2 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int]; + float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int]; + a = h2 - h1; + b = h5 - h1 - h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + float h1 = _loadedHeightData->floatHeightData->v9[x_int * 129 + y_int]; + float h3 = _loadedHeightData->floatHeightData->v9[x_int * 129 + y_int + 1]; + float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + float h2 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int]; + float h4 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int + 1]; + float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + float h3 = _loadedHeightData->floatHeightData->v9[(x_int) * 129 + y_int + 1]; + float h4 = _loadedHeightData->floatHeightData->v9[(x_int + 1) * 129 + y_int + 1]; + float h5 = 2 * _loadedHeightData->floatHeightData->v8[x_int * 128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return a * x + b * y + c; +} + +float GridTerrainData::getHeightFromUint8(float x, float y) const +{ + if (!_loadedHeightData || !_loadedHeightData->uint8HeightData) + return INVALID_HEIGHT; + + x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int &= (MAP_RESOLUTION - 1); + y_int &= (MAP_RESOLUTION - 1); + + if (isHole(x_int, y_int)) + return INVALID_HEIGHT; + + int32 a, b, c; + uint8* V9_h1_ptr = &_loadedHeightData->uint8HeightData->v9[x_int * 128 + x_int + y_int]; + if (x + y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h2 = V9_h1_ptr[129]; + int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int]; + a = h2 - h1; + b = h5 - h1 - h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h3 = V9_h1_ptr[1]; + int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + int32 h2 = V9_h1_ptr[129]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + int32 h3 = V9_h1_ptr[1]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * _loadedHeightData->uint8HeightData->v8[x_int * 128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return (float)((a * x) + (b * y) + c) * _loadedHeightData->uint8HeightData->gridIntHeightMultiplier + _loadedHeightData->gridHeight; +} + +float GridTerrainData::getHeightFromUint16(float x, float y) const +{ + if (!_loadedHeightData || !_loadedHeightData->uint16HeightData) + return INVALID_HEIGHT; + + x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int &= (MAP_RESOLUTION - 1); + y_int &= (MAP_RESOLUTION - 1); + + if (isHole(x_int, y_int)) + return INVALID_HEIGHT; + + int32 a, b, c; + uint16* V9_h1_ptr = &_loadedHeightData->uint16HeightData->v9[x_int * 128 + x_int + y_int]; + if (x + y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h2 = V9_h1_ptr[129]; + int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int]; + a = h2 - h1; + b = h5 - h1 - h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h3 = V9_h1_ptr[1]; + int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + int32 h2 = V9_h1_ptr[129]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + int32 h3 = V9_h1_ptr[1]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * _loadedHeightData->uint16HeightData->v8[x_int * 128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return (float)((a * x) + (b * y) + c) * _loadedHeightData->uint16HeightData->gridIntHeightMultiplier + _loadedHeightData->gridHeight; +} + +bool GridTerrainData::isHole(int row, int col) const +{ + if (!_loadedHoleData) + return false; + + int cellRow = row / 8; // 8 squares per cell + int cellCol = col / 8; + int holeRow = row % 8 / 2; + int holeCol = (col - (cellCol * 8)) / 2; + + uint16 hole = _loadedHoleData->holes[cellRow * 16 + cellCol]; + + return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0; +} + +float GridTerrainData::getMinHeight(float x, float y) const +{ + if (!_loadedHeightData || !_loadedHeightData->minHeightPlanes) + return MIN_HEIGHT; + + GridCoord gridCoord = Acore::ComputeGridCoordSimple(x, y); + + int32 doubleGridX = int32(std::floor(-(x - MAP_HALFSIZE) / CENTER_GRID_OFFSET)); + int32 doubleGridY = int32(std::floor(-(y - MAP_HALFSIZE) / CENTER_GRID_OFFSET)); + + float gx = x - (int32(gridCoord.x_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + float gy = y - (int32(gridCoord.y_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + + uint32 quarterIndex = 0; + if (doubleGridY & 1) + { + if (doubleGridX & 1) + quarterIndex = 4 + (gx <= gy); + else + quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy); + } + else if (doubleGridX & 1) + quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy); + else + quarterIndex = gx > gy; + + G3D::Ray ray = G3D::Ray::fromOriginAndDirection(G3D::Vector3(gx, gy, 0.0f), G3D::Vector3::unitZ()); + return ray.intersection(_loadedHeightData->minHeightPlanes->at(quarterIndex)).z; +} + +float GridTerrainData::getLiquidLevel(float x, float y) const +{ + if (!_loadedLiquidData) + return INVALID_HEIGHT; + + if (!_loadedLiquidData->liquidMap) + return _loadedLiquidData->liquidLevel; + + x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); + + int cx_int = ((int)x & (MAP_RESOLUTION - 1)) - _loadedLiquidData->liquidOffY; + int cy_int = ((int)y & (MAP_RESOLUTION - 1)) - _loadedLiquidData->liquidOffX; + + if (cx_int < 0 || cx_int >= _loadedLiquidData->liquidHeight) + return INVALID_HEIGHT; + if (cy_int < 0 || cy_int >= _loadedLiquidData->liquidWidth) + return INVALID_HEIGHT; + + return _loadedLiquidData->liquidMap->at(cx_int * _loadedLiquidData->liquidWidth + cy_int); +} + +// Get water state on map +LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const +{ + LiquidData liquidData; + if (!_loadedLiquidData) + return liquidData; + + // Check water type (if no water return) + if (_loadedLiquidData->liquidGlobalFlags || _loadedLiquidData->liquidFlags) + { + // Get cell + float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); + float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); + + int x_int = (int)cx & (MAP_RESOLUTION - 1); + int y_int = (int)cy & (MAP_RESOLUTION - 1); + + // Check water type in cell + int idx = (x_int >> 3) * 16 + (y_int >> 3); + uint8 type = _loadedLiquidData->liquidFlags ? _loadedLiquidData->liquidFlags->at(idx) : _loadedLiquidData->liquidGlobalFlags; + uint32 entry = _loadedLiquidData->liquidEntry ? _loadedLiquidData->liquidEntry->at(idx) : _loadedLiquidData->liquidGlobalEntry; + if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry)) + { + type &= MAP_LIQUID_TYPE_DARK_WATER; + uint32 liqTypeIdx = liquidEntry->Type; + if (entry < 21) + { + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) + { + uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; + if (!overrideLiquid && area->zone) + { + area = sAreaTableStore.LookupEntry(area->zone); + if (area) + overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; + } + + if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) + { + entry = overrideLiquid; + liqTypeIdx = liq->Type; + } + } + } + + type |= 1 << liqTypeIdx; + } + + // Check req liquid type mask + if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0)) + { + // Check water level: + // Check water height map + int lx_int = x_int - _loadedLiquidData->liquidOffY; + int ly_int = y_int - _loadedLiquidData->liquidOffX; + if (lx_int >= 0 && lx_int < _loadedLiquidData->liquidHeight && ly_int >= 0 && ly_int < _loadedLiquidData->liquidWidth) + { + // Get water level + float liquid_level = _loadedLiquidData->liquidMap ? _loadedLiquidData->liquidMap->at(lx_int * _loadedLiquidData->liquidWidth + ly_int) : _loadedLiquidData->liquidLevel; + // Get ground level + float ground_level = getHeight(x, y); + + // Check water level and ground level (sub 0.2 for fix some errors) + if (liquid_level >= ground_level && z >= ground_level - 0.2f) + { + // All ok in water -> store data + liquidData.Entry = entry; + liquidData.Flags = type; + liquidData.Level = liquid_level; + liquidData.DepthLevel = ground_level; + + // For speed check as int values + float delta = liquid_level - z; + + if (delta > collisionHeight) + liquidData.Status = LIQUID_MAP_UNDER_WATER; + else if (delta > 0.0f) + liquidData.Status = LIQUID_MAP_IN_WATER; + else if (delta > -0.1f) + liquidData.Status = LIQUID_MAP_WATER_WALK; + else + liquidData.Status = LIQUID_MAP_ABOVE_WATER; + } + } + } + } + + return liquidData; +} diff --git a/src/server/game/Grids/GridTerrainData.h b/src/server/game/Grids/GridTerrainData.h new file mode 100644 index 00000000000000..6d6b898252f635 --- /dev/null +++ b/src/server/game/Grids/GridTerrainData.h @@ -0,0 +1,255 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef GRID_TERRAIN_DATA_H +#define GRID_TERRAIN_DATA_H + +#include "Common.h" +#include +#include +#include + +#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface +#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE +#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT +#define MIN_HEIGHT -500.0f + +#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER) +#define MAP_LIQUID_STATUS_IN_CONTACT (MAP_LIQUID_STATUS_SWIMMING | LIQUID_MAP_WATER_WALK) + +#define MAP_LIQUID_TYPE_NO_WATER 0x00 +#define MAP_LIQUID_TYPE_WATER 0x01 +#define MAP_LIQUID_TYPE_OCEAN 0x02 +#define MAP_LIQUID_TYPE_MAGMA 0x04 +#define MAP_LIQUID_TYPE_SLIME 0x08 + +#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME) + +#define MAP_LIQUID_TYPE_DARK_WATER 0x10 + +// ****************************************** +// Map file format defines +// ****************************************** +union u_map_magic +{ + char asChar[4]; + uint32 asUInt; +}; + +const u_map_magic MapMagic = { {'M', 'A', 'P', 'S'} }; +const uint32 MapVersionMagic = 9; +const u_map_magic MapAreaMagic = { {'A', 'R', 'E', 'A'} }; +const u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} }; +const u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} }; + +struct map_fileheader +{ + uint32 mapMagic; + uint32 versionMagic; + uint32 buildMagic; + uint32 areaMapOffset; + uint32 areaMapSize; + uint32 heightMapOffset; + uint32 heightMapSize; + uint32 liquidMapOffset; + uint32 liquidMapSize; + uint32 holesOffset; + uint32 holesSize; +}; + +#define MAP_AREA_NO_AREA 0x0001 + +struct map_areaHeader +{ + uint32 fourcc; + uint16 flags; + uint16 gridArea; +}; + +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 + +struct map_heightHeader +{ + uint32 fourcc; + uint32 flags; + float gridHeight; + float gridMaxHeight; +}; + +#define MAP_LIQUID_NO_TYPE 0x0001 +#define MAP_LIQUID_NO_HEIGHT 0x0002 + +struct map_liquidHeader +{ + uint32 fourcc; + uint8 flags; + uint8 liquidFlags; + uint16 liquidType; + uint8 offsetX; + uint8 offsetY; + uint8 width; + uint8 height; + float liquidLevel; +}; + +// ****************************************** +// Loaded map data structures +// ****************************************** + +struct LoadedAreaData +{ + typedef std::array AreaMapType; + + uint16 gridArea; + std::unique_ptr areaMap; +}; + +struct LoadedHeightData +{ + typedef std::array HeightPlanesType; + + struct Uint16HeightData + { + typedef std::array V9Type; + typedef std::array V8Type; + + V9Type v9; + V8Type v8; + float gridIntHeightMultiplier; + }; + + struct Uint8HeightData + { + typedef std::array V9Type; + typedef std::array V8Type; + + V9Type v9; + V8Type v8; + float gridIntHeightMultiplier; + }; + + struct FloatHeightData + { + typedef std::array V9Type; + typedef std::array V8Type; + + V9Type v9; + V8Type v8; + }; + + float gridHeight; + std::unique_ptr uint16HeightData; + std::unique_ptr uint8HeightData; + std::unique_ptr floatHeightData; + std::unique_ptr minHeightPlanes; +}; + +struct LoadedLiquidData +{ + typedef std::array LiquidEntryType; + typedef std::array LiquidFlagsType; + typedef std::vector LiquidMapType; + + uint16 liquidGlobalEntry; + uint8 liquidGlobalFlags; + uint8 liquidOffX; + uint8 liquidOffY; + uint8 liquidWidth; + uint8 liquidHeight; + float liquidLevel; + std::unique_ptr liquidEntry; + std::unique_ptr liquidFlags; + std::unique_ptr liquidMap; +}; + +struct LoadedHoleData +{ + typedef std::array HolesType; + + HolesType holes; +}; + +enum LiquidStatus +{ + LIQUID_MAP_NO_WATER = 0x00000000, + LIQUID_MAP_ABOVE_WATER = 0x00000001, + LIQUID_MAP_WATER_WALK = 0x00000002, + LIQUID_MAP_IN_WATER = 0x00000004, + LIQUID_MAP_UNDER_WATER = 0x00000008 +}; + +struct LiquidData +{ + LiquidData() = default; + + uint32 Entry{ 0 }; + uint32 Flags{ 0 }; + float Level{ INVALID_HEIGHT }; + float DepthLevel{ INVALID_HEIGHT }; + LiquidStatus Status{ LIQUID_MAP_NO_WATER }; +}; + +enum class TerrainMapDataReadResult +{ + Success, + NotFound, + ReadError, + InvalidMagic, + InvalidAreaData, + InvalidHeightData, + InvalidLiquidData, + InvalidHoleData +}; + +class GridTerrainData +{ + bool LoadAreaData(std::ifstream& fileStream, uint32 const offset); + bool LoadHeightData(std::ifstream& fileStream, uint32 const offset); + bool LoadLiquidData(std::ifstream& fileStream, uint32 const offset); + bool LoadHolesData(std::ifstream& fileStream, uint32 const offset); + + std::unique_ptr _loadedAreaData; + std::unique_ptr _loadedHeightData; + std::unique_ptr _loadedLiquidData; + std::unique_ptr _loadedHoleData; + + bool isHole(int row, int col) const; + + // Get height functions and pointers + typedef float (GridTerrainData::* GetHeightPtr) (float x, float y) const; + GetHeightPtr _gridGetHeight; + float getHeightFromFloat(float x, float y) const; + float getHeightFromUint16(float x, float y) const; + float getHeightFromUint8(float x, float y) const; + float getHeightFromFlat(float x, float y) const; + +public: + GridTerrainData(); + ~GridTerrainData() { }; + TerrainMapDataReadResult Load(std::string const& mapFileName); + + uint16 getArea(float x, float y) const; + inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); } + float getMinHeight(float x, float y) const; + float getLiquidLevel(float x, float y) const; + LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const; +}; + +#endif diff --git a/src/server/game/Grids/GridTerrainLoader.cpp b/src/server/game/Grids/GridTerrainLoader.cpp new file mode 100644 index 00000000000000..b82c3b544618c9 --- /dev/null +++ b/src/server/game/Grids/GridTerrainLoader.cpp @@ -0,0 +1,160 @@ +#include "DisableMgr.h" +#include "GridTerrainLoader.h" +#include "MMapFactory.h" +#include "MMapMgr.h" +#include "ScriptMgr.h" +#include "VMapFactory.h" +#include "VMapMgr2.h" + +void GridTerrainLoader::LoadTerrain() +{ + LoadMap(); + if (_map->GetInstanceId() == 0) + { + LoadVMap(); + LoadMMap(); + } +} + +void GridTerrainLoader::LoadMap() +{ + // Instances will point to the parent maps terrain data + if (_map->GetInstanceId() != 0) + { + // load grid map for base map + Map* parentMap = const_cast(_map->GetParent()); + + // GetGridTerrainData will create the parent map grid + _grid.SetTerrainData(parentMap->GetGridTerrainDataSharedPtr(GridCoord(_grid.GetX(), _grid.GetY()))); + return; + } + + // map file name + std::string const mapFileName = Acore::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), _map->GetId(), GetX(), GetY()); + + // loading data + LOG_DEBUG("maps", "Loading map {}", mapFileName); + std::unique_ptr terrainData = std::make_unique(); + TerrainMapDataReadResult loadResult = terrainData->Load(mapFileName); + if (loadResult == TerrainMapDataReadResult::Success) + _grid.SetTerrainData(std::move(terrainData)); + else + { + if (loadResult == TerrainMapDataReadResult::InvalidMagic) + LOG_ERROR("maps", "Map file '{}' is from an incompatible clientversion. Please recreate using the mapextractor.", mapFileName); + else + LOG_DEBUG("maps", "Error (result: {}) loading map file: {}", uint32(loadResult), mapFileName); + } + + sScriptMgr->OnLoadGridMap(_map, _grid.GetTerrainData(), GetX(), GetY()); +} + +void GridTerrainLoader::LoadVMap() +{ + int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), _map->GetId(), GetX(), GetY()); + switch (vmapLoadResult) + { + case VMAP::VMAP_LOAD_RESULT_OK: + LOG_DEBUG("maps", "VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", + _map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY()); + break; + case VMAP::VMAP_LOAD_RESULT_ERROR: + LOG_DEBUG("maps", "Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", + _map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY()); + break; + case VMAP::VMAP_LOAD_RESULT_IGNORED: + LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", + _map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY()); + break; + } +} + +void GridTerrainLoader::LoadMMap() +{ + if (!DisableMgr::IsPathfindingEnabled(_map)) + return; + + int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(_map->GetId(), GetX(), GetY()); + switch (mmapLoadResult) + { + case MMAP::MMAP_LOAD_RESULT_OK: + LOG_DEBUG("maps", "MMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", + _map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY()); + break; + case MMAP::MMAP_LOAD_RESULT_ERROR: + LOG_DEBUG("maps", "Could not load MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", + _map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY()); + break; + case MMAP::MMAP_LOAD_RESULT_IGNORED: + LOG_DEBUG("maps", "Ignored MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", + _map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY()); + break; + } +} + +bool GridTerrainLoader::ExistMap(uint32 mapid, int gx, int gy) +{ + std::string const mapFileName = Acore::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), mapid, gx, gy); + std::ifstream fileStream(mapFileName, std::ios::binary); + if (fileStream.fail()) + { + LOG_DEBUG("maps", "Map file '{}': error opening file", mapFileName); + return false; + } + + map_fileheader header; + if (!fileStream.read(reinterpret_cast(&header), sizeof(header))) + { + LOG_DEBUG("maps", "Map file '{}': unable to read header", mapFileName); + return false; + } + + if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic) + { + LOG_ERROR("maps", "Map file '{}' is from an incompatible map version ({:.4u} v{}), {:.4s} 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.", + mapFileName, 4, header.mapMagic, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic); + return false; + } + + return true; +} + +bool GridTerrainLoader::ExistVMap(uint32 mapid, int gx, int gy) +{ + if (VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr()) + { + if (vmgr->isMapLoadingEnabled()) + { + VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy); + std::string name = vmgr->getDirFileName(mapid, gx, gy); + switch (result) + { + case VMAP::LoadResult::Success: + break; + case VMAP::LoadResult::FileNotFound: + LOG_DEBUG("maps", "VMap file '{}' does not exist", (sWorld->GetDataPath() + "vmaps/" + name)); + LOG_DEBUG("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/")); + return false; + case VMAP::LoadResult::VersionMismatch: + LOG_ERROR("maps", "VMap file '{}' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name)); + 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."); + return false; + } + } + } + + return true; +} + +void GridTerrainUnloader::UnloadTerrain() +{ + // Only parent maps manage terrain data + if (_map->GetInstanceId() != 0) + return; + + int gx = (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetX(); + int gy = (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetY(); + + VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(_map->GetId(), gx, gy); + MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(_map->GetId(), gx, gy); +} diff --git a/src/server/game/Grids/GridTerrainLoader.h b/src/server/game/Grids/GridTerrainLoader.h new file mode 100644 index 00000000000000..03db11f7fdea7d --- /dev/null +++ b/src/server/game/Grids/GridTerrainLoader.h @@ -0,0 +1,59 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef ACORE_GRID_TERRAIN_LOADER_H +#define ACORE_GRID_TERRAIN_LOADER_H + +#include "GridDefines.h" + +class GridTerrainLoader +{ +public: + GridTerrainLoader(MapGridType& grid, Map* map) + : _grid(grid), _map(map) { } + + void LoadTerrain(); + + static bool ExistMap(uint32 mapid, int gx, int gy); + static bool ExistVMap(uint32 mapid, int gx, int gy); + +private: + void LoadMap(); + void LoadVMap(); + void LoadMMap(); + + uint16 GetX() { return (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetX(); } + uint16 GetY() { return (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetY(); } + + MapGridType& _grid; + Map* _map; +}; + +class GridTerrainUnloader +{ +public: + GridTerrainUnloader(MapGridType& grid, Map* map) + : _grid(grid), _map(map) { } + + void UnloadTerrain(); + +private: + MapGridType& _grid; + Map* _map; +}; + +#endif diff --git a/src/server/game/Grids/MapGrid.h b/src/server/game/Grids/MapGrid.h new file mode 100644 index 00000000000000..9c6b33c9195e6b --- /dev/null +++ b/src/server/game/Grids/MapGrid.h @@ -0,0 +1,154 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAP_GRID_H +#define MAP_GRID_H + +#include "GridCell.h" +#include "GridReference.h" + +class GridTerrainData; + +template +< + class WORLD_OBJECT_TYPES, + class GRID_OBJECT_TYPES +> +class MapGrid +{ +public: + typedef GridCell GridCellType; + + MapGrid(uint16 const x, uint16 const y) + : _x(x), _y(y), _objectDataLoaded(false), _terrainData(nullptr) { } + + // Unique identifier for grid + uint32 GetId() const { return _y * MAX_NUMBER_OF_GRIDS + _x; } + + uint16 GetX() const { return _x; } + uint16 GetY() const { return _y; } + + bool IsObjectDataLoaded() const { return _objectDataLoaded; } + void SetObjectDataLoaded() { _objectDataLoaded = true; } + + template void AddWorldObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj) + { + GetOrCreateCell(x, y).AddWorldObject(obj); + } + + template void RemoveWorldObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj) + { + GetOrCreateCell(x, y).RemoveWorldObject(obj); + } + + template void AddGridObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj) + { + GetOrCreateCell(x, y).AddGridObject(obj); + } + + template void RemoveGridObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj) + { + GetOrCreateCell(x, y).RemoveGridObject(obj); + } + + // Visit all cells + template + void VisitAllCells(TypeContainerVisitor >& visitor) + { + for (auto& cellX : _cells) + { + for (auto& cellY : cellX) + { + if (!cellY) + continue; + + cellY->Visit(visitor); + } + } + } + + // Visit single cell + template + void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor >& visitor) + { + GridCellType* gridCell = GetCell(x, y); + if (!gridCell) + return; + + gridCell->Visit(visitor); + } + + void link(GridRefMgr>* pTo) + { + _gridReference.link(pTo, this); + } + + GridTerrainData* GetTerrainData() const { return _terrainData.get(); } + std::shared_ptr GetTerrainDataSharedPtr() { return _terrainData; } + void SetTerrainData(std::shared_ptr terrainData) { _terrainData = terrainData; } + + uint32 GetCreatedCellsCount() + { + uint32 count = 0; + for (auto& cellX : _cells) + { + for (auto& cellY : cellX) + { + if (!cellY) + continue; + + ++count; + } + } + return count; + } + +private: + // Creates and returns the cell if not already created + GridCellType& GetOrCreateCell(uint16 const x, uint16 const y) + { + GridCellType* cell = GetCell(x, y); + if (!cell) + _cells[x][y] = std::make_unique(); + + return *_cells[x][y]; + } + + GridCellType* GetCell(uint16 const x, uint16 const y) + { + ASSERT(x < MAX_NUMBER_OF_CELLS && y < MAX_NUMBER_OF_CELLS); + return _cells[x][y].get(); + } + + GridCellType const* GetCell(uint16 const x, uint16 const y) const + { + ASSERT(x < MAX_NUMBER_OF_CELLS && y < MAX_NUMBER_OF_CELLS); + return _cells[x][y].get(); + } + + uint16 _x; + uint16 _y; + + bool _objectDataLoaded; + std::array, MAX_NUMBER_OF_CELLS>, MAX_NUMBER_OF_CELLS> _cells; // N * N array + GridReference> _gridReference; + + // Instances will share a copy of the parent maps terrainData + std::shared_ptr _terrainData; +}; + +#endif diff --git a/src/server/game/Grids/MapGridManager.cpp b/src/server/game/Grids/MapGridManager.cpp new file mode 100644 index 00000000000000..21ca5bfed31199 --- /dev/null +++ b/src/server/game/Grids/MapGridManager.cpp @@ -0,0 +1,129 @@ +#include "MapGridManager.h" +#include "GridObjectLoader.h" +#include "GridTerrainLoader.h" + +void MapGridManager::CreateGrid(uint16 const x, uint16 const y) +{ + std::lock_guard guard(_gridLock); + if (IsGridCreated(x, y)) + return; + + std::unique_ptr grid = std::make_unique(x, y); + grid->link(_map); + + GridTerrainLoader loader(*grid, _map); + loader.LoadTerrain(); + + _mapGrid[x][y] = std::move(grid); + + ++_createdGridsCount; +} + +bool MapGridManager::LoadGrid(uint16 const x, uint16 const y) +{ + MapGridType* grid = GetGrid(x, y); + if (!grid || grid->IsObjectDataLoaded()) + return false; + + // Must mark as loaded first, as GridObjectLoader spawning objects can attempt to recursively load the grid + grid->SetObjectDataLoaded(); + + GridObjectLoader loader(*grid, _map); + loader.LoadAllCellsInGrid(); + + ++_loadedGridsCount; + return true; +} + +void MapGridManager::UnloadGrid(uint16 const x, uint16 const y) +{ + MapGridType* grid = GetGrid(x, y); + if (!grid) + return; + + { + GridObjectCleaner worker; + TypeContainerVisitor visitor(worker); + grid->VisitAllCells(visitor); + } + + _map->RemoveAllObjectsInRemoveList(); + + { + GridObjectUnloader worker; + TypeContainerVisitor visitor(worker); + grid->VisitAllCells(visitor); + } + + GridTerrainUnloader terrainUnloader(*grid, _map); + terrainUnloader.UnloadTerrain(); + + _mapGrid[x][y] = nullptr; +} + +bool MapGridManager::IsGridCreated(uint16 const x, uint16 const y) const +{ + if (!MapGridManager::IsValidGridCoordinates(x, y)) + return false; + + return _mapGrid[x][y].get(); +} + +bool MapGridManager::IsGridLoaded(uint16 const x, uint16 const y) const +{ + if (!MapGridManager::IsValidGridCoordinates(x, y)) + return false; + + return _mapGrid[x][y].get() && _mapGrid[x][y]->IsObjectDataLoaded(); +} + +MapGridType* MapGridManager::GetGrid(uint16 const x, uint16 const y) +{ + if (!MapGridManager::IsValidGridCoordinates(x, y)) + return nullptr; + + return _mapGrid[x][y].get(); +} + +uint32 MapGridManager::GetCreatedGridsCount() +{ + return _createdGridsCount; +} + +uint32 MapGridManager::GetLoadedGridsCount() +{ + return _loadedGridsCount; +} + +uint32 MapGridManager::GetCreatedCellsInGridCount(uint16 const x, uint16 const y) +{ + MapGridType* grid = GetGrid(x, y); + if (grid) + return grid->GetCreatedCellsCount(); + + return 0; +} + +uint32 MapGridManager::GetCreatedCellsInMapCount() +{ + uint32 count = 0; + for (uint32 gridX = 0; gridX < MAX_NUMBER_OF_GRIDS; ++gridX) + { + for (uint32 gridY = 0; gridY < MAX_NUMBER_OF_GRIDS; ++gridY) + { + if (MapGridType* grid = GetGrid(gridX, gridY)) + count += grid->GetCreatedCellsCount(); + } + } + return count; +} + +bool MapGridManager::IsGridsFullyCreated() const +{ + return _createdGridsCount == (MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS); +} + +bool MapGridManager::IsGridsFullyLoaded() const +{ + return _loadedGridsCount == (MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS); +} diff --git a/src/server/game/Grids/MapGridManager.h b/src/server/game/Grids/MapGridManager.h new file mode 100644 index 00000000000000..3eb7c629d53ec7 --- /dev/null +++ b/src/server/game/Grids/MapGridManager.h @@ -0,0 +1,62 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAP_GRID_MANAGER_H +#define MAP_GRID_MANAGER_H + +#include "Common.h" +#include "GridDefines.h" +#include "MapDefines.h" +#include "MapGrid.h" + +#include + +class Map; + +class MapGridManager +{ +public: + MapGridManager(Map* map) : _map(map), _createdGridsCount(0), _loadedGridsCount(0) { } + + void CreateGrid(uint16 const x, uint16 const y); + bool LoadGrid(uint16 const x, uint16 const y); + void UnloadGrid(uint16 const x, uint16 const y); + bool IsGridCreated(uint16 const x, uint16 const y) const; + bool IsGridLoaded(uint16 const x, uint16 const y) const; + MapGridType* GetGrid(uint16 const x, uint16 const y); + + static bool IsValidGridCoordinates(uint16 const x, uint16 const y) { return (x < MAX_NUMBER_OF_GRIDS && y < MAX_NUMBER_OF_GRIDS); } + + uint32 GetCreatedGridsCount(); + uint32 GetLoadedGridsCount(); + uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y); + uint32 GetCreatedCellsInMapCount(); + + bool IsGridsFullyCreated() const; + bool IsGridsFullyLoaded() const; + +private: + Map* _map; + + uint32 _createdGridsCount; + uint32 _loadedGridsCount; + + std::mutex _gridLock; + std::unique_ptr _mapGrid[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; +}; + +#endif diff --git a/src/server/game/Grids/NGrid.h b/src/server/game/Grids/NGrid.h deleted file mode 100644 index 6ac60aeb72dcd4..00000000000000 --- a/src/server/game/Grids/NGrid.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef ACORE_NGRID_H -#define ACORE_NGRID_H - -/** NGrid is nothing more than a wrapper of the Grid with an NxN cells - */ - -#include "Grid.h" -#include "GridReference.h" -#include "Timer.h" - -template -< - uint32 N, - class ACTIVE_OBJECT, - class WORLD_OBJECT_TYPES, - class GRID_OBJECT_TYPES - > -class NGrid -{ -public: - typedef Grid GridType; - NGrid(uint32 id, int32 x, int32 y) - : i_gridId(id), i_x(x), i_y(y), i_GridObjectDataLoaded(false) - { - } - - GridType& GetGridType(const uint32 x, const uint32 y) - { - ASSERT(x < N && y < N); - return i_cells[x][y]; - } - - [[nodiscard]] GridType const& GetGridType(const uint32 x, const uint32 y) const - { - ASSERT(x < N && y < N); - return i_cells[x][y]; - } - - [[nodiscard]] uint32 GetGridId() const { return i_gridId; } - [[nodiscard]] int32 getX() const { return i_x; } - [[nodiscard]] int32 getY() const { return i_y; } - - void link(GridRefMgr >* pTo) - { - i_Reference.link(pTo, this); - } - [[nodiscard]] bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; } - void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; } - - /* - template void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj) - { - GetGridType(x, y).AddWorldObject(obj); - } - - template void RemoveWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj) - { - GetGridType(x, y).RemoveWorldObject(obj); - } - - template void AddGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj) - { - GetGridType(x, y).AddGridObject(obj); - } - - template void RemoveGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj) - { - GetGridType(x, y).RemoveGridObject(obj); - } - */ - - // Visit all Grids (cells) in NGrid (grid) - template - void VisitAllGrids(TypeContainerVisitor >& visitor) - { - for (uint32 x = 0; x < N; ++x) - for (uint32 y = 0; y < N; ++y) - GetGridType(x, y).Visit(visitor); - } - - // Visit a single Grid (cell) in NGrid (grid) - template - void VisitGrid(const uint32 x, const uint32 y, TypeContainerVisitor >& visitor) - { - GetGridType(x, y).Visit(visitor); - } - -private: - uint32 i_gridId; - GridReference > i_Reference; - int32 i_x; - int32 i_y; - GridType i_cells[N][N]; - bool i_GridObjectDataLoaded; -}; -#endif diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 42f657f9bb836c..6e084b7338e055 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -24,7 +24,7 @@ #include "GameObject.h" #include "Group.h" #include "Object.h" -#include "ObjectGridLoader.h" +#include "GridObjectLoader.h" #include "Optional.h" #include "Player.h" #include "Spell.h" diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp deleted file mode 100644 index 2b7d6f8ef54dcb..00000000000000 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "ObjectGridLoader.h" -#include "CellImpl.h" -#include "Corpse.h" -#include "Creature.h" -#include "DynamicObject.h" -#include "GameObject.h" -#include "GridNotifiers.h" -#include "ObjectMgr.h" -#include "Transport.h" - -// for loading world object at grid loading (Corpses) -//TODO: to implement npc on transport, also need to load npcs at grid loading -class ObjectWorldLoader -{ -public: - explicit ObjectWorldLoader(ObjectGridLoader& gloader) - : i_cell(gloader.i_cell), i_map(gloader.i_map), i_grid(gloader.i_grid), i_corpses(gloader.i_corpses) - {} - - void Visit(CorpseMapType& m); - - template void Visit(GridRefMgr&) { } - -private: - Cell i_cell; - Map* i_map; - NGridType& i_grid; -public: - uint32& i_corpses; -}; - -template void ObjectGridLoader::SetObjectCell(T* /*obj*/, CellCoord const& /*cellCoord*/) -{ -} - -template<> void ObjectGridLoader::SetObjectCell(Creature* obj, CellCoord const& cellCoord) -{ - Cell cell(cellCoord); - obj->SetCurrentCell(cell); -} - -template<> void ObjectGridLoader::SetObjectCell(GameObject* obj, CellCoord const& cellCoord) -{ - Cell cell(cellCoord); - obj->SetCurrentCell(cell); -} - -template -void AddObjectHelper(CellCoord& cell, GridRefMgr& m, uint32& count, Map* /*map*/, T* obj) -{ - obj->AddToGrid(m); - ObjectGridLoader::SetObjectCell(obj, cell); - obj->AddToWorld(); - ++count; -} - -template <> -void AddObjectHelper(CellCoord& cell, CreatureMapType& m, uint32& count, Map* map, Creature* obj) -{ - obj->AddToGrid(m); - ObjectGridLoader::SetObjectCell(obj, cell); - obj->AddToWorld(); - if (obj->isActiveObject()) - map->AddToActive(obj); - - ++count; -} - -template <> -void AddObjectHelper(CellCoord& cell, GameObjectMapType& m, uint32& count, Map* map, GameObject* obj) -{ - obj->AddToGrid(m); - ObjectGridLoader::SetObjectCell(obj, cell); - obj->AddToWorld(); - if (obj->isActiveObject()) - map->AddToActive(obj); - - ++count; -} - -template -void LoadHelper(CellGuidSet const& /*guid_set*/, CellCoord& /*cell*/, GridRefMgr& /*m*/, uint32& /*count*/, Map* /*map*/) -{ -} - -template <> -void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr& m, uint32& count, Map* map) -{ - for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid) - { - Creature* obj = new Creature(); - ObjectGuid::LowType guid = *i_guid; - if (!obj->LoadFromDB(guid, map)) - { - delete obj; - continue; - } - - AddObjectHelper(cell, m, count, map, obj); - - if (!obj->IsMoveInLineOfSightDisabled() && obj->GetDefaultMovementType() == IDLE_MOTION_TYPE && !obj->isNeedNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION)) - { - if (obj->IsAlive() && !obj->HasUnitState(UNIT_STATE_SIGHTLESS) && obj->HasReactState(REACT_AGGRESSIVE) && !obj->IsImmuneToNPC()) - { - // call MoveInLineOfSight for nearby grid creatures - Acore::AIRelocationNotifier notifier(*obj); - Cell::VisitGridObjects(obj, notifier, 60.f); - } - } - } -} - -template <> -void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr& m, uint32& count, Map* map) -{ - for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid) - { - ObjectGuid::LowType guid = *i_guid; - GameObjectData const* data = sObjectMgr->GetGameObjectData(guid); - GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject(); - - if (!obj->LoadFromDB(guid, map)) - { - delete obj; - continue; - } - - AddObjectHelper(cell, m, count, map, obj); - } -} - -void ObjectGridLoader::Visit(GameObjectMapType& m) -{ - CellCoord cellCoord = i_cell.GetCellCoord(); - CellObjectGuids const& cell_guids = sObjectMgr->GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cellCoord.GetId()); - LoadHelper(cell_guids.gameobjects, cellCoord, m, i_gameObjects, i_map); -} - -void ObjectGridLoader::Visit(CreatureMapType& m) -{ - CellCoord cellCoord = i_cell.GetCellCoord(); - CellObjectGuids const& cell_guids = sObjectMgr->GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cellCoord.GetId()); - LoadHelper(cell_guids.creatures, cellCoord, m, i_creatures, i_map); -} - -void ObjectWorldLoader::Visit(CorpseMapType& /*m*/) -{ - CellCoord cellCoord = i_cell.GetCellCoord(); - if (std::unordered_set const* corpses = i_map->GetCorpsesInCell(cellCoord.GetId())) - { - for (Corpse* corpse : *corpses) - { - corpse->AddToWorld(); - GridType& cell = i_grid.GetGridType(i_cell.CellX(), i_cell.CellY()); - if (corpse->IsWorldObject()) - cell.AddWorldObject(corpse); - else - cell.AddGridObject(corpse); - - ++i_corpses; - } - } -} - -void ObjectGridLoader::LoadN(void) -{ - i_gameObjects = 0; - i_creatures = 0; - i_corpses = 0; - i_cell.data.Part.cell_y = 0; - for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x) - { - i_cell.data.Part.cell_x = x; - for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y) - { - i_cell.data.Part.cell_y = y; - - //Load creatures and game objects - { - TypeContainerVisitor visitor(*this); - i_grid.VisitGrid(x, y, visitor); - } - - //Load corpses (not bones) - { - ObjectWorldLoader worker(*this); - TypeContainerVisitor visitor(worker); - i_grid.VisitGrid(x, y, visitor); - } - } - } - LOG_DEBUG("maps", "{} GameObjects, {} Creatures, and {} Corpses/Bones loaded for grid {} on map {}", i_gameObjects, i_creatures, i_corpses, i_grid.GetGridId(), i_map->GetId()); -} - -template -void ObjectGridUnloader::Visit(GridRefMgr& m) -{ - while (!m.IsEmpty()) - { - T* obj = m.getFirst()->GetSource(); - // if option set then object already saved at this moment - //if (!sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) - // obj->SaveRespawnTime(); - //Some creatures may summon other temp summons in CleanupsBeforeDelete() - //So we need this even after cleaner (maybe we can remove cleaner) - //Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted - //TODO: Check if that script has the correct logic. Do we really need to summons something before deleting? - obj->CleanupsBeforeDelete(); - ///- object will get delinked from the manager when deleted - delete obj; - } -} - -template -void ObjectGridCleaner::Visit(GridRefMgr& m) -{ - for (typename GridRefMgr::iterator iter = m.begin(); iter != m.end(); ++iter) - iter->GetSource()->CleanupsBeforeDelete(); -} - -template void ObjectGridUnloader::Visit(CreatureMapType&); -template void ObjectGridUnloader::Visit(GameObjectMapType&); -template void ObjectGridUnloader::Visit(DynamicObjectMapType&); - -template void ObjectGridCleaner::Visit(CreatureMapType&); -template void ObjectGridCleaner::Visit(GameObjectMapType&); -template void ObjectGridCleaner::Visit(DynamicObjectMapType&); -template void ObjectGridCleaner::Visit(CorpseMapType&); diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index f5c3df9b85d858..963fdcb29637d7 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -777,16 +777,10 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData) Unit* unit = ObjectAccessor::GetUnit(*_player, guid); - CellCoord p = Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); - - Cell cell(p); - cell.SetNoCreate(); - Acore::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); Acore::LocalizedPacketDo emote_do(emote_builder); Acore::PlayerDistWorker > emote_worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do); - TypeContainerVisitor >, WorldTypeMapContainer> message(emote_worker); - cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); + Cell::VisitWorldObjects(GetPlayer(), emote_worker, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); diff --git a/src/server/game/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp index e5b6de588bd8b3..434ad43250c603 100644 --- a/src/server/game/Loot/LootItemStorage.cpp +++ b/src/server/game/Loot/LootItemStorage.cpp @@ -20,6 +20,7 @@ #include "ObjectMgr.h" #include "PreparedStatement.h" #include "QueryResult.h" +#include "Timer.h" LootItemStorage::LootItemStorage() { diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 5d9579c4a3000c..38f501bb3c13b5 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -28,13 +28,13 @@ #include "InstanceScript.h" #include "IVMapMgr.h" #include "LFGMgr.h" +#include "MapGrid.h" #include "MapInstanced.h" #include "Metric.h" #include "MiscPackets.h" #include "MMapFactory.h" #include "Object.h" #include "ObjectAccessor.h" -#include "ObjectGridLoader.h" #include "ObjectMgr.h" #include "Pet.h" #include "ScriptMgr.h" @@ -44,21 +44,6 @@ #include "VMapMgr2.h" #include "Weather.h" -union u_map_magic -{ - char asChar[4]; - uint32 asUInt; -}; - -u_map_magic MapMagic = { {'M', 'A', 'P', 'S'} }; -uint32 MapVersionMagic = 9; -u_map_magic MapAreaMagic = { {'A', 'R', 'E', 'A'} }; -u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} }; -u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} }; - -static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 }; -static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 }; - #define MAP_INVALID_ZONE 0xFFFFFFFF ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE), @@ -83,181 +68,29 @@ Map::~Map() if (!m_scriptSchedule.empty()) sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size()); - //MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(GetId()); MMAP::MMapFactory::createOrGetMMapMgr()->unloadMapInstance(GetId(), i_InstanceId); } -bool Map::ExistMap(uint32 mapid, int gx, int gy) -{ - int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1; - char* tmp = new char[len]; - snprintf(tmp, len, (char*)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), mapid, gx, gy); - - bool ret = false; - FILE* pf = fopen(tmp, "rb"); - - if (!pf) - LOG_ERROR("maps", "Map file '{}': does not exist!", tmp); - else - { - map_fileheader header; - if (fread(&header, sizeof(header), 1, pf) == 1) - { - if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic) - { - LOG_ERROR("maps", "Map file '{}' is from an incompatible map version ({:.4u} v{}), {:.4s} 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.", - tmp, 4, header.mapMagic, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic); - } - - else - ret = true; - } - fclose(pf); - } - delete [] tmp; - return ret; -} - -bool Map::ExistVMap(uint32 mapid, int gx, int gy) -{ - if (VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr()) - { - if (vmgr->isMapLoadingEnabled()) - { - VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy); - std::string name = vmgr->getDirFileName(mapid, gx, gy); - switch (result) - { - case VMAP::LoadResult::Success: - break; - case VMAP::LoadResult::FileNotFound: - LOG_ERROR("maps", "VMap file '{}' does not exist", (sWorld->GetDataPath() + "vmaps/" + name)); - 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/")); - return false; - case VMAP::LoadResult::VersionMismatch: - LOG_ERROR("maps", "VMap file '{}' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name)); - 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."); - return false; - } - } - } - - return true; -} - -void Map::LoadMMap(int gx, int gy) -{ - if (!sDisableMgr->IsPathfindingEnabled(this)) // pussywizard - return; - - int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(GetId(), gx, gy); - switch (mmapLoadResult) - { - case MMAP::MMAP_LOAD_RESULT_OK: - LOG_DEBUG("maps", "MMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy); - break; - case MMAP::MMAP_LOAD_RESULT_ERROR: - LOG_DEBUG("maps", "Could not load MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy); - break; - case MMAP::MMAP_LOAD_RESULT_IGNORED: - LOG_DEBUG("maps", "Ignored MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy); - break; - } -} - -void Map::LoadVMap(int gx, int gy) -{ - // x and y are swapped !! - int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), GetId(), gx, gy); - switch (vmapLoadResult) - { - case VMAP::VMAP_LOAD_RESULT_OK: - LOG_DEBUG("maps", "VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy); - break; - case VMAP::VMAP_LOAD_RESULT_ERROR: - LOG_DEBUG("maps", "Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy); - break; - case VMAP::VMAP_LOAD_RESULT_IGNORED: - LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy); - break; - } -} - -void Map::LoadMap(int gx, int gy, bool reload) -{ - if (i_InstanceId != 0) - { - if (GridMaps[gx][gy]) - return; - - // load grid map for base map - m_parentMap->EnsureGridCreated(GridCoord(63 - gx, 63 - gy)); - - GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; - return; - } - - if (GridMaps[gx][gy] && !reload) - return; - - //map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?) - if (GridMaps[gx][gy]) - { - LOG_DEBUG("maps", "Unloading previously loaded map {} before reloading.", GetId()); - sScriptMgr->OnUnloadGridMap(this, GridMaps[gx][gy], gx, gy); - - delete (GridMaps[gx][gy]); - GridMaps[gx][gy] = nullptr; - } - - // map file name - char* tmp = nullptr; - int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1; - tmp = new char[len]; - snprintf(tmp, len, (char*)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy); - LOG_DEBUG("maps", "Loading map {}", tmp); - // loading data - GridMaps[gx][gy] = new GridMap(); - if (!GridMaps[gx][gy]->loadData(tmp)) - { - LOG_ERROR("maps", "Error loading map file: \n {}\n", tmp); - } - delete [] tmp; - - sScriptMgr->OnLoadGridMap(this, GridMaps[gx][gy], gx, gy); -} - -void Map::LoadMapAndVMap(int gx, int gy) -{ - LoadMap(gx, gy); - if (i_InstanceId == 0) - { - LoadVMap(gx, gy); // Only load the data for the base map - LoadMMap(gx, gy); - } -} - Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : - i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), + _mapGridManager(this), i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0), m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()), i_scriptLock(false), _defaultLight(GetDefaultMapLight(id)) { m_parentMap = (_parent ? _parent : this); - for (unsigned int idx = 0; idx < MAX_NUMBER_OF_GRIDS; ++idx) - { - for (unsigned int j = 0; j < MAX_NUMBER_OF_GRIDS; ++j) - { - //z code - GridMaps[idx][j] = nullptr; - setNGrid(nullptr, idx, j); - } - } _zonePlayerCountMap.clear(); //lets initialize visibility distance for map Map::InitVisibilityDistance(); +} + +// Hook called after map is created AND after added to map list +void Map::OnCreateMap() +{ + // Instances load all grids by default (both base map and child maps) + if (GetInstanceId()) + LoadAllGrids(); sScriptMgr->OnCreateMap(this); } @@ -282,21 +115,21 @@ void Map::InitVisibilityDistance() template void Map::AddToGrid(T* obj, Cell const& cell) { - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); if (obj->IsWorldObject()) - grid->GetGridType(cell.CellX(), cell.CellY()).template AddWorldObject(obj); + grid->AddWorldObject(cell.CellX(), cell.CellY(), obj); else - grid->GetGridType(cell.CellX(), cell.CellY()).template AddGridObject(obj); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); } template<> void Map::AddToGrid(Creature* obj, Cell const& cell) { - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); if (obj->IsWorldObject()) - grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); + grid->AddWorldObject(cell.CellX(), cell.CellY(), obj); else - grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); obj->SetCurrentCell(cell); } @@ -304,8 +137,8 @@ void Map::AddToGrid(Creature* obj, Cell const& cell) template<> void Map::AddToGrid(GameObject* obj, Cell const& cell) { - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); obj->SetCurrentCell(cell); } @@ -313,11 +146,11 @@ void Map::AddToGrid(GameObject* obj, Cell const& cell) template<> void Map::AddToGrid(DynamicObject* obj, Cell const& cell) { - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); if (obj->IsWorldObject()) - grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); + grid->AddWorldObject(cell.CellX(), cell.CellY(), obj); else - grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); obj->SetCurrentCell(cell); } @@ -325,19 +158,19 @@ void Map::AddToGrid(DynamicObject* obj, Cell const& cell) template<> void Map::AddToGrid(Corpse* obj, Cell const& cell) { - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); // Corpses are a special object type - they can be added to grid via a call to AddToMap // or loaded through ObjectGridLoader. // Both corpses loaded from database and these freshly generated by Player::CreateCoprse are added to _corpsesByCell // ObjectGridLoader loads all corpses from _corpsesByCell even if they were already added to grid before it was loaded // so we need to explicitly check it here (Map::AddToGrid is only called from Player::BuildPlayerRepop, not from ObjectGridLoader) // to avoid failing an assertion in GridObject::AddToGrid - if (grid->isGridObjectDataLoaded()) + if (grid->IsObjectDataLoaded()) { if (obj->IsWorldObject()) - grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); + grid->AddWorldObject(cell.CellX(), cell.CellY(), obj); else - grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); } } @@ -363,21 +196,19 @@ void Map::SwitchGridContainers(Creature* obj, bool on) return; LOG_DEBUG("maps", "Switch object {} from grid[{}, {}] {}", obj->GetGUID().ToString(), cell.GridX(), cell.GridY(), on); - NGridType* ngrid = getNGrid(cell.GridX(), cell.GridY()); - ASSERT(ngrid); - - GridType& grid = ngrid->GetGridType(cell.CellX(), cell.CellY()); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); + ASSERT(grid); obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add if (on) { - grid.AddWorldObject(obj); + grid->AddWorldObject(cell.CellX(), cell.CellY(), obj); AddWorldObject(obj); } else { - grid.AddGridObject(obj); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); RemoveWorldObject(obj); } @@ -401,21 +232,19 @@ void Map::SwitchGridContainers(GameObject* obj, bool on) return; //LOG_DEBUG(LOG_FILTER_MAPS, "Switch object {} from grid[{}, {}] {}", obj->GetGUID().ToString(), cell.data.Part.grid_x, cell.data.Part.grid_y, on); - NGridType* ngrid = getNGrid(cell.GridX(), cell.GridY()); - ASSERT(ngrid); - - GridType& grid = ngrid->GetGridType(cell.CellX(), cell.CellY()); + MapGridType* grid = GetMapGrid(cell.GridX(), cell.GridY()); + ASSERT(grid); obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add if (on) { - grid.AddWorldObject(obj); + grid->AddWorldObject(cell.CellX(), cell.CellY(), obj); AddWorldObject(obj); } else { - grid.AddGridObject(obj); + grid->AddGridObject(cell.CellX(), cell.CellY(), obj); RemoveWorldObject(obj); } } @@ -436,78 +265,81 @@ void Map::DeleteFromWorld(Player* player) delete player; } -void Map::EnsureGridCreated(const GridCoord& p) -{ - if (getNGrid(p.x_coord, p.y_coord)) // pussywizard - return; - std::lock_guard guard(GridLock); - EnsureGridCreated_i(p); -} - -//Create NGrid so the object can be added to it -//But object data is not loaded here -void Map::EnsureGridCreated_i(const GridCoord& p) +void Map::EnsureGridCreated(GridCoord const& gridCoord) { - if (!getNGrid(p.x_coord, p.y_coord)) - { - // pussywizard: moved setNGrid to the end of the function - NGridType* ngt = new NGridType(p.x_coord * MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord); - - // build a linkage between this map and NGridType - buildNGridLinkage(ngt); // pussywizard: getNGrid(x, y) changed to: ngt - - //z coord - int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; - int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; - - if (!GridMaps[gx][gy]) - { - LoadMapAndVMap(gx, gy); - } - - // pussywizard: moved here - setNGrid(ngt, p.x_coord, p.y_coord); - } + _mapGridManager.CreateGrid(gridCoord.x_coord, gridCoord.y_coord); } -//Create NGrid and load the object data in it -bool Map::EnsureGridLoaded(const Cell& cell) +bool Map::EnsureGridLoaded(Cell const& cell) { EnsureGridCreated(GridCoord(cell.GridX(), cell.GridY())); - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - ASSERT(grid); - if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) + if (_mapGridManager.LoadGrid(cell.GridX(), cell.GridY())) { - //if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) - //{ - LOG_DEBUG("maps", "Loading grid[{}, {}] for map {} instance {}", cell.GridX(), cell.GridY(), GetId(), i_InstanceId); - - setGridObjectDataLoaded(true, cell.GridX(), cell.GridY()); - - ObjectGridLoader loader(*grid, this, cell); - loader.LoadN(); - Balance(); return true; - //} } return false; } +MapGridType* Map::GetMapGrid(uint16 const x, uint16 const y) +{ + return _mapGridManager.GetGrid(x, y); +} + +bool Map::IsGridLoaded(GridCoord const& gridCoord) const +{ + return _mapGridManager.IsGridLoaded(gridCoord.x_coord, gridCoord.y_coord); +} + +bool Map::IsGridCreated(GridCoord const& gridCoord) const +{ + return _mapGridManager.IsGridCreated(gridCoord.x_coord, gridCoord.y_coord); +} + void Map::LoadGrid(float x, float y) { EnsureGridLoaded(Cell(x, y)); } -void Map::LoadAllCells() +void Map::LoadAllGrids() { for (uint32 cellX = 0; cellX < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellX++) for (uint32 cellY = 0; cellY < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellY++) LoadGrid((cellX + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL, (cellY + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL); } +void Map::LoadGridsInRange(Position const& center, float radius) +{ + if (_mapGridManager.IsGridsFullyLoaded()) + return; + + float const x = center.GetPositionX(); + float const y = center.GetPositionY(); + + CellCoord cellCoord(Acore::ComputeCellCoord(x, y)); + if (!cellCoord.IsCoordValid()) + return; + + if (radius > SIZE_OF_GRIDS) + radius = SIZE_OF_GRIDS; + + CellArea area = Cell::CalculateCellArea(x, y, radius); + if (!area) + return; + + for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x) + { + for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y) + { + CellCoord cellCoord(x, y); + Cell cell(cellCoord); + EnsureGridLoaded(cell); + } + } +} + bool Map::AddPlayerToMap(Player* player) { CellCoord cellCoord = Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()); @@ -519,7 +351,7 @@ bool Map::AddPlayerToMap(Player* player) } Cell cell(cellCoord); - EnsureGridLoaded(cell); + LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE); AddToGrid(player, cell); // Check if we are adding to correct map @@ -660,11 +492,6 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/) return true; } -bool Map::IsGridLoaded(const GridCoord& p) const -{ - return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); -} - void Map::VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor& gridVisitor, TypeContainerVisitor& worldVisitor, TypeContainerVisitor& largeGridVisitor, @@ -725,7 +552,6 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor visitor(worker); - ngrid.VisitAllGrids(visitor); - } - - RemoveAllObjectsInRemoveList(); - - { - ObjectGridUnloader worker; - TypeContainerVisitor visitor(worker); - ngrid.VisitAllGrids(visitor); - } + _mapGridManager.UnloadGrid(grid.GetX(), grid.GetY()); ASSERT(i_objectsToRemove.empty()); - - delete &ngrid; - setNGrid(nullptr, x, y); - - int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; - int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; - - if (i_InstanceId == 0) - { - if (GridMaps[gx][gy]) - { - GridMaps[gx][gy]->unloadData(); - delete GridMaps[gx][gy]; - } - // x and y are swapped - VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(GetId(), gx, gy); - MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(GetId(), gx, gy); - } - - GridMaps[gx][gy] = nullptr; - - LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {} finished", x, y, GetId()); + LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {} finished", grid.GetX(), grid.GetY(), GetId()); return true; } @@ -1304,9 +1092,9 @@ void Map::UnloadAll() _creaturesToMove.clear(); _gameObjectsToMove.clear(); - for (GridRefMgr::iterator i = GridRefMgr::begin(); i != GridRefMgr::end();) + for (GridRefMgr::iterator i = GridRefMgr::begin(); i != GridRefMgr::end();) { - NGridType& grid(*i->GetSource()); + MapGridType& grid(*i->GetSource()); ++i; UnloadGrid(grid); // deletes the grid and removes it from the GridRefMgr } @@ -1341,696 +1129,45 @@ void Map::UnloadAll() _corpseBones.clear(); } -// ***************************** -// Grid function -// ***************************** -GridMap::GridMap() -{ - _flags = 0; - // Area data - _gridArea = 0; - _areaMap = nullptr; - // Height level data - _gridHeight = INVALID_HEIGHT; - _gridGetHeight = &GridMap::getHeightFromFlat; - _gridIntHeightMultiplier = 0; - m_V9 = nullptr; - m_V8 = nullptr; - _maxHeight = nullptr; - _minHeight = nullptr; - // Liquid data - _liquidGlobalEntry = 0; - _liquidGlobalFlags = 0; - _liquidOffX = 0; - _liquidOffY = 0; - _liquidWidth = 0; - _liquidHeight = 0; - _liquidLevel = INVALID_HEIGHT; - _liquidEntry = nullptr; - _liquidFlags = nullptr; - _liquidMap = nullptr; - _holes = nullptr; -} - -GridMap::~GridMap() -{ - unloadData(); -} - -bool GridMap::loadData(char* filename) -{ - // Unload old data if exist - unloadData(); - - map_fileheader header; - // Not return error if file not found - FILE* in = fopen(filename, "rb"); - if (!in) - return true; - - if (fread(&header, sizeof(header), 1, in) != 1) - { - fclose(in); - return false; - } - - if (header.mapMagic == MapMagic.asUInt && header.versionMagic == MapVersionMagic) - { - // loadup area data - if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) - { - LOG_ERROR("maps", "Error loading map area data\n"); - fclose(in); - return false; - } - // loadup height data - if (header.heightMapOffset && !loadHeightData(in, header.heightMapOffset, header.heightMapSize)) - { - LOG_ERROR("maps", "Error loading map height data\n"); - fclose(in); - return false; - } - // loadup liquid data - if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize)) - { - LOG_ERROR("maps", "Error loading map liquids data\n"); - fclose(in); - return false; - } - // loadup holes data (if any. check header.holesOffset) - if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize)) - { - LOG_ERROR("maps", "Error loading map holes data\n"); - fclose(in); - return false; - } - fclose(in); - return true; - } - LOG_ERROR("maps", "Map file '{}' is from an incompatible clientversion. Please recreate using the mapextractor.", filename); - fclose(in); - return false; -} - -void GridMap::unloadData() +std::shared_ptr Map::GetGridTerrainDataSharedPtr(GridCoord const& gridCoord) { - delete[] _areaMap; - delete[] m_V9; - delete[] m_V8; - delete[] _maxHeight; - delete[] _minHeight; - delete[] _liquidEntry; - delete[] _liquidFlags; - delete[] _liquidMap; - delete[] _holes; - _areaMap = nullptr; - m_V9 = nullptr; - m_V8 = nullptr; - _maxHeight = nullptr; - _minHeight = nullptr; - _liquidEntry = nullptr; - _liquidFlags = nullptr; - _liquidMap = nullptr; - _holes = nullptr; - _gridGetHeight = &GridMap::getHeightFromFlat; + // ensure GridMap is created + EnsureGridCreated(gridCoord); + return _mapGridManager.GetGrid(gridCoord.x_coord, gridCoord.y_coord)->GetTerrainDataSharedPtr(); } -bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/) +GridTerrainData* Map::GetGridTerrainData(GridCoord const& gridCoord) { - map_areaHeader header; - fseek(in, offset, SEEK_SET); - - if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapAreaMagic.asUInt) - return false; - - _gridArea = header.gridArea; - if (!(header.flags & MAP_AREA_NO_AREA)) - { - _areaMap = new uint16 [16 * 16]; - if (fread(_areaMap, sizeof(uint16), 16 * 16, in) != 16 * 16) - return false; - } - return true; -} - -bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) -{ - map_heightHeader header; - fseek(in, offset, SEEK_SET); - - if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapHeightMagic.asUInt) - return false; - - _gridHeight = header.gridHeight; - if (!(header.flags & MAP_HEIGHT_NO_HEIGHT)) - { - if ((header.flags & MAP_HEIGHT_AS_INT16)) - { - m_uint16_V9 = new uint16 [129 * 129]; - m_uint16_V8 = new uint16 [128 * 128]; - if (fread(m_uint16_V9, sizeof(uint16), 129 * 129, in) != 129 * 129 || - fread(m_uint16_V8, sizeof(uint16), 128 * 128, in) != 128 * 128) - return false; - _gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; - _gridGetHeight = &GridMap::getHeightFromUint16; - } - else if ((header.flags & MAP_HEIGHT_AS_INT8)) - { - m_uint8_V9 = new uint8 [129 * 129]; - m_uint8_V8 = new uint8 [128 * 128]; - if (fread(m_uint8_V9, sizeof(uint8), 129 * 129, in) != 129 * 129 || - fread(m_uint8_V8, sizeof(uint8), 128 * 128, in) != 128 * 128) - return false; - _gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255; - _gridGetHeight = &GridMap::getHeightFromUint8; - } - else - { - m_V9 = new float [129 * 129]; - m_V8 = new float [128 * 128]; - if (fread(m_V9, sizeof(float), 129 * 129, in) != 129 * 129 || - fread(m_V8, sizeof(float), 128 * 128, in) != 128 * 128) - return false; - _gridGetHeight = &GridMap::getHeightFromFloat; - } - } - else - _gridGetHeight = &GridMap::getHeightFromFlat; - - if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) - { - _maxHeight = new int16[3 * 3]; - _minHeight = new int16[3 * 3]; - if (fread(_maxHeight, sizeof(int16), 3 * 3, in) != 3 * 3 || - fread(_minHeight, sizeof(int16), 3 * 3, in) != 3 * 3) - return false; - } - - return true; -} - -bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/) -{ - map_liquidHeader header; - fseek(in, offset, SEEK_SET); - - if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapLiquidMagic.asUInt) - return false; - - _liquidGlobalEntry = header.liquidType; - _liquidGlobalFlags = header.liquidFlags; - _liquidOffX = header.offsetX; - _liquidOffY = header.offsetY; - _liquidWidth = header.width; - _liquidHeight = header.height; - _liquidLevel = header.liquidLevel; - - if (!(header.flags & MAP_LIQUID_NO_TYPE)) - { - _liquidEntry = new uint16[16 * 16]; - if (fread(_liquidEntry, sizeof(uint16), 16 * 16, in) != 16 * 16) - return false; - - _liquidFlags = new uint8[16 * 16]; - if (fread(_liquidFlags, sizeof(uint8), 16 * 16, in) != 16 * 16) - return false; - } - if (!(header.flags & MAP_LIQUID_NO_HEIGHT)) - { - _liquidMap = new float[uint32(_liquidWidth) * uint32(_liquidHeight)]; - if (fread(_liquidMap, sizeof(float), _liquidWidth * _liquidHeight, in) != (uint32(_liquidWidth) * uint32(_liquidHeight))) - return false; - } - return true; -} - -bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 /*size*/) -{ - if (fseek(in, offset, SEEK_SET) != 0) - return false; - - _holes = new uint16[16 * 16]; - if (fread(_holes, sizeof(uint16), 16 * 16, in) != 16 * 16) - return false; - - return true; -} - -uint16 GridMap::getArea(float x, float y) const -{ - if (!_areaMap) - return _gridArea; - - x = 16 * (32 - x / SIZE_OF_GRIDS); - y = 16 * (32 - y / SIZE_OF_GRIDS); - int lx = (int)x & 15; - int ly = (int)y & 15; - return _areaMap[lx * 16 + ly]; -} - -float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const -{ - return _gridHeight; -} - -float GridMap::getHeightFromFloat(float x, float y) const -{ - if (!m_V8 || !m_V9) - return _gridHeight; - - x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); - - int x_int = (int)x; - int y_int = (int)y; - x -= x_int; - y -= y_int; - x_int &= (MAP_RESOLUTION - 1); - y_int &= (MAP_RESOLUTION - 1); - - if (isHole(x_int, y_int)) - return INVALID_HEIGHT; - - // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid - // +--------------> X - // | h1-------h2 Coordinates is: - // | | \ 1 / | h1 0, 0 - // | | \ / | h2 0, 1 - // | | 2 h5 3 | h3 1, 0 - // | | / \ | h4 1, 1 - // | | / 4 \ | h5 1/2, 1/2 - // | h3-------h4 - // V Y - // For find height need - // 1 - detect triangle - // 2 - solve linear equation from triangle points - // Calculate coefficients for solve h = a*x + b*y + c - - float a, b, c; - // Select triangle: - if (x + y < 1) - { - if (x > y) - { - // 1 triangle (h1, h2, h5 points) - float h1 = m_V9[(x_int) * 129 + y_int]; - float h2 = m_V9[(x_int + 1) * 129 + y_int]; - float h5 = 2 * m_V8[x_int * 128 + y_int]; - a = h2 - h1; - b = h5 - h1 - h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - float h1 = m_V9[x_int * 129 + y_int ]; - float h3 = m_V9[x_int * 129 + y_int + 1]; - float h5 = 2 * m_V8[x_int * 128 + y_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (x > y) - { - // 3 triangle (h2, h4, h5 points) - float h2 = m_V9[(x_int + 1) * 129 + y_int ]; - float h4 = m_V9[(x_int + 1) * 129 + y_int + 1]; - float h5 = 2 * m_V8[x_int * 128 + y_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - float h3 = m_V9[(x_int) * 129 + y_int + 1]; - float h4 = m_V9[(x_int + 1) * 129 + y_int + 1]; - float h5 = 2 * m_V8[x_int * 128 + y_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - return a * x + b * y + c; -} - -float GridMap::getHeightFromUint8(float x, float y) const -{ - if (!m_uint8_V8 || !m_uint8_V9) - return _gridHeight; - - x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); - - int x_int = (int)x; - int y_int = (int)y; - x -= x_int; - y -= y_int; - x_int &= (MAP_RESOLUTION - 1); - y_int &= (MAP_RESOLUTION - 1); - - if (isHole(x_int, y_int)) - return INVALID_HEIGHT; - - int32 a, b, c; - uint8* V9_h1_ptr = &m_uint8_V9[x_int * 128 + x_int + y_int]; - if (x + y < 1) - { - if (x > y) - { - // 1 triangle (h1, h2, h5 points) - int32 h1 = V9_h1_ptr[ 0]; - int32 h2 = V9_h1_ptr[129]; - int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int]; - a = h2 - h1; - b = h5 - h1 - h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - int32 h1 = V9_h1_ptr[0]; - int32 h3 = V9_h1_ptr[1]; - int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (x > y) - { - // 3 triangle (h2, h4, h5 points) - int32 h2 = V9_h1_ptr[129]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - int32 h3 = V9_h1_ptr[ 1]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - return (float)((a * x) + (b * y) + c) * _gridIntHeightMultiplier + _gridHeight; -} - -float GridMap::getHeightFromUint16(float x, float y) const -{ - if (!m_uint16_V8 || !m_uint16_V9) - return _gridHeight; - - x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); - - int x_int = (int)x; - int y_int = (int)y; - x -= x_int; - y -= y_int; - x_int &= (MAP_RESOLUTION - 1); - y_int &= (MAP_RESOLUTION - 1); - - if (isHole(x_int, y_int)) - return INVALID_HEIGHT; - - int32 a, b, c; - uint16* V9_h1_ptr = &m_uint16_V9[x_int * 128 + x_int + y_int]; - if (x + y < 1) - { - if (x > y) - { - // 1 triangle (h1, h2, h5 points) - int32 h1 = V9_h1_ptr[ 0]; - int32 h2 = V9_h1_ptr[129]; - int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int]; - a = h2 - h1; - b = h5 - h1 - h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - int32 h1 = V9_h1_ptr[0]; - int32 h3 = V9_h1_ptr[1]; - int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (x > y) - { - // 3 triangle (h2, h4, h5 points) - int32 h2 = V9_h1_ptr[129]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - int32 h3 = V9_h1_ptr[ 1]; - int32 h4 = V9_h1_ptr[130]; - int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - return (float)((a * x) + (b * y) + c) * _gridIntHeightMultiplier + _gridHeight; -} - -bool GridMap::isHole(int row, int col) const -{ - if (!_holes) - return false; - - int cellRow = row / 8; // 8 squares per cell - int cellCol = col / 8; - int holeRow = row % 8 / 2; - int holeCol = (col - (cellCol * 8)) / 2; - - uint16 hole = _holes[cellRow * 16 + cellCol]; - - return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0; -} - -float GridMap::getMinHeight(float x, float y) const -{ - if (!_minHeight) - return -500.0f; - - static uint32 const indices[] = - { - 3, 0, 4, - 0, 1, 4, - 1, 2, 4, - 2, 5, 4, - 5, 8, 4, - 8, 7, 4, - 7, 6, 4, - 6, 3, 4 - }; - - static float const boundGridCoords[] = - { - 0.0f, 0.0f, - 0.0f, -266.66666f, - 0.0f, -533.33331f, - -266.66666f, 0.0f, - -266.66666f, -266.66666f, - -266.66666f, -533.33331f, - -533.33331f, 0.0f, - -533.33331f, -266.66666f, - -533.33331f, -533.33331f - }; - - Cell cell(x, y); - float gx = x - (int32(cell.GridX()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; - float gy = y - (int32(cell.GridY()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; - - uint32 quarterIndex = 0; - if (cell.CellY() < MAX_NUMBER_OF_CELLS / 2) - { - if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2) - { - quarterIndex = 4 + (gy > gx); - } - else - quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy); - } - else if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2) - { - quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy); - } - else - quarterIndex = gx > gy; - - quarterIndex *= 3; - - return G3D::Plane( - G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], _minHeight[indices[quarterIndex + 0]]), - G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], _minHeight[indices[quarterIndex + 1]]), - G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], _minHeight[indices[quarterIndex + 2]]) - ).distance(G3D::Vector3(gx, gy, 0.0f)); -} - -float GridMap::getLiquidLevel(float x, float y) const -{ - if (!_liquidMap) - return _liquidLevel; - - x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); - - int cx_int = ((int)x & (MAP_RESOLUTION - 1)) - _liquidOffY; - int cy_int = ((int)y & (MAP_RESOLUTION - 1)) - _liquidOffX; - - if (cx_int < 0 || cx_int >= _liquidHeight) - return INVALID_HEIGHT; - if (cy_int < 0 || cy_int >= _liquidWidth) - return INVALID_HEIGHT; - - return _liquidMap[cx_int * _liquidWidth + cy_int]; -} - -// Get water state on map -inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const -{ - LiquidData liquidData; - - // Check water type (if no water return) - if (_liquidGlobalFlags || _liquidFlags) - { - // Get cell - float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS); - float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS); - - int x_int = (int) cx & (MAP_RESOLUTION - 1); - int y_int = (int) cy & (MAP_RESOLUTION - 1); - - // Check water type in cell - int idx=(x_int>>3)*16 + (y_int>>3); - uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidGlobalFlags; - uint32 entry = _liquidEntry ? _liquidEntry[idx] : _liquidGlobalEntry; - if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry)) - { - type &= MAP_LIQUID_TYPE_DARK_WATER; - uint32 liqTypeIdx = liquidEntry->Type; - if (entry < 21) - { - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) - { - uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; - if (!overrideLiquid && area->zone) - { - area = sAreaTableStore.LookupEntry(area->zone); - if (area) - overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; - } - - if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) - { - entry = overrideLiquid; - liqTypeIdx = liq->Type; - } - } - } - - type |= 1 << liqTypeIdx; - } - - // Check req liquid type mask - if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0)) - { - // Check water level: - // Check water height map - int lx_int = x_int - _liquidOffY; - int ly_int = y_int - _liquidOffX; - if (lx_int >= 0 && lx_int < _liquidHeight && ly_int >= 0 && ly_int < _liquidWidth) - { - // Get water level - float liquid_level = _liquidMap ? _liquidMap[lx_int * _liquidWidth + ly_int] : _liquidLevel; - // Get ground level - float ground_level = getHeight(x, y); - - // Check water level and ground level (sub 0.2 for fix some errors) - if (liquid_level >= ground_level && z >= ground_level - 0.2f) - { - // All ok in water -> store data - liquidData.Entry = entry; - liquidData.Flags = type; - liquidData.Level = liquid_level; - liquidData.DepthLevel = ground_level; - - // For speed check as int values - float delta = liquid_level - z; - - if (delta > collisionHeight) - liquidData.Status = LIQUID_MAP_UNDER_WATER; - else if (delta > 0.0f) - liquidData.Status = LIQUID_MAP_IN_WATER; - else if (delta > -0.1f) - liquidData.Status = LIQUID_MAP_WATER_WALK; - else - liquidData.Status = LIQUID_MAP_ABOVE_WATER; - } - } - } - } + if (!MapGridManager::IsValidGridCoordinates(gridCoord.x_coord, gridCoord.y_coord)) + return nullptr; - return liquidData; + // ensure GridMap is created + EnsureGridCreated(gridCoord); + return _mapGridManager.GetGrid(gridCoord.x_coord, gridCoord.y_coord)->GetTerrainData(); } -GridMap* Map::GetGrid(float x, float y) +GridTerrainData* Map::GetGridTerrainData(float x, float y) { - // half opt method - int gx = (int)(32 - x / SIZE_OF_GRIDS); //grid x - int gy = (int)(32 - y / SIZE_OF_GRIDS); //grid y - - // ensure GridMap is loaded - EnsureGridCreated(GridCoord(63 - gx, 63 - gy)); - - return GridMaps[gx][gy]; + GridCoord const gridCoord = Acore::ComputeGridCoord(x, y); + return GetGridTerrainData(gridCoord); } float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/, float collisionHeight) const { - if (const_cast(this)->GetGrid(x, y)) - { - // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(phasemask, x, y, z + Z_OFFSET_FIND_HEIGHT, true, 50.0f); - if (ground) - *ground = ground_z; + // we need ground level (including grid height version) for proper return water level in point + float ground_z = GetHeight(phasemask, x, y, z + Z_OFFSET_FIND_HEIGHT, true, 50.0f); + if (ground) + *ground = ground_z; - LiquidData const& liquidData = const_cast(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS); - switch (liquidData.Status) - { - case LIQUID_MAP_ABOVE_WATER: - return std::max(liquidData.Level, ground_z); - case LIQUID_MAP_NO_WATER: - return ground_z; - default: - return liquidData.Level; - } + LiquidData const& liquidData = const_cast(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS); + switch (liquidData.Status) + { + case LIQUID_MAP_ABOVE_WATER: + return std::max(liquidData.Level, ground_z); + case LIQUID_MAP_NO_WATER: + return ground_z; + default: + return liquidData.Level; } return VMAP_INVALID_HEIGHT_VALUE; @@ -2102,18 +1239,18 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float float Map::GetGridHeight(float x, float y) const { - if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + if (GridTerrainData* gmap = const_cast(this)->GetGridTerrainData(x, y)) return gmap->getHeight(x, y); - return VMAP_INVALID_HEIGHT_VALUE; + return INVALID_HEIGHT; } float Map::GetMinHeight(float x, float y) const { - if (GridMap const* grid = const_cast(this)->GetGrid(x, y)) + if (GridTerrainData const* grid = const_cast(this)->GetGridTerrainData(x, y)) return grid->getMinHeight(x, y); - return -500.0f; + return MIN_HEIGHT; } static inline bool IsInWMOInterior(uint32 mogpFlags) @@ -2156,7 +1293,7 @@ bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags if (hasVmapAreaInfo || hasDynamicAreaInfo) { // check if there's terrain between player height and object height - if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + if (GridTerrainData* gmap = const_cast(this)->GetGridTerrainData(x, y)) { float mapHeight = gmap->getHeight(x, y); // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice... @@ -2179,7 +1316,7 @@ uint32 Map::GetAreaId(uint32 phaseMask, float x, float y, float z) const uint32 gridAreaId = 0; float gridMapHeight = INVALID_HEIGHT; - if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + if (GridTerrainData* gmap = const_cast(this)->GetGridTerrainData(x, y)) { gridAreaId = gmap->getArea(x, y); gridMapHeight = gmap->getHeight(x, y); @@ -2290,7 +1427,7 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, if (useGridLiquid) { - if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + if (GridTerrainData* gmap = const_cast(this)->GetGridTerrainData(x, y)) { LiquidData const& map_data = gmap->GetLiquidData(x, y, z, collisionHeight, ReqLiquidType); // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: @@ -2312,7 +1449,7 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType) { - GridMap* gmap = GetGrid(x, y); + GridTerrainData* gmap = GetGridTerrainData(x, y); VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); VMAP::AreaAndLiquidData vmapData; @@ -2455,10 +1592,10 @@ void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y float Map::GetWaterLevel(float x, float y) const { - if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + if (GridTerrainData* gmap = const_cast(this)->GetGridTerrainData(x, y)) return gmap->getLiquidLevel(x, y); - else - return 0; + + return INVALID_HEIGHT; } bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const @@ -2625,16 +1762,6 @@ void Map::SendRemoveTransports(Player* player) player->GetSession()->SendPacket(&packet); } -inline void Map::setNGrid(NGridType* grid, uint32 x, uint32 y) -{ - if (x >= MAX_NUMBER_OF_GRIDS || y >= MAX_NUMBER_OF_GRIDS) - { - LOG_ERROR("maps", "map::setNGrid() Invalid grid coordinates found: {}, {}!", x, y); - ABORT(); - } - i_grids[x][y] = grid; -} - void Map::SendObjectUpdates() { UpdateDataMapType update_players; @@ -3717,7 +2844,7 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const ownerGuid, bool insignia /*= // ignore bones creating option in case insignia if ((insignia || (IsBattlegroundOrArena() ? sWorld->getBoolConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld->getBoolConfig(CONFIG_DEATH_BONES_WORLD))) && - !IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY())) + !IsGridCreated(corpse->GetPositionX(), corpse->GetPositionY())) { // Create bones, don't change Corpse bones = new Corpse(); @@ -4139,6 +3266,26 @@ std::string Map::GetDebugInfo() const return sstr.str(); } +uint32 Map::GetCreatedGridsCount() +{ + return _mapGridManager.GetCreatedGridsCount(); +} + +uint32 Map::GetLoadedGridsCount() +{ + return _mapGridManager.GetLoadedGridsCount(); +} + +uint32 Map::GetCreatedCellsInGridCount(uint16 const x, uint16 const y) +{ + return _mapGridManager.GetCreatedCellsInGridCount(x, y); +} + +uint32 Map::GetCreatedCellsInMapCount() +{ + return _mapGridManager.GetCreatedCellsInMapCount(); +} + std::string InstanceMap::GetDebugInfo() const { std::stringstream sstr; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 54f8d7c2cd4115..33bb8238d6a9a9 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -26,6 +26,7 @@ #include "GameObjectModel.h" #include "GridDefines.h" #include "GridRefMgr.h" +#include "MapGridManager.h" #include "MapRefMgr.h" #include "ObjectDefines.h" #include "ObjectGuid.h" @@ -33,6 +34,7 @@ #include "Position.h" #include "SharedDefines.h" #include "TaskScheduler.h" +#include "GridTerrainData.h" #include #include #include @@ -81,101 +83,9 @@ struct ScriptAction ScriptInfo const* script; // pointer to static script data }; -// ****************************************** -// Map file format defines -// ****************************************** -struct map_fileheader -{ - uint32 mapMagic; - uint32 versionMagic; - uint32 buildMagic; - uint32 areaMapOffset; - uint32 areaMapSize; - uint32 heightMapOffset; - uint32 heightMapSize; - uint32 liquidMapOffset; - uint32 liquidMapSize; - uint32 holesOffset; - uint32 holesSize; -}; - -#define MAP_AREA_NO_AREA 0x0001 - -struct map_areaHeader -{ - uint32 fourcc; - uint16 flags; - uint16 gridArea; -}; - -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 -#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 - -struct map_heightHeader -{ - uint32 fourcc; - uint32 flags; - float gridHeight; - float gridMaxHeight; -}; - -#define MAP_LIQUID_NO_TYPE 0x0001 -#define MAP_LIQUID_NO_HEIGHT 0x0002 - -struct map_liquidHeader -{ - uint32 fourcc; - uint8 flags; - uint8 liquidFlags; - uint16 liquidType; - uint8 offsetX; - uint8 offsetY; - uint8 width; - uint8 height; - float liquidLevel; -}; - -enum LiquidStatus -{ - LIQUID_MAP_NO_WATER = 0x00000000, - LIQUID_MAP_ABOVE_WATER = 0x00000001, - LIQUID_MAP_WATER_WALK = 0x00000002, - LIQUID_MAP_IN_WATER = 0x00000004, - LIQUID_MAP_UNDER_WATER = 0x00000008 -}; - -#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER) -#define MAP_LIQUID_STATUS_IN_CONTACT (MAP_LIQUID_STATUS_SWIMMING | LIQUID_MAP_WATER_WALK) - -#define MAP_LIQUID_TYPE_NO_WATER 0x00 -#define MAP_LIQUID_TYPE_WATER 0x01 -#define MAP_LIQUID_TYPE_OCEAN 0x02 -#define MAP_LIQUID_TYPE_MAGMA 0x04 -#define MAP_LIQUID_TYPE_SLIME 0x08 - -#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME) - -#define MAP_LIQUID_TYPE_DARK_WATER 0x10 - -#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface -#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE -#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT #define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations #define MIN_UNLOAD_DELAY 1 // immediate unload -struct LiquidData -{ - LiquidData() = default; - - uint32 Entry{0}; - uint32 Flags{0}; - float Level{INVALID_HEIGHT}; - float DepthLevel{INVALID_HEIGHT}; - LiquidStatus Status{LIQUID_MAP_NO_WATER}; -}; - struct PositionFullTerrainStatus { PositionFullTerrainStatus() = default; @@ -196,71 +106,6 @@ enum LineOfSightChecks LINEOFSIGHT_ALL_CHECKS = LINEOFSIGHT_CHECK_VMAP | LINEOFSIGHT_CHECK_GOBJECT_ALL }; -class GridMap -{ - uint32 _flags; - union - { - float* m_V9; - uint16* m_uint16_V9; - uint8* m_uint8_V9; - }; - union - { - float* m_V8; - uint16* m_uint16_V8; - uint8* m_uint8_V8; - }; - int16* _maxHeight; - int16* _minHeight; - // Height level data - float _gridHeight; - float _gridIntHeightMultiplier; - - // Area data - uint16* _areaMap; - - // Liquid data - float _liquidLevel; - uint16* _liquidEntry; - uint8* _liquidFlags; - float* _liquidMap; - uint16 _gridArea; - uint16 _liquidGlobalEntry; - uint8 _liquidGlobalFlags; - uint8 _liquidOffX; - uint8 _liquidOffY; - uint8 _liquidWidth; - uint8 _liquidHeight; - uint16* _holes; - - bool loadAreaData(FILE* in, uint32 offset, uint32 size); - bool loadHeightData(FILE* in, uint32 offset, uint32 size); - bool loadLiquidData(FILE* in, uint32 offset, uint32 size); - bool loadHolesData(FILE* in, uint32 offset, uint32 size); - [[nodiscard]] bool isHole(int row, int col) const; - - // Get height functions and pointers - typedef float (GridMap::*GetHeightPtr) (float x, float y) const; - GetHeightPtr _gridGetHeight; - [[nodiscard]] float getHeightFromFloat(float x, float y) const; - [[nodiscard]] float getHeightFromUint16(float x, float y) const; - [[nodiscard]] float getHeightFromUint8(float x, float y) const; - [[nodiscard]] float getHeightFromFlat(float x, float y) const; - -public: - GridMap(); - ~GridMap(); - bool loadData(char* filaname); - void unloadData(); - - [[nodiscard]] uint16 getArea(float x, float y) const; - [[nodiscard]] inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} - [[nodiscard]] float getMinHeight(float x, float y) const; - [[nodiscard]] float getLiquidLevel(float x, float y) const; - [[nodiscard]] LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const; -}; - // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform #if defined(__GNUC__) #pragma pack(1) @@ -307,9 +152,10 @@ enum EncounterCreditType : uint8 ENCOUNTER_CREDIT_CAST_SPELL = 1, }; -class Map : public GridRefMgr +class Map : public GridRefMgr { friend class MapReference; + friend class GridObjectLoader; public: Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr); ~Map() override; @@ -348,6 +194,7 @@ class Map : public GridRefMgr [[nodiscard]] float GetVisibilityRange() const { return m_VisibleDistance; } void SetVisibilityRange(float range) { m_VisibleDistance = range; } + void OnCreateMap(); //function for setting up visibility distance for maps on per-type/per-Id basis virtual void InitVisibilityDistance(); @@ -358,26 +205,28 @@ class Map : public GridRefMgr template void Visit(const Cell& cell, TypeContainerVisitor& visitor); - [[nodiscard]] bool IsRemovalGrid(float x, float y) const + bool IsGridLoaded(GridCoord const& gridCoord) const; + bool IsGridLoaded(float x, float y) const { - GridCoord p = Acore::ComputeGridCoord(x, y); - return !getNGrid(p.x_coord, p.y_coord); + return IsGridLoaded(Acore::ComputeGridCoord(x, y)); } - - [[nodiscard]] bool IsGridLoaded(float x, float y) const + bool IsGridCreated(GridCoord const& gridCoord) const; + bool IsGridCreated(float x, float y) const { - return IsGridLoaded(Acore::ComputeGridCoord(x, y)); + return IsGridCreated(Acore::ComputeGridCoord(x, y)); } void LoadGrid(float x, float y); - void LoadAllCells(); - bool UnloadGrid(NGridType& ngrid); + void LoadAllGrids(); + void LoadGridsInRange(Position const& center, float radius); + bool UnloadGrid(MapGridType& grid); virtual void UnloadAll(); - [[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; } + std::shared_ptr GetGridTerrainDataSharedPtr(GridCoord const& gridCoord); + GridTerrainData* GetGridTerrainData(GridCoord const& gridCoord); + GridTerrainData* GetGridTerrainData(float x, float y); - static bool ExistMap(uint32 mapid, int gx, int gy); - static bool ExistVMap(uint32 mapid, int gx, int gy); + [[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; } [[nodiscard]] Map const* GetParent() const { return m_parentMap; } @@ -627,8 +476,7 @@ class Map : public GridRefMgr // Do whatever you want to all the players in map [including GameMasters], i.e.: param exec = [&](Player* p) { p->Whatever(); } void DoForAllPlayers(std::function exec); - GridMap* GetGrid(float x, float y); - void EnsureGridCreated(const GridCoord&); + void EnsureGridCreated(GridCoord const& gridCoord); [[nodiscard]] bool AllTransportsEmpty() const; // pussywizard void AllTransportsRemovePassengers(); // pussywizard [[nodiscard]] TransportsContainer const& GetAllTransports() const { return _transports; } @@ -659,13 +507,12 @@ class Map : public GridRefMgr virtual std::string GetDebugInfo() const; -private: - void LoadMapAndVMap(int gx, int gy); - void LoadVMap(int gx, int gy); - void LoadMap(int gx, int gy, bool reload = false); + uint32 GetCreatedGridsCount(); + uint32 GetLoadedGridsCount(); + uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y); + uint32 GetCreatedCellsInMapCount(); - // Load MMap Data - void LoadMMap(int gx, int gy); +private: template void InitializeObject(T* obj); void AddCreatureToMoveList(Creature* c); @@ -679,33 +526,22 @@ class Map : public GridRefMgr std::vector _gameObjectsToMove; std::vector _dynamicObjectsToMove; - [[nodiscard]] bool IsGridLoaded(const GridCoord&) const; - void EnsureGridCreated_i(const GridCoord&); + bool EnsureGridLoaded(Cell const& cell); + MapGridType* GetMapGrid(uint16 const x, uint16 const y); - void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } - - [[nodiscard]] NGridType* getNGrid(uint32 x, uint32 y) const - { - ASSERT(x < MAX_NUMBER_OF_GRIDS && y < MAX_NUMBER_OF_GRIDS); - return i_grids[x][y]; - } - - bool EnsureGridLoaded(Cell const&); - [[nodiscard]] bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x, y)->isGridObjectDataLoaded(); } - void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x, y)->setGridObjectDataLoaded(pLoaded); } - - void setNGrid(NGridType* grid, uint32 x, uint32 y); void ScriptsProcess(); - void UpdateActiveCells(const float& x, const float& y, const uint32 t_diff); - void SendObjectUpdates(); protected: + // Type specific code for add/remove to/from grid + template + void AddToGrid(T* object, Cell const& cell); + std::mutex Lock; - std::mutex GridLock; std::shared_mutex MMapLock; + MapGridManager _mapGridManager; MapEntry const* i_mapEntry; uint8 i_spawnMode; uint32 i_InstanceId; @@ -739,10 +575,8 @@ class Map : public GridRefMgr //InstanceMaps and BattlegroundMaps... Map* m_parentMap; - NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; - GridMap* GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; - std::bitset marked_cells; - std::bitset marked_cells_large; + std::bitset marked_cells; + std::bitset marked_cells_large; bool i_scriptLock; std::unordered_set i_objectsToRemove; @@ -752,10 +586,6 @@ class Map : public GridRefMgr typedef std::multimap ScriptScheduleMap; ScriptScheduleMap m_scriptSchedule; - // Type specific code for add/remove to/from grid - template - void AddToGrid(T* object, Cell const& cell); - template void DeleteFromWorld(T*); @@ -875,16 +705,14 @@ class BattlegroundMap : public Map template inline void Map::Visit(Cell const& cell, TypeContainerVisitor& visitor) { - const uint32 x = cell.GridX(); - const uint32 y = cell.GridY(); - const uint32 cell_x = cell.CellX(); - const uint32 cell_y = cell.CellY(); + uint32 const grid_x = cell.GridX(); + uint32 const grid_y = cell.GridY(); - if (!cell.NoCreate() || IsGridLoaded(GridCoord(x, y))) - { - EnsureGridLoaded(cell); - getNGrid(x, y)->VisitGrid(cell_x, cell_y, visitor); - } + // If grid is not loaded, nothing to visit. + if (!IsGridLoaded(GridCoord(grid_x, grid_y))) + return; + + GetMapGrid(grid_x, grid_y)->VisitCell(cell.CellX(), cell.CellY(), visitor); } #endif diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 6566a2a209d764..8b42389e3dd2e8 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -203,6 +203,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, InstanceMap* map = new InstanceMap(GetId(), InstanceId, difficulty, this); ASSERT(map->IsDungeon()); + m_InstancedMaps[InstanceId] = map; map->LoadRespawnTimes(); map->LoadCorpseData(); @@ -212,10 +213,11 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, else map->CreateInstanceScript(false, "", 0); + map->OnCreateMap(); + if (!save) // this is for sure a dungeon (assert above), no need to check here sInstanceSaveMgr->AddInstanceSave(GetId(), InstanceId, difficulty); - m_InstancedMaps[InstanceId] = map; return map; } @@ -237,10 +239,13 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun BattlegroundMap* map = new BattlegroundMap(GetId(), InstanceId, this, spawnMode); ASSERT(map->IsBattlegroundOrArena()); + m_InstancedMaps[InstanceId] = map; + map->SetBG(bg); bg->SetBgMap(map); - m_InstancedMaps[InstanceId] = map; + map->OnCreateMap(); + return map; } diff --git a/src/server/game/Maps/MapMgr.cpp b/src/server/game/Maps/MapMgr.cpp index 3a52e5fe389620..2b1fe2b3b4301d 100644 --- a/src/server/game/Maps/MapMgr.cpp +++ b/src/server/game/Maps/MapMgr.cpp @@ -19,6 +19,7 @@ #include "Chat.h" #include "DatabaseEnv.h" #include "GridDefines.h" +#include "GridTerrainLoader.h" #include "Group.h" #include "InstanceSaveMgr.h" #include "LFGMgr.h" @@ -83,13 +84,17 @@ Map* MapMgr::CreateBaseMap(uint32 id) if (entry->Instanceable()) map = new MapInstanced(id); else - { map = new Map(id, 0, REGULAR_DIFFICULTY); + + i_maps[id] = map; + + if (!entry->Instanceable()) + { map->LoadRespawnTimes(); map->LoadCorpseData(); } - i_maps[id] = map; + map->OnCreateMap(); } } @@ -303,7 +308,7 @@ bool MapMgr::ExistMapAndVMap(uint32 mapid, float x, float y) int gx = 63 - p.x_coord; int gy = 63 - p.y_coord; - return Map::ExistMap(mapid, gx, gy) && Map::ExistVMap(mapid, gx, gy); + return GridTerrainLoader::ExistMap(mapid, gx, gy) && GridTerrainLoader::ExistVMap(mapid, gx, gy); } bool MapMgr::IsValidMAP(uint32 mapid, bool startUp) diff --git a/src/server/game/Maps/MapMgr.h b/src/server/game/Maps/MapMgr.h index 9cf80a9797c51c..2872ddd7c8597b 100644 --- a/src/server/game/Maps/MapMgr.h +++ b/src/server/game/Maps/MapMgr.h @@ -24,6 +24,7 @@ #include "MapInstanced.h" #include "MapUpdater.h" #include "Object.h" +#include "Timer.h" class Transport; class StaticTransport; diff --git a/src/server/game/Movement/Waypoints/WaypointMgr.cpp b/src/server/game/Movement/Waypoints/WaypointMgr.cpp index de437b2cbaa770..7a2596fbf75b67 100644 --- a/src/server/game/Movement/Waypoints/WaypointMgr.cpp +++ b/src/server/game/Movement/Waypoints/WaypointMgr.cpp @@ -20,6 +20,7 @@ #include "GridDefines.h" #include "Log.h" #include "QueryResult.h" +#include "Timer.h" WaypointMgr::WaypointMgr() { diff --git a/src/server/game/Scripting/ScriptDefines/AllMapScript.cpp b/src/server/game/Scripting/ScriptDefines/AllMapScript.cpp index a4390736513f8d..1f8402644ea69d 100644 --- a/src/server/game/Scripting/ScriptDefines/AllMapScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/AllMapScript.cpp @@ -134,10 +134,9 @@ void ScriptMgr::OnDestroyMap(Map* map) }); } -void ScriptMgr::OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy) +void ScriptMgr::OnLoadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy) { ASSERT(map); - ASSERT(gmap); ForeachMaps(map, [&](WorldMapScript* script) @@ -158,7 +157,7 @@ void ScriptMgr::OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy) }); } -void ScriptMgr::OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy) +void ScriptMgr::OnUnloadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy) { ASSERT(map); ASSERT(gmap); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index af4b494902dceb..26159984b2a92f 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -189,8 +189,8 @@ class ScriptMgr public: /* MapScript */ void OnCreateMap(Map* map); void OnDestroyMap(Map* map); - void OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy); - void OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy); + void OnLoadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy); + void OnUnloadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy); void OnPlayerEnterMap(Map* map, Player* player); void OnPlayerLeaveMap(Map* map, Player* player); void OnMapUpdate(Map* map, uint32 diff); diff --git a/src/server/game/Scripting/ScriptObject.h b/src/server/game/Scripting/ScriptObject.h index 1dd8500cdcba54..fe6cb2c12dceea 100644 --- a/src/server/game/Scripting/ScriptObject.h +++ b/src/server/game/Scripting/ScriptObject.h @@ -98,10 +98,10 @@ class MapScript : public UpdatableScript virtual void OnDestroy(TMap* /*map*/) { } // Called when a grid map is loaded. - virtual void OnLoadGridMap(TMap* /*map*/, GridMap* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { } + virtual void OnLoadGridMap(TMap* /*map*/, GridTerrainData* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { } // Called when a grid map is unloaded. - virtual void OnUnloadGridMap(TMap* /*map*/, GridMap* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { } + virtual void OnUnloadGridMap(TMap* /*map*/, GridTerrainData* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { } // Called when a player enters the map. virtual void OnPlayerEnter(TMap* /*map*/, Player* /*player*/) { } diff --git a/src/server/game/Scripting/ScriptObjectFwd.h b/src/server/game/Scripting/ScriptObjectFwd.h index a7a899e02846e7..35f425eae5e8be 100644 --- a/src/server/game/Scripting/ScriptObjectFwd.h +++ b/src/server/game/Scripting/ScriptObjectFwd.h @@ -41,7 +41,7 @@ class CreatureAI; class DynamicObject; class GameObject; class GameObjectAI; -class GridMap; +class GridTerrainData; class Group; class Guardian; class Guild; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c5f72b8090a118..4b766bc218f629 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2160,10 +2160,6 @@ void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* refere x = pos->GetPositionX(); y = pos->GetPositionY(); - CellCoord p(Acore::ComputeCellCoord(x, y)); - Cell cell(p); - cell.SetNoCreate(); - Map* map = referer->GetMap(); if (searchInWorld) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index c4282b1128ce98..80c36b456faf3f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1969,7 +1969,7 @@ void World::SetInitialWorldSettings() if (map) { LOG_INFO("server.loading", ">> Loading All Grids For Map {}", map->GetId()); - map->LoadAllCells(); + map->LoadAllGrids(); } } } diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index a8d767dfdac925..3a48e5d33a00e7 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -104,7 +104,8 @@ class debug_commandscript : public CommandScript { "moveflags", HandleDebugMoveflagsCommand, SEC_ADMINISTRATOR, Console::No }, { "unitstate", HandleDebugUnitStateCommand, SEC_ADMINISTRATOR, Console::No }, { "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes}, - { "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No } + { "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No }, + { "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No } }; static ChatCommandTable commandTable = { @@ -1373,6 +1374,20 @@ class debug_commandscript : public CommandScript handler->SendSysMessage("This command does nothing right now. Edit your local core (cs_debug.cpp) to make it do whatever you need for testing."); return true; } + + static bool HandleDebugMapDataCommand(ChatHandler* handler) + { + Cell cell(handler->GetPlayer()->GetPositionX(), handler->GetPlayer()->GetPositionY()); + Map* map = handler->GetPlayer()->GetMap(); + + handler->PSendSysMessage("GridX {} GridY {}", cell.GridX(), cell.GridY()); + handler->PSendSysMessage("CellX {} CellY {}", cell.CellX(), cell.CellY()); + handler->PSendSysMessage("Created Grids: {} / {}", map->GetCreatedGridsCount(), MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS); + handler->PSendSysMessage("Loaded Grids: {} / {}", map->GetLoadedGridsCount(), MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS); + handler->PSendSysMessage("Created Cells In Grid: {} / {}", map->GetCreatedCellsInGridCount(cell.GridX(), cell.GridY()), MAX_NUMBER_OF_CELLS * MAX_NUMBER_OF_CELLS); + handler->PSendSysMessage("Created Cells In Map: {} / {}", map->GetCreatedCellsInMapCount(), TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP); + return true; + } }; void AddSC_debug_commandscript() diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index cbfc4517c08886..9f7bd95109b873 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -25,6 +25,7 @@ #include "GameGraveyard.h" #include "GameTime.h" #include "GridNotifiers.h" +#include "GridTerrainLoader.h" #include "Group.h" #include "GuildMgr.h" #include "IPLocation.h" @@ -589,8 +590,8 @@ class misc_commandscript : public CommandScript int gridX = 63 - gridCoord.x_coord; int gridY = 63 - gridCoord.y_coord; - uint32 haveMap = Map::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0; - uint32 haveVMap = Map::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0; + uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0; + uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0; uint32 haveMMAP = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()) ? 1 : 0; if (haveVMap) @@ -2404,10 +2405,6 @@ class misc_commandscript : public CommandScript { Player* player = handler->GetSession()->GetPlayer(); - CellCoord p(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY())); - Cell cell(p); - cell.SetNoCreate(); - Acore::RespawnDo u_do; Acore::WorldObjectWorker worker(player, u_do); Cell::VisitGridObjects(player, worker, player->GetGridActivationRange()); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index 1dc1995f4fb831..70bcad38e23aba 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -172,7 +172,6 @@ struct boss_nightbane : public BossAI { if (action == ACTION_START_INTRO) { - me->GetMap()->LoadGrid(-11260.0f, -1771.0f); // load grid at far end of intro path me->GetMap()->SetVisibilityRange(DEFAULT_VISIBILITY_INSTANCE + 100.0f); // see nightbane me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); _phase = PHASE_INTRO; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp b/src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp index d515388871949d..99193ef24c2285 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp @@ -89,8 +89,6 @@ class instance_stratholme : public InstanceMapScript if (_baronRunTime > 0) if (Aura* aura = player->AddAura(SPELL_BARON_ULTIMATUM, player)) aura->SetDuration(_baronRunTime * MINUTE * IN_MILLISECONDS); - if (_barthilasrunProgress == DONE) - instance->LoadGrid(3663.229980f, -3619.139893f); } void OnCreatureCreate(Creature* creature) override @@ -261,7 +259,6 @@ class instance_stratholme : public InstanceMapScript { if (_zigguratState1 == 2 && _zigguratState2 == 2 && _zigguratState3 == 2) { - instance->LoadGrid(4035.83f, -3336.31f); if (Creature* baron = instance->GetCreature(_baronRivendareGUID)) baron->AI()->Talk(SAY_BRAON_ZIGGURAT_FALL_YELL); @@ -301,7 +298,6 @@ class instance_stratholme : public InstanceMapScript DoCastSpellOnPlayers(SPELL_BARON_ULTIMATUM); events.ScheduleEvent(EVENT_BARON_TIME, 60000); - instance->LoadGrid(4035.83f, -3336.31f); if (Creature* baron = instance->GetCreature(_baronRivendareGUID)) baron->AI()->Talk(SAY_BARON_INIT_YELL); } @@ -505,7 +501,6 @@ class instance_stratholme : public InstanceMapScript case EVENT_BARON_TIME: { --_baronRunTime; - instance->LoadGrid(4035.83f, -3336.31f); Creature* baron = instance->GetCreature(_baronRivendareGUID); if (baron && !baron->IsInCombat()) { @@ -536,7 +531,6 @@ class instance_stratholme : public InstanceMapScript } case EVENT_EXECUTE_PRISONER: { - instance->LoadGrid(4035.83f, -3336.31f); Creature* baron = instance->GetCreature(_baronRivendareGUID); if (baron && baron->IsAlive()) { diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp index 5e6524d3d8b7d6..93d9618d0b143e 100644 --- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp +++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp @@ -116,7 +116,6 @@ class instance_sunken_temple : public InstanceMapScript ++_defendersKilled; if (_defendersKilled == DEFENDERS_COUNT) { - instance->LoadGrid(-425.89f, -86.07f); if (Creature* jammal = instance->GetCreature(_jammalanGUID)) jammal->AI()->Talk(0); if (GameObject* forcefield = instance->GetGameObject(_forcefieldGUID)) diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp index 03c85d22819f04..34743573df13fa 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp @@ -103,8 +103,6 @@ class instance_sunwell_plateau : public InstanceMapScript void OnPlayerEnter(Player* player) override { - instance->LoadGrid(1477.94f, 643.22f); - instance->LoadGrid(1641.45f, 988.08f); if (GameObject* gobj = GetGameObject(DATA_ICEBARRIER)) gobj->SendUpdateToPlayer(player); } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp index e0b161d2b46b78..3a0723c823a337 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp @@ -227,10 +227,6 @@ class at_zulgurub_entrance_speech : public OnlyOnceAreaTriggerScript { if (InstanceScript* instance = player->GetInstanceScript()) { - // Instance map's enormous, Hakkar's GRID is not loaded by the time players enter. - // Without this, the creature never says anything, because it doesn't load in time. - player->GetMap()->LoadGrid(-11783.99f, -1655.27f); - if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR))) { hakkar->setActive(true); @@ -254,10 +250,6 @@ class at_zulgurub_bridge_speech : public OnlyOnceAreaTriggerScript { if (InstanceScript* instance = player->GetInstanceScript()) { - // Instance map's enormous, Hakkar's GRID is not loaded by the time players enter. - // Without this, the creature never says anything, because it doesn't load in time. - player->GetMap()->LoadGrid(-11783.99f, -1655.27f); - if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR))) { if (hakkar->GetAI()) @@ -280,10 +272,6 @@ class at_zulgurub_temple_speech : public OnlyOnceAreaTriggerScript { if (InstanceScript* instance = player->GetInstanceScript()) { - // Instance map's enormous, Hakkar's GRID is not loaded by the time players enter. - // Without this, the creature never says anything, because it doesn't load in time. - player->GetMap()->LoadGrid(-11783.99f, -1655.27f); - if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR))) { if (hakkar->GetAI()) @@ -306,10 +294,6 @@ class at_zulgurub_bloodfire_pit_speech : public OnlyOnceAreaTriggerScript { if (InstanceScript* instance = player->GetInstanceScript()) { - // Instance map's enormous, Hakkar's GRID is not loaded by the time players enter. - // Without this, the creature never says anything, because it doesn't load in time. - player->GetMap()->LoadGrid(-11783.99f, -1655.27f); - if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR))) { if (hakkar->GetAI()) @@ -332,10 +316,6 @@ class at_zulgurub_edge_of_madness_speech : public OnlyOnceAreaTriggerScript { if (InstanceScript* instance = player->GetInstanceScript()) { - // Instance map's enormous, Hakkar's GRID is not loaded by the time players enter. - // Without this, the creature never says anything, because it doesn't load in time. - player->GetMap()->LoadGrid(-11783.99f, -1655.27f); - if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR))) { if (hakkar->GetAI()) diff --git a/src/server/scripts/Events/firework_show/firework_show.cpp b/src/server/scripts/Events/firework_show/firework_show.cpp index bbe92223a4d119..111a754f9193f9 100644 --- a/src/server/scripts/Events/firework_show/firework_show.cpp +++ b/src/server/scripts/Events/firework_show/firework_show.cpp @@ -28,6 +28,7 @@ #include "firework_show_Undercity.h" #include "GameObjectAI.h" #include "GameObjectScript.h" +#include "Timer.h" // , show std::map, FireworkShow const *> const FireworkShowStore = { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp index 9c377998735aa3..c6a17339a58f0a 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp @@ -67,8 +67,6 @@ class instance_culling_of_stratholme : public InstanceMapScript if (instance->GetPlayersCountExceptGMs() == 1) SetData(DATA_ARTHAS_REPOSITION, 2); - EnsureGridLoaded(); - if (plr->getRace() != RACE_HUMAN && plr->getRace() != RACE_DWARF && plr->getRace() != RACE_GNOME) plr->CastSpell(plr, ((plr->getGender() == GENDER_MALE) ? SPELL_HUMAN_MALE : SPELL_HUMAN_FEMALE), true); } @@ -224,7 +222,6 @@ class instance_culling_of_stratholme : public InstanceMapScript { if (!arthas->IsAlive()) { - EnsureGridLoaded(); arthas->setDeathState(DeathState::Dead); arthas->Respawn(); } @@ -352,16 +349,6 @@ class instance_culling_of_stratholme : public InstanceMapScript } } - void EnsureGridLoaded() - { - instance->LoadGrid(LeaderIntroPos1.GetPositionX(), LeaderIntroPos1.GetPositionY()); - instance->LoadGrid(LeaderIntroPos2.GetPositionX(), LeaderIntroPos2.GetPositionY()); - instance->LoadGrid(LeaderIntroPos3.GetPositionX(), LeaderIntroPos3.GetPositionY()); - instance->LoadGrid(LeaderIntroPos4.GetPositionX(), LeaderIntroPos4.GetPositionY()); - instance->LoadGrid(LeaderIntroPos5.GetPositionX(), LeaderIntroPos5.GetPositionY()); - instance->LoadGrid(LeaderIntroPos6.GetPositionX(), LeaderIntroPos6.GetPositionY()); - } - std::string GetSaveData() override { OUT_SAVE_INST_DATA; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/instance_old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/instance_old_hillsbrad.cpp index 9528692439bfcb..fdbd0b4f74b4e0 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/instance_old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/instance_old_hillsbrad.cpp @@ -69,8 +69,6 @@ class instance_old_hillsbrad : public InstanceMapScript if (instance->GetPlayersCountExceptGMs() <= 1) CleanupInstance(); - EnsureGridLoaded(); - if (_encounterProgress < ENCOUNTER_PROGRESS_BARRELS) player->SendUpdateWorldState(WORLD_STATE_BARRELS_PLANTED, _barrelCount); } @@ -197,9 +195,6 @@ class instance_old_hillsbrad : public InstanceMapScript { case EVENT_INITIAL_BARRELS_FLAME: { - instance->LoadGrid(instancePositions[0].GetPositionX(), instancePositions[0].GetPositionY()); - instance->LoadGrid(instancePositions[1].GetPositionX(), instancePositions[1].GetPositionY()); - for (ObjectGuid const& guid : _prisonersSet) if (Creature* orc = instance->GetCreature(guid)) { @@ -220,9 +215,6 @@ class instance_old_hillsbrad : public InstanceMapScript } case EVENT_FINAL_BARRELS_FLAME: { - instance->LoadGrid(instancePositions[0].GetPositionX(), instancePositions[0].GetPositionY()); - instance->LoadGrid(instancePositions[1].GetPositionX(), instancePositions[1].GetPositionY()); - if (_encounterProgress == ENCOUNTER_PROGRESS_NONE) { Map::PlayerList const& players = instance->GetPlayers(); @@ -250,7 +242,6 @@ class instance_old_hillsbrad : public InstanceMapScript } case EVENT_SUMMON_LIEUTENANT: { - instance->LoadGrid(instancePositions[2].GetPositionX(), instancePositions[2].GetPositionY()); instance->SummonCreature(NPC_LIEUTENANT_DRAKE, instancePositions[2]); break; } @@ -261,7 +252,6 @@ class instance_old_hillsbrad : public InstanceMapScript if (!thrall->IsAlive()) { ++_attemptsCount; - EnsureGridLoaded(); thrall->SetVisible(false); Reposition(thrall); thrall->setDeathState(DeathState::Dead); @@ -293,12 +283,6 @@ class instance_old_hillsbrad : public InstanceMapScript } } - void EnsureGridLoaded() - { - for (uint8 i = 0; i < THRALL_POSITIONS_COUNT; ++i) - instance->LoadGrid(thrallPositions[i].GetPositionX(), thrallPositions[i].GetPositionY()); - } - void ReadSaveDataMore(std::istringstream& data) override { data >> _encounterProgress; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp index 9265e4e91d24f6..3946eca1fcc4e3 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp @@ -74,7 +74,6 @@ class instance_the_black_morass : public InstanceMapScript // prevent getting stuck if event fails during boss break _noBossSpawnDelay = true; - instance->LoadGrid(-2023.0f, 7121.0f); if (Creature* medivh = GetCreature(DATA_MEDIVH)) { medivh->Respawn(); diff --git a/src/server/scripts/Kalimdor/DireMaul/instance_dire_maul.cpp b/src/server/scripts/Kalimdor/DireMaul/instance_dire_maul.cpp index 52d569572c82e8..247a414df61998 100644 --- a/src/server/scripts/Kalimdor/DireMaul/instance_dire_maul.cpp +++ b/src/server/scripts/Kalimdor/DireMaul/instance_dire_maul.cpp @@ -95,11 +95,9 @@ class instance_dire_maul : public InstanceMapScript { case TYPE_EAST_WING_PROGRESS: _eastWingProgress = data; - instance->LoadGrid(-56.59f, -269.12f); break; case TYPE_WEST_WING_PROGRESS: _westWingProgress = data; - instance->LoadGrid(132.626f, 625.913f); break; case TYPE_NORTH_WING_PROGRESS: _northWingProgress = data; @@ -113,7 +111,6 @@ class instance_dire_maul : public InstanceMapScript _pylonsState |= data; if (_pylonsState == ALL_PYLONS_OFF) // all five active, 31 { - instance->LoadGrid(-38.08f, 812.44f); if (Creature* immol = instance->GetCreature(_immoltharGUID)) { immol->setActive(true); diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp index 7938f9b75f7978..98b2b1e87f9d38 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp @@ -82,9 +82,6 @@ struct boss_kurinnaxx : public BossAI { if (killer) { - killer->GetMap()->LoadGrid(-9502.80f, 2042.65f); // Ossirian grid - killer->GetMap()->LoadGrid(-8538.17f, 1486.09f); // Andorov run path grid - if (Player* player = killer->GetCharmerOrOwnerPlayerOrPlayerItself()) { if (Creature* creature = player->SummonCreature(NPC_ANDOROV, -8538.177f, 1486.0956f, 32.39054f, 3.7638654f, TEMPSUMMON_CORPSE_DESPAWN, 0)) diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp index a4680ea5530dbc..40d4b02c49f4ef 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp @@ -87,7 +87,6 @@ class instance_ruins_of_ahnqiraj : public InstanceMapScript _rajaxWaveCounter == 0 && // if non-zero, encounter is in progress !_andorovGUID) // cleared if he is dead { - instance->LoadGrid(-8538.17f, 1486.09f); // Andorov run path grid if (Creature* creature = player->SummonCreature(NPC_ANDOROV, -8538.177f, 1486.0956f, 32.39054f, 3.7638654f, TEMPSUMMON_CORPSE_DESPAWN, 0)) { creature->setActive(true); diff --git a/src/server/scripts/Kalimdor/WailingCaverns/instance_wailing_caverns.cpp b/src/server/scripts/Kalimdor/WailingCaverns/instance_wailing_caverns.cpp index b8097f4c118912..0fddc3be91ded9 100644 --- a/src/server/scripts/Kalimdor/WailingCaverns/instance_wailing_caverns.cpp +++ b/src/server/scripts/Kalimdor/WailingCaverns/instance_wailing_caverns.cpp @@ -64,7 +64,6 @@ class instance_wailing_caverns : public InstanceMapScript if (type == TYPE_LORD_COBRAHN && _encounters[TYPE_LORD_SERPENTIS] != DONE) { - instance->LoadGrid(-120.163f, -24.624f); if (Creature* serpentis = instance->GetCreature(SerpentisGUID)) serpentis->AI()->Talk(SAY_SERPENTIS); } @@ -72,7 +71,6 @@ class instance_wailing_caverns : public InstanceMapScript if (type != TYPE_MUTANUS && _encounters[TYPE_LORD_COBRAHN] == DONE && _encounters[TYPE_LORD_PYTHAS] == DONE && _encounters[TYPE_LADY_ANACONDRA] == DONE && _encounters[TYPE_LORD_SERPENTIS] == DONE) { - instance->LoadGrid(-134.97f, 125.402f); if (Creature* disciple = instance->GetCreature(DiscipleOfNaralexGUID)) disciple->AI()->Talk(SAY_DISCIPLE); } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp index c2dbb9b1e9fe08..d70eb3b625ecce 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp @@ -63,7 +63,6 @@ class instance_ruby_sanctum : public InstanceMapScript { if (GetBossState(DATA_HALION_INTRO_DONE) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE) { - instance->LoadGrid(3156.0f, 537.0f); if (Creature* halionController = instance->GetCreature(HalionControllerGUID)) halionController->AI()->DoAction(ACTION_INTRO_HALION); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index 7669ed17ad60cc..fd43fce38156f1 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -325,7 +325,6 @@ class instance_halls_of_reflection : public InstanceMapScript } else { - instance->LoadGrid(PathWaypoints[PATH_WP_COUNT - 1].GetPositionX(), PathWaypoints[PATH_WP_COUNT - 1].GetPositionY()); creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true); creature->StopMovingOnCurrentPos(); } @@ -515,7 +514,6 @@ class instance_halls_of_reflection : public InstanceMapScript { break; } - instance->LoadGrid(LeaderEscapePos.GetPositionX(), LeaderEscapePos.GetPositionY()); if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) { if (!c->IsAlive()) @@ -567,7 +565,6 @@ class instance_halls_of_reflection : public InstanceMapScript case DATA_LICH_KING: if (data == DONE) { - instance->LoadGrid(PathWaypoints[0].GetPositionX(), PathWaypoints[0].GetPositionY()); EncounterMask |= (1 << DATA_LICH_KING); if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) c->setActive(false); diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/instance_pit_of_saron.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/instance_pit_of_saron.cpp index e91e0b954ac752..337415ebbc6b38 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/instance_pit_of_saron.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/instance_pit_of_saron.cpp @@ -78,7 +78,6 @@ class instance_pit_of_saron : public InstanceMapScript { InstanceScript::OnPlayerEnter(player); - instance->LoadGrid(LeaderIntroPos.GetPositionX(), LeaderIntroPos.GetPositionY()); if (Creature* c = instance->GetCreature(GetGuidData(DATA_LEADER_FIRST_GUID))) c->AI()->SetData(DATA_START_INTRO, 0); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 08932e30827c93..884cda64a8cb9d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -1537,7 +1537,6 @@ class at_sindragosa_lair : public AreaTriggerScript if (!instance->GetData(DATA_SINDRAGOSA_FROSTWYRMS) && instance->GetBossState(DATA_SINDRAGOSA) != IN_PROGRESS) { - player->GetMap()->LoadGrid(SindragosaSpawnPos.GetPositionX(), SindragosaSpawnPos.GetPositionY()); if (Creature* sindragosa = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SINDRAGOSA))) sindragosa->AI()->DoAction(ACTION_START_FROSTWYRM); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 3d7970eadaa15f..0393ace0ca1ef7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -747,8 +747,6 @@ class npc_crok_scourgebane : public CreatureScript me->setActive(true); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); me->SetImmuneToAll(true); - // Load Grid with Sister Svalna - me->GetMap()->LoadGrid(4356.71f, 2484.33f); if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA))) svalna->AI()->DoAction(ACTION_START_GAUNTLET); for (uint32 i = 0; i < 4; ++i) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index f2640d9c52969b..e624110870e45a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -651,7 +651,6 @@ class instance_icecrown_citadel : public InstanceMapScript FrostwyrmGUIDs.erase(creature->GetSpawnId()); if (FrostwyrmGUIDs.empty()) { - instance->LoadGrid(SindragosaSpawnPos.GetPositionX(), SindragosaSpawnPos.GetPositionY()); if (Creature* boss = instance->SummonCreature(NPC_SINDRAGOSA, SindragosaSpawnPos)) boss->AI()->DoAction(ACTION_START_FROSTWYRM); } @@ -1190,7 +1189,6 @@ class instance_icecrown_citadel : public InstanceMapScript if (GameObject* pillars = instance->GetGameObject(PillarsUnchainedGUID)) pillars->SetRespawnTime(7 * DAY); - instance->LoadGrid(JainaSpawnPos.GetPositionX(), JainaSpawnPos.GetPositionY()); instance->SummonCreature(NPC_LADY_JAINA_PROUDMOORE_QUEST, JainaSpawnPos); instance->SummonCreature(NPC_MURADIN_BRONZEBEARD_QUEST, MuradinSpawnPos); instance->SummonCreature(NPC_UTHER_THE_LIGHTBRINGER_QUEST, UtherSpawnPos); diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index f9b1357e1c342c..550a84743f9095 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -821,8 +821,6 @@ class instance_naxxramas : public InstanceMapScript if (state == DONE) { _speakTimer = 1; - // Load KT's grid so he can talk - instance->LoadGrid(3763.43f, -5115.87f); } else if (state == NOT_STARTED) { @@ -1061,8 +1059,6 @@ class instance_naxxramas : public InstanceMapScript switch (events.ExecuteEvent()) { case EVENT_KELTHUZAD_WING_TAUNT: - // Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work. - instance->LoadGrid(3749.67f, -5114.06f); if (Creature* kelthuzad = instance->GetCreature(_kelthuzadGUID)) { kelthuzad->AI()->Talk(_currentWingTaunt); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index a987a7c82fdd53..04ab6e9a73b142 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -178,7 +178,6 @@ class instance_ulduar : public InstanceMapScript void OnPlayerEnter(Player* player) override { // mimiron tram: - instance->LoadGrid(2307.0f, 284.632f); if (GameObject* MimironTram = instance->GetGameObject(m_mimironTramGUID)) { player->UpdateVisibilityOf(MimironTram); @@ -537,10 +536,7 @@ class instance_ulduar : public InstanceMapScript break; case GO_KEEPERS_GATE: if (GetData(TYPE_MIMIRON) == DONE && GetData(TYPE_FREYA) == DONE && GetData(TYPE_HODIR) == DONE && GetData(TYPE_THORIM) == DONE) - { - instance->LoadGrid(1903.0f, 248.0f); gameObject->RemoveGameObjectFlag(GO_FLAG_LOCKED); - } m_keepersgateGUID = gameObject->GetGUID(); break; @@ -752,8 +748,6 @@ class instance_ulduar : public InstanceMapScript case EVENT_TOWER_OF_FROST_DESTROYED: case EVENT_TOWER_OF_FLAMES_DESTROYED: { - instance->LoadGrid(364.0f, -16.0f); //make sure leviathan is loaded - instance->LoadGrid(364.0f, 32.0f); //make sure Mimiron's and Thorim's Targetting Crystal are loaded m_leviathanTowers[type - EVENT_TOWER_OF_LIFE_DESTROYED] = data; for (uint8 i = 0; i < 2; ++i) { diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp index d59e2fb17e9a6f..77d1b0a73a42c2 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp @@ -89,7 +89,7 @@ void UpdateCreatureHalaa(ObjectGuid::LowType spawnId, Map* map, float x, float y sObjectMgr->AddCreatureToGrid(spawnId, &data); // Spawn if necessary (loaded grids only) - if (!map->Instanceable() && !map->IsRemovalGrid(x, y)) + if (!map->Instanceable() && !map->IsGridCreated(x, y)) { Creature* creature = new Creature(); if (!creature->LoadCreatureFromDB(spawnId, map, true, true)) diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp index 84a4c665635b6d..a3354a2a27c729 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp @@ -125,7 +125,6 @@ struct boss_kelidan_the_breaker : public BossAI { Talk(SAY_DIE); _JustDied(); - me->GetMap()->LoadGrid(0, -111.0f); } void ApplyImmunities(bool apply) diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp index 2ed91f6f98bf22..c490108ed49590 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp @@ -99,7 +99,6 @@ class instance_shattered_halls : public InstanceMapScript if (type == DATA_ENTERED_ROOM && data == DATA_ENTERED_ROOM && RescueTimer == 100 * MINUTE * IN_MILLISECONDS) { DoCastSpellOnPlayers(SPELL_KARGATHS_EXECUTIONER_1); - instance->LoadGrid(230, -80); if (Creature* kargath = GetCreature(DATA_KARGATH)) sCreatureTextMgr->SendChat(kargath, GetTeamIdInInstance() == TEAM_ALLIANCE ? 3 : 4, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP);