summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakenbacon <revoke1336@live.com>2025-02-14 13:11:27 -0800
committerGitHub <noreply@github.com>2025-02-14 22:11:27 +0100
commitee69a569c404594ab52304e78a13682662538470 (patch)
tree3bf818cd40102e1e2849ba26af41e53cac13b823
parent10183efd5135d2f51bf1117c93921239401b7c3d (diff)
fix(Core/Grids): Grid improvements (#20955)
-rw-r--r--src/common/Collision/Maps/MapDefines.h1
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp5
-rw-r--r--src/server/game/Entities/Creature/CreatureGroups.cpp1
-rw-r--r--src/server/game/Entities/Item/ItemEnchantmentMgr.cpp1
-rw-r--r--src/server/game/Entities/Object/Object.cpp11
-rw-r--r--src/server/game/Entities/Transport/Transport.h1
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp18
-rw-r--r--src/server/game/Globals/ObjectMgr.h4
-rw-r--r--src/server/game/Grids/Cells/Cell.h24
-rw-r--r--src/server/game/Grids/Cells/CellImpl.h59
-rw-r--r--src/server/game/Grids/Grid.h131
-rw-r--r--src/server/game/Grids/GridCell.h75
-rw-r--r--src/server/game/Grids/GridDefines.h16
-rw-r--r--src/server/game/Grids/GridLoader.h76
-rw-r--r--src/server/game/Grids/GridObjectLoader.cpp138
-rw-r--r--src/server/game/Grids/GridObjectLoader.h (renamed from src/server/game/Grids/ObjectGridLoader.h)45
-rw-r--r--src/server/game/Grids/GridTerrainData.cpp617
-rw-r--r--src/server/game/Grids/GridTerrainData.h255
-rw-r--r--src/server/game/Grids/GridTerrainLoader.cpp160
-rw-r--r--src/server/game/Grids/GridTerrainLoader.h59
-rw-r--r--src/server/game/Grids/MapGrid.h154
-rw-r--r--src/server/game/Grids/MapGridManager.cpp129
-rw-r--r--src/server/game/Grids/MapGridManager.h62
-rw-r--r--src/server/game/Grids/NGrid.h113
-rw-r--r--src/server/game/Grids/Notifiers/GridNotifiers.h2
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp245
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp8
-rw-r--r--src/server/game/Loot/LootItemStorage.cpp1
-rw-r--r--src/server/game/Maps/Map.cpp1147
-rw-r--r--src/server/game/Maps/Map.h252
-rw-r--r--src/server/game/Maps/MapInstanced.cpp9
-rw-r--r--src/server/game/Maps/MapMgr.cpp11
-rw-r--r--src/server/game/Maps/MapMgr.h1
-rw-r--r--src/server/game/Movement/Waypoints/WaypointMgr.cpp1
-rw-r--r--src/server/game/Scripting/ScriptDefines/AllMapScript.cpp5
-rw-r--r--src/server/game/Scripting/ScriptMgr.h4
-rw-r--r--src/server/game/Scripting/ScriptObject.h4
-rw-r--r--src/server/game/Scripting/ScriptObjectFwd.h2
-rw-r--r--src/server/game/Spells/Spell.cpp4
-rw-r--r--src/server/game/World/World.cpp2
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp17
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp9
-rw-r--r--src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp1
-rw-r--r--src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp6
-rw-r--r--src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp1
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp2
-rw-r--r--src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp20
-rw-r--r--src/server/scripts/Events/firework_show/firework_show.cpp1
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp13
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/instance_old_hillsbrad.cpp16
-rw-r--r--src/server/scripts/Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp1
-rw-r--r--src/server/scripts/Kalimdor/DireMaul/instance_dire_maul.cpp3
-rw-r--r--src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp3
-rw-r--r--src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp1
-rw-r--r--src/server/scripts/Kalimdor/WailingCaverns/instance_wailing_caverns.cpp2
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp1
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp3
-rw-r--r--src/server/scripts/Northrend/FrozenHalls/PitOfSaron/instance_pit_of_saron.cpp1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp1
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp2
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp2
-rw-r--r--src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp4
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp6
-rw-r--r--src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp2
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp1
-rw-r--r--src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp1
67 files changed, 1952 insertions, 2023 deletions
diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h
index 6772a20c70..7f28fc8b2a 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 0366216561..404305b785 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<Acore::BroadcastTextBuilder> _localizer(_builder);
Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::BroadcastTextBuilder>> _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 759d38fa17..c4ef53ae60 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 f82d42f874..dd781062ea 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 <cmath>
#include <functional>
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index fe37ea46c9..f790f4297d 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<Creature*>& 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<Acore::AllCreaturesOfEntryInRange> searcher(this, creatureList, check);
-
- TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange>, WorldTypeMapContainer> world_visitor(searcher);
- cell.Visit(pair, world_visitor, *(this->GetMap()), *this, radius);
-
- TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange>, 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 75fc9f9ee6..2387b3b989 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 f1fd084122..43b2568dc1 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 aa39808ce4..9b04949b13 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 3541637b9a..3e1a15f8bf 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1150,12 +1150,12 @@ public:
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 86ce107b17..b3c5747a77 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<class T> static void VisitGridObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true);
- template<class T> static void VisitWorldObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true);
- template<class T> static void VisitAllObjects(WorldObject const* obj, T& visitor, float radius, bool dont_load = true);
+ template<class T> static void VisitGridObjects(WorldObject const* obj, T& visitor, float radius);
+ template<class T> static void VisitWorldObjects(WorldObject const* obj, T& visitor, float radius);
+ template<class T> static void VisitAllObjects(WorldObject const* obj, T& visitor, float radius);
- template<class T> static void VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true);
- template<class T> static void VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true);
- template<class T> static void VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load = true);
+ template<class T> static void VisitGridObjects(float x, float y, Map* map, T& visitor, float radius);
+ template<class T> static void VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius);
+ template<class T> static void VisitAllObjects(float x, float y, Map* map, T& visitor, float radius);
private:
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER>&, 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 f8cf0ed08b..ec6e6e93aa 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<T,
}
template<class T, class CONTAINER>
-inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float x_off, float y_off, float radius) const{
+inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& 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, TypeContainerVisitor<T,
return;
}
- //ALWAYS visit standing cell first!!! Since we deal with small radiuses
- //it is very essential to call visitor for standing cell firstly...
- map.Visit(*this, visitor);
-
// loop the cell range
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);
- //lets skip standing cell since we already visited it
- if (cellCoord != standing_cell)
- {
- Cell r_zone(cellCoord);
- r_zone.data.Part.nocreate = this->data.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<T, CONTAINER>& 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<T, CONTAINER>& 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<class T>
-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<T, GridTypeMapContainer> gnotifier(visitor);
cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
}
template<class T>
-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<T, WorldTypeMapContainer> wnotifier(visitor);
cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
}
template<class T>
-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<T, WorldTypeMapContainer> 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<class T>
-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<T, GridTypeMapContainer> gnotifier(visitor);
cell.Visit(p, gnotifier, *map, x, y, radius);
}
template<class T>
-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<T, WorldTypeMapContainer> wnotifier(visitor);
cell.Visit(p, wnotifier, *map, x, y, radius);
}
template<class T>
-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<T, WorldTypeMapContainer> 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 b9cafdbe0c..0000000000
--- 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 <http://www.gnu.org/licenses/>.
- */
-
-#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 A, class T, class O> class GridLoader;
-
-template
-<
- class ACTIVE_OBJECT,
- class WORLD_OBJECT_TYPES,
- class GRID_OBJECT_TYPES
- >
-class Grid
-{
- // allows the GridLoader to access its internals
- template<class A, class T, class O> 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<class SPECIFIC_OBJECT> void AddWorldObject(SPECIFIC_OBJECT* obj)
- {
- i_objects.template insert<SPECIFIC_OBJECT>(obj);
- ASSERT(obj->IsInGrid());
- }
-
- /** an object of interested exits the grid
- */
- //Actually an unlink is enough, no need to go through the container
- //template<class SPECIFIC_OBJECT> void RemoveWorldObject(SPECIFIC_OBJECT *obj)
- //{
- // ASSERT(obj->GetGridRef().isValid());
- // i_objects.template remove<SPECIFIC_OBJECT>(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<class T>
- void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
- {
- visitor.Visit(i_container);
- }
-
- // Visit world objects
- template<class T>
- void Visit(TypeContainerVisitor<T, TypeMapContainer<WORLD_OBJECT_TYPES> >& visitor)
- {
- visitor.Visit(i_objects);
- }
-
- /** Inserts a container type object into the grid.
- */
- template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
- {
- i_container.template insert<SPECIFIC_OBJECT>(obj);
- ASSERT(obj->IsInGrid());
- }
-
- /** Removes a containter type object from the grid
- */
- //template<class SPECIFIC_OBJECT> void RemoveGridObject(SPECIFIC_OBJECT *obj)
- //{
- // ASSERT(obj->GetGridRef().isValid());
- // i_container.template remove<SPECIFIC_OBJECT>(obj);
- // ASSERT(!obj->GetGridRef().isValid());
- //}
-
- /*bool NoWorldObjectInGrid() const
- {
- return i_objects.GetElements().IsEmpty();
- }
-
- bool NoGridObjectInGrid() const
- {
- return i_container.GetElements().IsEmpty();
- }*/
-private:
- TypeMapContainer<GRID_OBJECT_TYPES> i_container;
- TypeMapContainer<WORLD_OBJECT_TYPES> i_objects;
- //typedef std::set<void*> 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 0000000000..c0ccfdbba1
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<class SPECIFIC_OBJECT> void AddWorldObject(SPECIFIC_OBJECT* obj)
+ {
+ _worldObjects.template insert<SPECIFIC_OBJECT>(obj);
+ ASSERT(obj->IsInGrid());
+ }
+
+ template<class SPECIFIC_OBJECT> void AddGridObject(SPECIFIC_OBJECT* obj)
+ {
+ _gridObjects.template insert<SPECIFIC_OBJECT>(obj);
+ ASSERT(obj->IsInGrid());
+ }
+
+ // Visit grid objects
+ template<class T>
+ void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
+ {
+ visitor.Visit(_gridObjects);
+ }
+
+ // Visit world objects
+ template<class T>
+ void Visit(TypeContainerVisitor<T, TypeMapContainer<WORLD_OBJECT_TYPES> >& visitor)
+ {
+ visitor.Visit(_worldObjects);
+ }
+private:
+ TypeMapContainer<GRID_OBJECT_TYPES> _gridObjects;
+ TypeMapContainer<WORLD_OBJECT_TYPES> _worldObjects;
+};
+#endif
diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h
index 0e72af22e2..62d1a6f500 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<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType;
-typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
+typedef GridCell<AllWorldObjectTypes, AllGridObjectTypes> GridCellType;
+typedef MapGrid<AllWorldObjectTypes, AllGridObjectTypes> MapGridType;
typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer;
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;
@@ -187,6 +186,13 @@ namespace Acore
return Compute<GridCoord, CENTER_GRID_ID>(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<CellCoord, CENTER_GRID_CELL_ID>(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 00081281c8..0000000000
--- 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 <http://www.gnu.org/licenses/>.
- */
-
-#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<class LOADER>
- void Load(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> &grid, LOADER &loader)
- {
- grid.LockGrid();
- loader.Load(grid);
- grid.UnlockGrid();
- }
-
- // Stop the grid
- template<class STOPER>
- void Stop(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> &grid, STOPER &stoper)
- {
- grid.LockGrid();
- stoper.Stop(grid);
- grid.UnlockGrid();
- }
-
- // Unloads the grid
- template<class UNLOADER>
- void Unload(Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> &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 0000000000..09550ab906
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <class T>
+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<Creature>(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<GameObject>(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<Corpse*> 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<class T>
+void GridObjectUnloader::Visit(GridRefMgr<T>& 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<class T>
+void GridObjectCleaner::Visit(GridRefMgr<T>& m)
+{
+ for (typename GridRefMgr<T>::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<GameObject>(GameObjectMapType&);
+template void GridObjectCleaner::Visit<DynamicObject>(DynamicObjectMapType&);
+template void GridObjectCleaner::Visit<Corpse>(CorpseMapType&);
diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/GridObjectLoader.h
index d6029ac7bf..101f489bfb 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 <http://www.gnu.org/licenses/>.
*/
-#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<class T>
+ void AddObjectHelper(Map* map, T* obj);
- template<class T> 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<class T> void Visit(GridRefMgr<T>&);
};
-//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 0000000000..e2439dc2e5
--- /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 <filesystem>
+#include <G3D/Ray.h>
+
+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<char*>(&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<char*>(&header), sizeof(header)) || header.fourcc != MapAreaMagic.asUInt)
+ return false;
+
+ _loadedAreaData = std::make_unique<LoadedAreaData>();
+ _loadedAreaData->gridArea = header.gridArea;
+ if (!(header.flags & MAP_AREA_NO_AREA))
+ {
+ _loadedAreaData->areaMap = std::make_unique<LoadedAreaData::AreaMapType>();
+ if (!fileStream.read(reinterpret_cast<char*>(_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<char*>(&header), sizeof(header)) || header.fourcc != MapHeightMagic.asUInt)
+ return false;
+
+ _loadedHeightData = std::make_unique<LoadedHeightData>();
+ _loadedHeightData->gridHeight = header.gridHeight;
+ if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
+ {
+ if ((header.flags & MAP_HEIGHT_AS_INT16))
+ {
+ _loadedHeightData->uint16HeightData = std::make_unique<LoadedHeightData::Uint16HeightData>();
+ if (!fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->uint16HeightData->v9), sizeof(_loadedHeightData->uint16HeightData->v9))
+ || !fileStream.read(reinterpret_cast<char*>(&_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<LoadedHeightData::Uint8HeightData>();
+ if (!fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->uint8HeightData->v9), sizeof(_loadedHeightData->uint8HeightData->v9))
+ || !fileStream.read(reinterpret_cast<char*>(&_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<LoadedHeightData::FloatHeightData>();
+ if (!fileStream.read(reinterpret_cast<char*>(&_loadedHeightData->floatHeightData->v9), sizeof(_loadedHeightData->floatHeightData->v9))
+ || !fileStream.read(reinterpret_cast<char*>(&_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<int16, 9> maxHeights;
+ std::array<int16, 9> minHeights;
+ if (!fileStream.read(reinterpret_cast<char*>(maxHeights.data()), sizeof(maxHeights)) ||
+ !fileStream.read(reinterpret_cast<char*>(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<LoadedHeightData::HeightPlanesType>();
+ 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<char*>(&header), sizeof(header)) || header.fourcc != MapLiquidMagic.asUInt)
+ return false;
+
+ _loadedLiquidData = std::make_unique<LoadedLiquidData>();
+ _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<LoadedLiquidData::LiquidEntryType>();
+ if (!fileStream.read(reinterpret_cast<char*>(_loadedLiquidData->liquidEntry.get()), sizeof(LoadedLiquidData::LiquidEntryType)))
+ return false;
+
+ _loadedLiquidData->liquidFlags = std::make_unique<LoadedLiquidData::LiquidFlagsType>();
+ if (!fileStream.read(reinterpret_cast<char*>(_loadedLiquidData->liquidFlags.get()), sizeof(LoadedLiquidData::LiquidFlagsType)))
+ return false;
+ }
+ if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
+ {
+ _loadedLiquidData->liquidMap = std::make_unique<LoadedLiquidData::LiquidMapType>();
+ _loadedLiquidData->liquidMap->resize(_loadedLiquidData->liquidWidth * _loadedLiquidData->liquidHeight);
+ if (!fileStream.read(reinterpret_cast<char*>(_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<LoadedHoleData>();
+ if (!fileStream.read(reinterpret_cast<char*>(&_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 0000000000..6d6b898252
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRID_TERRAIN_DATA_H
+#define GRID_TERRAIN_DATA_H
+
+#include "Common.h"
+#include <fstream>
+#include <G3D/Plane.h>
+#include <memory>
+
+#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<uint16, 16 * 16> AreaMapType;
+
+ uint16 gridArea;
+ std::unique_ptr<AreaMapType> areaMap;
+};
+
+struct LoadedHeightData
+{
+ typedef std::array<G3D::Plane, 8> HeightPlanesType;
+
+ struct Uint16HeightData
+ {
+ typedef std::array<uint16, 129 * 129> V9Type;
+ typedef std::array<uint16, 128 * 128> V8Type;
+
+ V9Type v9;
+ V8Type v8;
+ float gridIntHeightMultiplier;
+ };
+
+ struct Uint8HeightData
+ {
+ typedef std::array<uint8, 129 * 129> V9Type;
+ typedef std::array<uint8, 128 * 128> V8Type;
+
+ V9Type v9;
+ V8Type v8;
+ float gridIntHeightMultiplier;
+ };
+
+ struct FloatHeightData
+ {
+ typedef std::array<float, 129 * 129> V9Type;
+ typedef std::array<float, 128 * 128> V8Type;
+
+ V9Type v9;
+ V8Type v8;
+ };
+
+ float gridHeight;
+ std::unique_ptr<Uint16HeightData> uint16HeightData;
+ std::unique_ptr<Uint8HeightData> uint8HeightData;
+ std::unique_ptr<FloatHeightData> floatHeightData;
+ std::unique_ptr<HeightPlanesType> minHeightPlanes;
+};
+
+struct LoadedLiquidData
+{
+ typedef std::array<uint16, 16 * 16> LiquidEntryType;
+ typedef std::array<uint8, 16 * 16> LiquidFlagsType;
+ typedef std::vector<float> LiquidMapType;
+
+ uint16 liquidGlobalEntry;
+ uint8 liquidGlobalFlags;
+ uint8 liquidOffX;
+ uint8 liquidOffY;
+ uint8 liquidWidth;
+ uint8 liquidHeight;
+ float liquidLevel;
+ std::unique_ptr<LiquidEntryType> liquidEntry;
+ std::unique_ptr<LiquidFlagsType> liquidFlags;
+ std::unique_ptr<LiquidMapType> liquidMap;
+};
+
+struct LoadedHoleData
+{
+ typedef std::array<uint16, 16 * 16> 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> _loadedAreaData;
+ std::unique_ptr<LoadedHeightData> _loadedHeightData;
+ std::unique_ptr<LoadedLiquidData> _loadedLiquidData;
+ std::unique_ptr<LoadedHoleData> _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 0000000000..b82c3b5446
--- /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*>(_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<GridTerrainData> terrainData = std::make_unique<GridTerrainData>();
+ 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<char*>(&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 0000000000..03db11f7fd
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 0000000000..9c6b33c919
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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<WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> 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<class SPECIFIC_OBJECT> void AddWorldObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
+ {
+ GetOrCreateCell(x, y).AddWorldObject(obj);
+ }
+
+ template<class SPECIFIC_OBJECT> void RemoveWorldObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
+ {
+ GetOrCreateCell(x, y).RemoveWorldObject(obj);
+ }
+
+ template<class SPECIFIC_OBJECT> void AddGridObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
+ {
+ GetOrCreateCell(x, y).AddGridObject(obj);
+ }
+
+ template<class SPECIFIC_OBJECT> void RemoveGridObject(uint16 const x, uint16 const y, SPECIFIC_OBJECT* obj)
+ {
+ GetOrCreateCell(x, y).RemoveGridObject(obj);
+ }
+
+ // Visit all cells
+ template<class T, class TT>
+ void VisitAllCells(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
+ {
+ for (auto& cellX : _cells)
+ {
+ for (auto& cellY : cellX)
+ {
+ if (!cellY)
+ continue;
+
+ cellY->Visit(visitor);
+ }
+ }
+ }
+
+ // Visit single cell
+ template<class T, class TT>
+ void VisitCell(uint16 const x, uint16 const y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
+ {
+ GridCellType* gridCell = GetCell(x, y);
+ if (!gridCell)
+ return;
+
+ gridCell->Visit(visitor);
+ }
+
+ void link(GridRefMgr<MapGrid<WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>>* pTo)
+ {
+ _gridReference.link(pTo, this);
+ }
+
+ GridTerrainData* GetTerrainData() const { return _terrainData.get(); }
+ std::shared_ptr<GridTerrainData> GetTerrainDataSharedPtr() { return _terrainData; }
+ void SetTerrainData(std::shared_ptr<GridTerrainData> 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<GridCellType>();
+
+ 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<std::array<std::unique_ptr<GridCellType>, MAX_NUMBER_OF_CELLS>, MAX_NUMBER_OF_CELLS> _cells; // N * N array
+ GridReference<MapGrid<WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES>> _gridReference;
+
+ // Instances will share a copy of the parent maps terrainData
+ std::shared_ptr<GridTerrainData> _terrainData;
+};
+
+#endif
diff --git a/src/server/game/Grids/MapGridManager.cpp b/src/server/game/Grids/MapGridManager.cpp
new file mode 100644
index 0000000000..21ca5bfed3
--- /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<std::mutex> guard(_gridLock);
+ if (IsGridCreated(x, y))
+ return;
+
+ std::unique_ptr<MapGridType> grid = std::make_unique<MapGridType>(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<GridObjectCleaner, GridTypeMapContainer> visitor(worker);
+ grid->VisitAllCells(visitor);
+ }
+
+ _map->RemoveAllObjectsInRemoveList();
+
+ {
+ GridObjectUnloader worker;
+ TypeContainerVisitor<GridObjectUnloader, GridTypeMapContainer> 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 0000000000..3eb7c629d5
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAP_GRID_MANAGER_H
+#define MAP_GRID_MANAGER_H
+
+#include "Common.h"
+#include "GridDefines.h"
+#include "MapDefines.h"
+#include "MapGrid.h"
+
+#include <mutex>
+
+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<MapGridType> _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 6ac60aeb72..0000000000
--- 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 <http://www.gnu.org/licenses/>.
- */
-
-#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<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> 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<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> >* pTo)
- {
- i_Reference.link(pTo, this);
- }
- [[nodiscard]] bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; }
- void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; }
-
- /*
- template<class SPECIFIC_OBJECT> void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
- {
- GetGridType(x, y).AddWorldObject(obj);
- }
-
- template<class SPECIFIC_OBJECT> void RemoveWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
- {
- GetGridType(x, y).RemoveWorldObject(obj);
- }
-
- template<class SPECIFIC_OBJECT> void AddGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
- {
- GetGridType(x, y).AddGridObject(obj);
- }
-
- template<class SPECIFIC_OBJECT> void RemoveGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
- {
- GetGridType(x, y).RemoveGridObject(obj);
- }
- */
-
- // Visit all Grids (cells) in NGrid (grid)
- template<class T, class TT>
- void VisitAllGrids(TypeContainerVisitor<T, TypeMapContainer<TT> >& 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<class T, class TT>
- void VisitGrid(const uint32 x, const uint32 y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
- {
- GetGridType(x, y).Visit(visitor);
- }
-
-private:
- uint32 i_gridId;
- GridReference<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> > 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 42f657f9bb..6e084b7338 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 2b7d6f8ef5..0000000000
--- 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 <http://www.gnu.org/licenses/>.
- */
-
-#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<class T> void Visit(GridRefMgr<T>&) { }
-
-private:
- Cell i_cell;
- Map* i_map;
- NGridType& i_grid;
-public:
- uint32& i_corpses;
-};
-
-template<class T> 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 <class T>
-void AddObjectHelper(CellCoord& cell, GridRefMgr<T>& 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 <class T>
-void LoadHelper(CellGuidSet const& /*guid_set*/, CellCoord& /*cell*/, GridRefMgr<T>& /*m*/, uint32& /*count*/, Map* /*map*/)
-{
-}
-
-template <>
-void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<Creature>& 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<GameObject>& 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<Corpse*> 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<ObjectGridLoader, GridTypeMapContainer> visitor(*this);
- i_grid.VisitGrid(x, y, visitor);
- }
-
- //Load corpses (not bones)
- {
- ObjectWorldLoader worker(*this);
- TypeContainerVisitor<ObjectWorldLoader, WorldTypeMapContainer> 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<class T>
-void ObjectGridUnloader::Visit(GridRefMgr<T>& 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<class T>
-void ObjectGridCleaner::Visit(GridRefMgr<T>& m)
-{
- for (typename GridRefMgr<T>::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<GameObject>(GameObjectMapType&);
-template void ObjectGridCleaner::Visit<DynamicObject>(DynamicObjectMapType&);
-template void ObjectGridCleaner::Visit<Corpse>(CorpseMapType&);
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index f5c3df9b85..963fdcb296 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<Acore::EmoteChatBuilder > emote_do(emote_builder);
Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::EmoteChatBuilder > > emote_worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do);
- TypeContainerVisitor<Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::EmoteChatBuilder> >, 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 e5b6de588b..434ad43250 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 5d9579c4a3..38f501bb3c 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<class T>
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<T>(obj);
+ grid->AddWorldObject<T>(cell.CellX(), cell.CellY(), obj);
else
- grid->GetGridType(cell.CellX(), cell.CellY()).template AddGridObject<T>(obj);
+ grid->AddGridObject<T>(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<std::mutex> 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<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
@@ -725,7 +552,6 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::Objec
markCell(cell_id);
CellCoord pair(x, y);
Cell cell(pair);
- //cell.SetNoCreate(); // in mmaps this is missing
Visit(cell, gridVisitor);
Visit(cell, worldVisitor);
@@ -1234,50 +1060,12 @@ void Map::MoveAllDynamicObjectsInMoveList()
_dynamicObjectsToMove.clear();
}
-bool Map::UnloadGrid(NGridType& ngrid)
+bool Map::UnloadGrid(MapGridType& grid)
{
- // pussywizard: UnloadGrid only done when whole map is unloaded, no need to worry about moving npcs between grids, etc.
-
- const uint32 x = ngrid.getX();
- const uint32 y = ngrid.getY();
-
- {
- ObjectGridCleaner worker;
- TypeContainerVisitor<ObjectGridCleaner, GridTypeMapContainer> visitor(worker);
- ngrid.VisitAllGrids(visitor);
- }
-
- RemoveAllObjectsInRemoveList();
-
- {
- ObjectGridUnloader worker;
- TypeContainerVisitor<ObjectGridUnloader, GridTypeMapContainer> 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<NGridType>::iterator i = GridRefMgr<NGridType>::begin(); i != GridRefMgr<NGridType>::end();)
+ for (GridRefMgr<MapGridType>::iterator i = GridRefMgr<MapGridType>::begin(); i != GridRefMgr<MapGridType>::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<GridTerrainData> 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<Map*>(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<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS);
- switch (liquidData.Status)
- {
- case LIQUID_MAP_ABOVE_WATER:
- return std::max<float>(liquidData.Level, ground_z);
- case LIQUID_MAP_NO_WATER:
- return ground_z;
- default:
- return liquidData.Level;
- }
+ LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS);
+ switch (liquidData.Status)
+ {
+ case LIQUID_MAP_ABOVE_WATER:
+ return std::max<float>(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<Map*>(this)->GetGrid(x, y))
+ if (GridTerrainData* gmap = const_cast<Map*>(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<Map*>(this)->GetGrid(x, y))
+ if (GridTerrainData const* grid = const_cast<Map*>(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<Map*>(this)->GetGrid(x, y))
+ if (GridTerrainData* gmap = const_cast<Map*>(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<Map*>(this)->GetGrid(x, y))
+ if (GridTerrainData* gmap = const_cast<Map*>(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<Map*>(this)->GetGrid(x, y))
+ if (GridTerrainData* gmap = const_cast<Map*>(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<Map*>(this)->GetGrid(x, y))
+ if (GridTerrainData* gmap = const_cast<Map*>(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 54f8d7c2cd..33bb8238d6 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 <bitset>
#include <list>
#include <memory>
@@ -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<NGridType>
+class Map : public GridRefMgr<MapGridType>
{
friend class MapReference;
+ friend class GridObjectLoader;
public:
Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr);
~Map() override;
@@ -348,6 +194,7 @@ public:
[[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 @@ public:
template<class T, class CONTAINER> void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER>& 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<GridTerrainData> 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 @@ public:
// Do whatever you want to all the players in map [including GameMasters], i.e.: param exec = [&](Player* p) { p->Whatever(); }
void DoForAllPlayers(std::function<void(Player*)> 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 @@ public:
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<class T> void InitializeObject(T* obj);
void AddCreatureToMoveList(Creature* c);
@@ -679,33 +526,22 @@ private:
std::vector<GameObject*> _gameObjectsToMove;
std::vector<DynamicObject*> _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<class T>
+ 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 @@ private:
//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<TOTAL_NUMBER_OF_CELLS_PER_MAP* TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
- std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP* TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
+ std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
+ std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
bool i_scriptLock;
std::unordered_set<WorldObject*> i_objectsToRemove;
@@ -752,10 +586,6 @@ private:
typedef std::multimap<time_t, ScriptAction> ScriptScheduleMap;
ScriptScheduleMap m_scriptSchedule;
- // Type specific code for add/remove to/from grid
- template<class T>
- void AddToGrid(T* object, Cell const& cell);
-
template<class T>
void DeleteFromWorld(T*);
@@ -875,16 +705,14 @@ private:
template<class T, class CONTAINER>
inline void Map::Visit(Cell const& cell, TypeContainerVisitor<T, CONTAINER>& 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 6566a2a209..8b42389e3d 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 3a52e5fe38..2b1fe2b3b4 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 9cf80a9797..2872ddd7c8 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 de437b2cba..7a2596fbf7 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 a439073651..1f8402644e 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<WorldMapScript>(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 af4b494902..26159984b2 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -189,8 +189,8 @@ public: /* FormulaScript */
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 1dd8500cdc..fe6cb2c12d 100644
--- a/src/server/game/Scripting/ScriptObject.h
+++ b/src/server/game/Scripting/ScriptObject.h
@@ -98,10 +98,10 @@ public:
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 a7a899e028..35f425eae5 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 c5f72b8090..4b766bc218 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 c4282b1128..80c36b456f 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 a8d767dfda..3a48e5d33a 100644
--- a/src/server/scripts/Commands/cs_debug.cpp
+++ b/src/server/scripts/Commands/cs_debug.cpp
@@ -104,7 +104,8 @@ public:
{ "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 @@ public:
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 cbfc4517c0..9f7bd95109 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 @@ public:
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 @@ public:
{
Player* player = handler->GetSession()->GetPlayer();
- CellCoord p(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()));
- Cell cell(p);
- cell.SetNoCreate();
-
Acore::RespawnDo u_do;
Acore::WorldObjectWorker<Acore::RespawnDo> 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 1dc1995f4f..70bcad38e2 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 d515388871..99193ef24c 100644
--- a/src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp
+++ b/src/server/scripts/EasternKingdoms/Stratholme/instance_stratholme.cpp
@@ -89,8 +89,6 @@ public:
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 @@ public:
{
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 @@ public:
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 @@ public:
case EVENT_BARON_TIME:
{
--_baronRunTime;
- instance->LoadGrid(4035.83f, -3336.31f);
Creature* baron = instance->GetCreature(_baronRivendareGUID);
if (baron && !baron->IsInCombat())
{
@@ -536,7 +531,6 @@ public:
}
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 5e6524d3d8..93d9618d0b 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 @@ public:
++_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 03c85d2281..34743573df 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 @@ public:
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 e0b161d2b4..3a0723c823 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp
@@ -227,10 +227,6 @@ public:
{
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 @@ public:
{
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 @@ public:
{
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 @@ public:
{
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 @@ public:
{
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 bbe92223a4..111a754f91 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"
// <mapId, zoneId>, show
std::map<std::pair<uint32, uint32>, 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 9c37799873..c6a17339a5 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 @@ public:
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 @@ public:
{
if (!arthas->IsAlive())
{
- EnsureGridLoaded();
arthas->setDeathState(DeathState::Dead);
arthas->Respawn();
}
@@ -352,16 +349,6 @@ public:
}
}
- 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 9528692439..fdbd0b4f74 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 @@ public:
if (instance->GetPlayersCountExceptGMs() <= 1)
CleanupInstance();
- EnsureGridLoaded();
-
if (_encounterProgress < ENCOUNTER_PROGRESS_BARRELS)
player->SendUpdateWorldState(WORLD_STATE_BARRELS_PLANTED, _barrelCount);
}
@@ -197,9 +195,6 @@ public:
{
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 @@ public:
}
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 @@ public:
}
case EVENT_SUMMON_LIEUTENANT:
{
- instance->LoadGrid(instancePositions[2].GetPositionX(), instancePositions[2].GetPositionY());
instance->SummonCreature(NPC_LIEUTENANT_DRAKE, instancePositions[2]);
break;
}
@@ -261,7 +252,6 @@ public:
if (!thrall->IsAlive())
{
++_attemptsCount;
- EnsureGridLoaded();
thrall->SetVisible(false);
Reposition(thrall);
thrall->setDeathState(DeathState::Dead);
@@ -293,12 +283,6 @@ public:
}
}
- 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 9265e4e91d..3946eca1fc 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 @@ public:
// 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 52d569572c..247a414df6 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 @@ public:
{
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 @@ public:
_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 7938f9b75f..98b2b1e87f 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 a4680ea553..40d4b02c49 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 @@ public:
_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 b8097f4c11..0fddc3be91 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 @@ public:
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 @@ public:
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 c2dbb9b1e9..d70eb3b625 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 @@ public:
{
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 7669ed17ad..fd43fce381 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 @@ public:
}
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 @@ public:
{
break;
}
- instance->LoadGrid(LeaderEscapePos.GetPositionX(), LeaderEscapePos.GetPositionY());
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
{
if (!c->IsAlive())
@@ -567,7 +565,6 @@ public:
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 e91e0b954a..337415ebbc 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 @@ public:
{
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 08932e3082..884cda64a8 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp
@@ -1537,7 +1537,6 @@ public:
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 3d7970eada..0393ace0ca 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
@@ -747,8 +747,6 @@ public:
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 f2640d9c52..e624110870 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 @@ public:
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 @@ public:
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 f9b1357e1c..550a84743f 100644
--- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
+++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp
@@ -821,8 +821,6 @@ public:
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 @@ public:
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 a987a7c82f..04ab6e9a73 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 @@ public:
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 @@ public:
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 @@ public:
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 d59e2fb17e..77d1b0a73a 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 84a4c66563..a3354a2a27 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 2ed91f6f98..c490108ed4 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 @@ public:
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);