Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-02-19 22:29:36 +08:00
parent d1032678ff
commit 7d431dc796
277 changed files with 7092 additions and 5050 deletions
+10 -14
View File
@@ -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;
+14 -51
View File
@@ -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);
-131
View File
@@ -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
+75
View File
@@ -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
+17 -26
View File
@@ -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)
-76
View File
@@ -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
+138
View File
@@ -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&);
@@ -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
+617
View File
@@ -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;
}
+255
View File
@@ -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
+157
View File
@@ -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());
}
+56
View File
@@ -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
+154
View File
@@ -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
+129
View File
@@ -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);
}
+62
View File
@@ -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
-113
View File
@@ -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"
-245
View File
@@ -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&);