Merge branch 'master' into Playerbot
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
@@ -51,8 +47,8 @@ inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
|
||||
return CellArea(center, center);
|
||||
}
|
||||
|
||||
CellCoord centerX = Acore::ComputeCellCoord(x - radius, y - radius).normalize();
|
||||
CellCoord centerY = Acore::ComputeCellCoord(x + radius, y + radius).normalize();
|
||||
CellCoord centerX = Acore::ComputeCellCoord(x + radius, y + radius).normalize();
|
||||
CellCoord centerY = Acore::ComputeCellCoord(x - radius, y - radius).normalize();
|
||||
|
||||
return CellArea(centerX, centerY);
|
||||
}
|
||||
@@ -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,16 @@ 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
|
||||
ASSERT(area.high_bound.x_coord >= area.low_bound.x_coord);
|
||||
ASSERT(area.high_bound.y_coord >= area.low_bound.y_coord);
|
||||
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 +128,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 +151,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 +194,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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -171,37 +170,29 @@ typedef CoordPair<TOTAL_NUMBER_OF_CELLS_PER_MAP> CellCoord;
|
||||
namespace Acore
|
||||
{
|
||||
template<class RET_TYPE, int CENTER_VAL>
|
||||
inline RET_TYPE Compute(float x, float y, float center_offset, float size)
|
||||
inline RET_TYPE Compute(float x, float y, float size)
|
||||
{
|
||||
// calculate and store temporary values in double format for having same result as same mySQL calculations
|
||||
double x_offset = (double(x) - center_offset) / size;
|
||||
double y_offset = (double(y) - center_offset) / size;
|
||||
int gx = (int)(CENTER_VAL - x / size);
|
||||
int gy = (int)(CENTER_VAL - y / size);
|
||||
|
||||
int x_val = int(x_offset + CENTER_VAL + 0.5f);
|
||||
int y_val = int(y_offset + CENTER_VAL + 0.5f);
|
||||
return RET_TYPE(x_val, y_val);
|
||||
return RET_TYPE(gx, gy);
|
||||
}
|
||||
|
||||
inline GridCoord ComputeGridCoord(float x, float y)
|
||||
{
|
||||
return Compute<GridCoord, CENTER_GRID_ID>(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS);
|
||||
return Compute<GridCoord, CENTER_GRID_ID>(x, y, 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);
|
||||
}
|
||||
|
||||
inline CellCoord ComputeCellCoord(float x, float y, float& x_off, float& y_off)
|
||||
{
|
||||
double x_offset = (double(x) - CENTER_GRID_CELL_OFFSET) / SIZE_OF_GRID_CELL;
|
||||
double y_offset = (double(y) - CENTER_GRID_CELL_OFFSET) / SIZE_OF_GRID_CELL;
|
||||
|
||||
int x_val = int(x_offset + CENTER_GRID_CELL_ID + 0.5f);
|
||||
int y_val = int(y_offset + CENTER_GRID_CELL_ID + 0.5f);
|
||||
x_off = (float(x_offset) - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
|
||||
y_off = (float(y_offset) - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
|
||||
return CellCoord(x_val, y_val);
|
||||
return Compute<CellCoord, CENTER_GRID_CELL_ID>(x, y, SIZE_OF_GRID_CELL);
|
||||
}
|
||||
|
||||
inline void NormalizeMapCoord(float& c)
|
||||
|
||||
@@ -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
|
||||
@@ -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&);
|
||||
+19
-28
@@ -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 LoadN(void);
|
||||
|
||||
template<class T> static void SetObjectCell(T* obj, CellCoord const& cellCoord);
|
||||
void LoadAllCellsInGrid();
|
||||
|
||||
private:
|
||||
Cell i_cell;
|
||||
NGridType& i_grid;
|
||||
Map* i_map;
|
||||
uint32 i_gameObjects;
|
||||
uint32 i_creatures;
|
||||
uint32 i_corpses;
|
||||
template<class T>
|
||||
void AddObjectHelper(Map* map, T* obj);
|
||||
|
||||
void LoadCreatures(CellGuidSet const& guid_set, Map* map);
|
||||
void LoadGameObjects(CellGuidSet const& guid_set, Map* map);
|
||||
|
||||
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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,157 @@
|
||||
#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(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY());
|
||||
}
|
||||
|
||||
void GridTerrainLoader::LoadVMap()
|
||||
{
|
||||
int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), _map->GetId(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GridTerrainLoader::LoadMMap()
|
||||
{
|
||||
if (!DisableMgr::IsPathfindingEnabled(_map))
|
||||
return;
|
||||
|
||||
int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(_map->GetId(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.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(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.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;
|
||||
|
||||
VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
MapGridType& _grid;
|
||||
Map* _map;
|
||||
};
|
||||
|
||||
class GridTerrainUnloader
|
||||
{
|
||||
public:
|
||||
GridTerrainUnloader(MapGridType& grid, Map* map)
|
||||
: _grid(grid), _map(map) { }
|
||||
|
||||
void UnloadTerrain();
|
||||
|
||||
private:
|
||||
MapGridType& _grid;
|
||||
Map* _map;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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&);
|
||||
Reference in New Issue
Block a user