fix(Core/Grids): Grid improvements (#20955)

This commit is contained in:
Takenbacon 2025-02-14 13:11:27 -08:00 committed by GitHub
parent 10183efd51
commit ee69a569c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 1955 additions and 2026 deletions

View File

@ -22,6 +22,7 @@
#include "DetourNavMesh.h"
#define MAX_NUMBER_OF_GRIDS 64
#define MAX_NUMBER_OF_CELLS 8
#define SIZE_OF_GRIDS 533.3333f
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'

View File

@ -751,11 +751,6 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement)
// if player is in world he can tell his friends about new achievement
else if (GetPlayer()->IsInWorld())
{
CellCoord p = Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
Cell cell(p);
cell.SetNoCreate();
Acore::BroadcastTextBuilder _builder(GetPlayer(), CHAT_MSG_ACHIEVEMENT, BROADCAST_TEXT_ACHIEVEMENT_EARNED, GetPlayer()->getGender(), GetPlayer(), achievement->ID);
Acore::LocalizedPacketDo<Acore::BroadcastTextBuilder> _localizer(_builder);
Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::BroadcastTextBuilder>> _worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), _localizer);

View File

@ -22,6 +22,7 @@
#include "MoveSplineInit.h"
#include "ObjectMgr.h"
#include "QueryResult.h"
#include "Timer.h"
#include "WaypointMgr.h"
FormationMgr::~FormationMgr()

View File

@ -21,6 +21,7 @@
#include "Log.h"
#include "ObjectMgr.h"
#include "QueryResult.h"
#include "Timer.h"
#include "Util.h"
#include <cmath>
#include <functional>

View File

@ -3098,18 +3098,9 @@ void WorldObject::BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& play
void WorldObject::GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry)
{
CellCoord pair(Acore::ComputeCellCoord(this->GetPositionX(), this->GetPositionY()));
Cell cell(pair);
cell.SetNoCreate();
Acore::AllCreaturesOfEntryInRange check(this, entry, radius);
Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange> searcher(this, creatureList, check);
TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange>, WorldTypeMapContainer> world_visitor(searcher);
cell.Visit(pair, world_visitor, *(this->GetMap()), *this, radius);
TypeContainerVisitor<Acore::CreatureListSearcher<Acore::AllCreaturesOfEntryInRange>, GridTypeMapContainer> grid_visitor(searcher);
cell.Visit(pair, grid_visitor, *(this->GetMap()), *this, radius);
Cell::VisitAllObjects(this, searcher, radius);
}
void WorldObject::AddToObjectUpdate()

View File

@ -19,6 +19,7 @@
#define TRANSPORTS_H
#include "GameObject.h"
#include "Timer.h"
#include "TransportMgr.h"
#include "VehicleDefines.h"
#include "ZoneScript.h"

View File

@ -20535,6 +20535,8 @@ void Unit::ExecuteDelayedUnitRelocationEvent()
}
}
GetMap()->LoadGridsInRange(*player, MAX_VISIBILITY_DISTANCE);
Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance
Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS);
relocateNoLarge.SendToSelf();

View File

@ -2341,8 +2341,8 @@ void ObjectMgr::AddCreatureToGrid(ObjectGuid::LowType guid, CreatureData const*
{
if (mask & 1)
{
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
cell_guids.creatures.insert(guid);
}
}
@ -2355,8 +2355,8 @@ void ObjectMgr::RemoveCreatureFromGrid(ObjectGuid::LowType guid, CreatureData co
{
if (mask & 1)
{
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
cell_guids.creatures.erase(guid);
}
}
@ -2454,7 +2454,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 mapId, float x, float y, float
AddCreatureToGrid(spawnId, &data);
// Spawn if necessary (loaded grids only)
if (!map->Instanceable() && !map->IsRemovalGrid(x, y))
if (!map->Instanceable() && !map->IsGridCreated(x, y))
{
Creature* creature = new Creature();
if (!creature->LoadCreatureFromDB(spawnId, map, true, true))
@ -2644,8 +2644,8 @@ void ObjectMgr::AddGameobjectToGrid(ObjectGuid::LowType guid, GameObjectData con
{
if (mask & 1)
{
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
cell_guids.gameobjects.insert(guid);
}
}
@ -2658,8 +2658,8 @@ void ObjectMgr::RemoveGameobjectFromGrid(ObjectGuid::LowType guid, GameObjectDat
{
if (mask & 1)
{
CellCoord cellCoord = Acore::ComputeCellCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
GridCoord gridCoord = Acore::ComputeGridCoord(data->posX, data->posY);
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][gridCoord.GetId()];
cell_guids.gameobjects.erase(guid);
}
}

View File

@ -1150,12 +1150,12 @@ public:
return nullptr;
}
CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id)
CellObjectGuids const& GetGridObjectGuids(uint16 mapid, uint8 spawnMode, uint32 gridId)
{
MapObjectGuids::const_iterator itr1 = _mapObjectGuidsStore.find(MAKE_PAIR32(mapid, spawnMode));
if (itr1 != _mapObjectGuidsStore.end())
{
CellObjectGuidsMap::const_iterator itr2 = itr1->second.find(cell_id);
CellObjectGuidsMap::const_iterator itr2 = itr1->second.find(gridId);
if (itr2 != itr1->second.end())
return itr2->second;
}

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;

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)
@ -66,7 +62,8 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T,
}
template<class T, class CONTAINER>
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float x_off, float y_off, float radius) const{
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float x_off, float y_off, float radius) const
{
if (!standing_cell.IsCoordValid())
return;
@ -101,23 +98,14 @@ inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T,
return;
}
//ALWAYS visit standing cell first!!! Since we deal with small radiuses
//it is very essential to call visitor for standing cell firstly...
map.Visit(*this, visitor);
// loop the cell range
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
{
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
{
CellCoord cellCoord(x, y);
//lets skip standing cell since we already visited it
if (cellCoord != standing_cell)
{
Cell r_zone(cellCoord);
r_zone.data.Part.nocreate = this->data.Part.nocreate;
map.Visit(r_zone, visitor);
}
Cell r_zone(cellCoord);
map.Visit(r_zone, visitor);
}
}
}
@ -138,7 +126,6 @@ inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map&
{
CellCoord cellCoord(x, y);
Cell r_zone(cellCoord);
r_zone.data.Part.nocreate = this->data.Part.nocreate;
map.Visit(r_zone, visitor);
}
}
@ -162,55 +149,41 @@ inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map&
//e.g. filling 2 trapezoids after filling central cell strip...
CellCoord cellCoord_left(x_start - step, y);
Cell r_zone_left(cellCoord_left);
r_zone_left.data.Part.nocreate = this->data.Part.nocreate;
map.Visit(r_zone_left, visitor);
//right trapezoid cell visit
CellCoord cellCoord_right(x_end + step, y);
Cell r_zone_right(cellCoord_right);
r_zone_right.data.Part.nocreate = this->data.Part.nocreate;
map.Visit(r_zone_right, visitor);
}
}
}
template<class T>
inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
inline void Cell::VisitGridObjects(WorldObject const* center_obj, T& visitor, float radius)
{
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
Cell cell(p);
if (dont_load)
{
cell.SetNoCreate();
}
TypeContainerVisitor<T, GridTypeMapContainer> gnotifier(visitor);
cell.Visit(p, gnotifier, *center_obj->GetMap(), *center_obj, radius);
}
template<class T>
inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
inline void Cell::VisitWorldObjects(WorldObject const* center_obj, T& visitor, float radius)
{
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
Cell cell(p);
if (dont_load)
{
cell.SetNoCreate();
}
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
}
template<class T>
inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius, bool dont_load /*= true*/)
inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, float radius)
{
CellCoord p(Acore::ComputeCellCoord(center_obj->GetPositionX(), center_obj->GetPositionY()));
Cell cell(p);
if (dont_load)
{
cell.SetNoCreate();
}
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
cell.Visit(p, wnotifier, *center_obj->GetMap(), *center_obj, radius);
@ -219,42 +192,30 @@ inline void Cell::VisitAllObjects(WorldObject const* center_obj, T& visitor, flo
}
template<class T>
inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
inline void Cell::VisitGridObjects(float x, float y, Map* map, T& visitor, float radius)
{
CellCoord p(Acore::ComputeCellCoord(x, y));
Cell cell(p);
if (dont_load)
{
cell.SetNoCreate();
}
TypeContainerVisitor<T, GridTypeMapContainer> gnotifier(visitor);
cell.Visit(p, gnotifier, *map, x, y, radius);
}
template<class T>
inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
inline void Cell::VisitWorldObjects(float x, float y, Map* map, T& visitor, float radius)
{
CellCoord p(Acore::ComputeCellCoord(x, y));
Cell cell(p);
if (dont_load)
{
cell.SetNoCreate();
}
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
cell.Visit(p, wnotifier, *map, x, y, radius);
}
template<class T>
inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius, bool dont_load /*= true*/)
inline void Cell::VisitAllObjects(float x, float y, Map* map, T& visitor, float radius)
{
CellCoord p(Acore::ComputeCellCoord(x, y));
Cell cell(p);
if (dont_load)
{
cell.SetNoCreate();
}
TypeContainerVisitor<T, WorldTypeMapContainer> wnotifier(visitor);
cell.Visit(p, wnotifier, *map, x, y, radius);

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

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

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;
@ -187,6 +186,13 @@ namespace Acore
return Compute<GridCoord, CENTER_GRID_ID>(x, y, CENTER_GRID_OFFSET, SIZE_OF_GRIDS);
}
inline GridCoord ComputeGridCoordSimple(float x, float y)
{
int gx = (int)(CENTER_GRID_ID - x / SIZE_OF_GRIDS);
int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS);
return GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy);
}
inline CellCoord ComputeCellCoord(float x, float y)
{
return Compute<CellCoord, CENTER_GRID_CELL_ID>(x, y, CENTER_GRID_CELL_OFFSET, SIZE_OF_GRID_CELL);

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

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&);

View File

@ -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

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;
}

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

View File

@ -0,0 +1,160 @@
#include "DisableMgr.h"
#include "GridTerrainLoader.h"
#include "MMapFactory.h"
#include "MMapMgr.h"
#include "ScriptMgr.h"
#include "VMapFactory.h"
#include "VMapMgr2.h"
void GridTerrainLoader::LoadTerrain()
{
LoadMap();
if (_map->GetInstanceId() == 0)
{
LoadVMap();
LoadMMap();
}
}
void GridTerrainLoader::LoadMap()
{
// Instances will point to the parent maps terrain data
if (_map->GetInstanceId() != 0)
{
// load grid map for base map
Map* parentMap = const_cast<Map*>(_map->GetParent());
// GetGridTerrainData will create the parent map grid
_grid.SetTerrainData(parentMap->GetGridTerrainDataSharedPtr(GridCoord(_grid.GetX(), _grid.GetY())));
return;
}
// map file name
std::string const mapFileName = Acore::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), _map->GetId(), GetX(), GetY());
// loading data
LOG_DEBUG("maps", "Loading map {}", mapFileName);
std::unique_ptr<GridTerrainData> terrainData = std::make_unique<GridTerrainData>();
TerrainMapDataReadResult loadResult = terrainData->Load(mapFileName);
if (loadResult == TerrainMapDataReadResult::Success)
_grid.SetTerrainData(std::move(terrainData));
else
{
if (loadResult == TerrainMapDataReadResult::InvalidMagic)
LOG_ERROR("maps", "Map file '{}' is from an incompatible clientversion. Please recreate using the mapextractor.", mapFileName);
else
LOG_DEBUG("maps", "Error (result: {}) loading map file: {}", uint32(loadResult), mapFileName);
}
sScriptMgr->OnLoadGridMap(_map, _grid.GetTerrainData(), GetX(), GetY());
}
void GridTerrainLoader::LoadVMap()
{
int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), _map->GetId(), GetX(), GetY());
switch (vmapLoadResult)
{
case VMAP::VMAP_LOAD_RESULT_OK:
LOG_DEBUG("maps", "VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY());
break;
case VMAP::VMAP_LOAD_RESULT_ERROR:
LOG_DEBUG("maps", "Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY());
break;
case VMAP::VMAP_LOAD_RESULT_IGNORED:
LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY());
break;
}
}
void GridTerrainLoader::LoadMMap()
{
if (!DisableMgr::IsPathfindingEnabled(_map))
return;
int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(_map->GetId(), GetX(), GetY());
switch (mmapLoadResult)
{
case MMAP::MMAP_LOAD_RESULT_OK:
LOG_DEBUG("maps", "MMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY());
break;
case MMAP::MMAP_LOAD_RESULT_ERROR:
LOG_DEBUG("maps", "Could not load MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY());
break;
case MMAP::MMAP_LOAD_RESULT_IGNORED:
LOG_DEBUG("maps", "Ignored MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), GetX(), GetY(), GetX(), GetY());
break;
}
}
bool GridTerrainLoader::ExistMap(uint32 mapid, int gx, int gy)
{
std::string const mapFileName = Acore::StringFormat("{}maps/{:03}{:02}{:02}.map", sWorld->GetDataPath(), mapid, gx, gy);
std::ifstream fileStream(mapFileName, std::ios::binary);
if (fileStream.fail())
{
LOG_DEBUG("maps", "Map file '{}': error opening file", mapFileName);
return false;
}
map_fileheader header;
if (!fileStream.read(reinterpret_cast<char*>(&header), sizeof(header)))
{
LOG_DEBUG("maps", "Map file '{}': unable to read header", mapFileName);
return false;
}
if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic)
{
LOG_ERROR("maps", "Map file '{}' is from an incompatible map version ({:.4u} v{}), {:.4s} v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files.",
mapFileName, 4, header.mapMagic, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic);
return false;
}
return true;
}
bool GridTerrainLoader::ExistVMap(uint32 mapid, int gx, int gy)
{
if (VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr())
{
if (vmgr->isMapLoadingEnabled())
{
VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy);
std::string name = vmgr->getDirFileName(mapid, gx, gy);
switch (result)
{
case VMAP::LoadResult::Success:
break;
case VMAP::LoadResult::FileNotFound:
LOG_DEBUG("maps", "VMap file '{}' does not exist", (sWorld->GetDataPath() + "vmaps/" + name));
LOG_DEBUG("maps", "Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory ({}), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "vmaps/"));
return false;
case VMAP::LoadResult::VersionMismatch:
LOG_ERROR("maps", "VMap file '{}' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name));
LOG_ERROR("maps", "This is because the version of the VMap file and the version of this module are different, please re-extract the maps with the tools compiled with this module.");
return false;
}
}
}
return true;
}
void GridTerrainUnloader::UnloadTerrain()
{
// Only parent maps manage terrain data
if (_map->GetInstanceId() != 0)
return;
int gx = (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetX();
int gy = (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetY();
VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(_map->GetId(), gx, gy);
MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(_map->GetId(), gx, gy);
}

View File

@ -0,0 +1,59 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACORE_GRID_TERRAIN_LOADER_H
#define ACORE_GRID_TERRAIN_LOADER_H
#include "GridDefines.h"
class GridTerrainLoader
{
public:
GridTerrainLoader(MapGridType& grid, Map* map)
: _grid(grid), _map(map) { }
void LoadTerrain();
static bool ExistMap(uint32 mapid, int gx, int gy);
static bool ExistVMap(uint32 mapid, int gx, int gy);
private:
void LoadMap();
void LoadVMap();
void LoadMMap();
uint16 GetX() { return (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetX(); }
uint16 GetY() { return (MAX_NUMBER_OF_GRIDS - 1) - _grid.GetY(); }
MapGridType& _grid;
Map* _map;
};
class GridTerrainUnloader
{
public:
GridTerrainUnloader(MapGridType& grid, Map* map)
: _grid(grid), _map(map) { }
void UnloadTerrain();
private:
MapGridType& _grid;
Map* _map;
};
#endif

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

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);
}

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

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

View File

@ -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"

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&);

View File

@ -777,16 +777,10 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData)
Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
CellCoord p = Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
Cell cell(p);
cell.SetNoCreate();
Acore::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit);
Acore::LocalizedPacketDo<Acore::EmoteChatBuilder > emote_do(emote_builder);
Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::EmoteChatBuilder > > emote_worker(GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), emote_do);
TypeContainerVisitor<Acore::PlayerDistWorker<Acore::LocalizedPacketDo<Acore::EmoteChatBuilder> >, WorldTypeMapContainer> message(emote_worker);
cell.Visit(p, message, *GetPlayer()->GetMap(), *GetPlayer(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
Cell::VisitWorldObjects(GetPlayer(), emote_worker, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit);

View File

@ -20,6 +20,7 @@
#include "ObjectMgr.h"
#include "PreparedStatement.h"
#include "QueryResult.h"
#include "Timer.h"
LootItemStorage::LootItemStorage()
{

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
#include "GameObjectModel.h"
#include "GridDefines.h"
#include "GridRefMgr.h"
#include "MapGridManager.h"
#include "MapRefMgr.h"
#include "ObjectDefines.h"
#include "ObjectGuid.h"
@ -33,6 +34,7 @@
#include "Position.h"
#include "SharedDefines.h"
#include "TaskScheduler.h"
#include "GridTerrainData.h"
#include <bitset>
#include <list>
#include <memory>
@ -81,101 +83,9 @@ struct ScriptAction
ScriptInfo const* script; // pointer to static script data
};
// ******************************************
// Map file format defines
// ******************************************
struct map_fileheader
{
uint32 mapMagic;
uint32 versionMagic;
uint32 buildMagic;
uint32 areaMapOffset;
uint32 areaMapSize;
uint32 heightMapOffset;
uint32 heightMapSize;
uint32 liquidMapOffset;
uint32 liquidMapSize;
uint32 holesOffset;
uint32 holesSize;
};
#define MAP_AREA_NO_AREA 0x0001
struct map_areaHeader
{
uint32 fourcc;
uint16 flags;
uint16 gridArea;
};
#define MAP_HEIGHT_NO_HEIGHT 0x0001
#define MAP_HEIGHT_AS_INT16 0x0002
#define MAP_HEIGHT_AS_INT8 0x0004
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
struct map_heightHeader
{
uint32 fourcc;
uint32 flags;
float gridHeight;
float gridMaxHeight;
};
#define MAP_LIQUID_NO_TYPE 0x0001
#define MAP_LIQUID_NO_HEIGHT 0x0002
struct map_liquidHeader
{
uint32 fourcc;
uint8 flags;
uint8 liquidFlags;
uint16 liquidType;
uint8 offsetX;
uint8 offsetY;
uint8 width;
uint8 height;
float liquidLevel;
};
enum LiquidStatus
{
LIQUID_MAP_NO_WATER = 0x00000000,
LIQUID_MAP_ABOVE_WATER = 0x00000001,
LIQUID_MAP_WATER_WALK = 0x00000002,
LIQUID_MAP_IN_WATER = 0x00000004,
LIQUID_MAP_UNDER_WATER = 0x00000008
};
#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)
#define MAP_LIQUID_STATUS_IN_CONTACT (MAP_LIQUID_STATUS_SWIMMING | LIQUID_MAP_WATER_WALK)
#define MAP_LIQUID_TYPE_NO_WATER 0x00
#define MAP_LIQUID_TYPE_WATER 0x01
#define MAP_LIQUID_TYPE_OCEAN 0x02
#define MAP_LIQUID_TYPE_MAGMA 0x04
#define MAP_LIQUID_TYPE_SLIME 0x08
#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT
#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations
#define MIN_UNLOAD_DELAY 1 // immediate unload
struct LiquidData
{
LiquidData() = default;
uint32 Entry{0};
uint32 Flags{0};
float Level{INVALID_HEIGHT};
float DepthLevel{INVALID_HEIGHT};
LiquidStatus Status{LIQUID_MAP_NO_WATER};
};
struct PositionFullTerrainStatus
{
PositionFullTerrainStatus() = default;
@ -196,71 +106,6 @@ enum LineOfSightChecks
LINEOFSIGHT_ALL_CHECKS = LINEOFSIGHT_CHECK_VMAP | LINEOFSIGHT_CHECK_GOBJECT_ALL
};
class GridMap
{
uint32 _flags;
union
{
float* m_V9;
uint16* m_uint16_V9;
uint8* m_uint8_V9;
};
union
{
float* m_V8;
uint16* m_uint16_V8;
uint8* m_uint8_V8;
};
int16* _maxHeight;
int16* _minHeight;
// Height level data
float _gridHeight;
float _gridIntHeightMultiplier;
// Area data
uint16* _areaMap;
// Liquid data
float _liquidLevel;
uint16* _liquidEntry;
uint8* _liquidFlags;
float* _liquidMap;
uint16 _gridArea;
uint16 _liquidGlobalEntry;
uint8 _liquidGlobalFlags;
uint8 _liquidOffX;
uint8 _liquidOffY;
uint8 _liquidWidth;
uint8 _liquidHeight;
uint16* _holes;
bool loadAreaData(FILE* in, uint32 offset, uint32 size);
bool loadHeightData(FILE* in, uint32 offset, uint32 size);
bool loadLiquidData(FILE* in, uint32 offset, uint32 size);
bool loadHolesData(FILE* in, uint32 offset, uint32 size);
[[nodiscard]] bool isHole(int row, int col) const;
// Get height functions and pointers
typedef float (GridMap::*GetHeightPtr) (float x, float y) const;
GetHeightPtr _gridGetHeight;
[[nodiscard]] float getHeightFromFloat(float x, float y) const;
[[nodiscard]] float getHeightFromUint16(float x, float y) const;
[[nodiscard]] float getHeightFromUint8(float x, float y) const;
[[nodiscard]] float getHeightFromFlat(float x, float y) const;
public:
GridMap();
~GridMap();
bool loadData(char* filaname);
void unloadData();
[[nodiscard]] uint16 getArea(float x, float y) const;
[[nodiscard]] inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
[[nodiscard]] float getMinHeight(float x, float y) const;
[[nodiscard]] float getLiquidLevel(float x, float y) const;
[[nodiscard]] LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const;
};
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
#if defined(__GNUC__)
#pragma pack(1)
@ -307,9 +152,10 @@ enum EncounterCreditType : uint8
ENCOUNTER_CREDIT_CAST_SPELL = 1,
};
class Map : public GridRefMgr<NGridType>
class Map : public GridRefMgr<MapGridType>
{
friend class MapReference;
friend class GridObjectLoader;
public:
Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr);
~Map() override;
@ -348,6 +194,7 @@ public:
[[nodiscard]] float GetVisibilityRange() const { return m_VisibleDistance; }
void SetVisibilityRange(float range) { m_VisibleDistance = range; }
void OnCreateMap();
//function for setting up visibility distance for maps on per-type/per-Id basis
virtual void InitVisibilityDistance();
@ -358,26 +205,28 @@ public:
template<class T, class CONTAINER> void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER>& visitor);
[[nodiscard]] bool IsRemovalGrid(float x, float y) const
{
GridCoord p = Acore::ComputeGridCoord(x, y);
return !getNGrid(p.x_coord, p.y_coord);
}
[[nodiscard]] bool IsGridLoaded(float x, float y) const
bool IsGridLoaded(GridCoord const& gridCoord) const;
bool IsGridLoaded(float x, float y) const
{
return IsGridLoaded(Acore::ComputeGridCoord(x, y));
}
bool IsGridCreated(GridCoord const& gridCoord) const;
bool IsGridCreated(float x, float y) const
{
return IsGridCreated(Acore::ComputeGridCoord(x, y));
}
void LoadGrid(float x, float y);
void LoadAllCells();
bool UnloadGrid(NGridType& ngrid);
void LoadAllGrids();
void LoadGridsInRange(Position const& center, float radius);
bool UnloadGrid(MapGridType& grid);
virtual void UnloadAll();
[[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; }
std::shared_ptr<GridTerrainData> GetGridTerrainDataSharedPtr(GridCoord const& gridCoord);
GridTerrainData* GetGridTerrainData(GridCoord const& gridCoord);
GridTerrainData* GetGridTerrainData(float x, float y);
static bool ExistMap(uint32 mapid, int gx, int gy);
static bool ExistVMap(uint32 mapid, int gx, int gy);
[[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; }
[[nodiscard]] Map const* GetParent() const { return m_parentMap; }
@ -627,8 +476,7 @@ public:
// Do whatever you want to all the players in map [including GameMasters], i.e.: param exec = [&](Player* p) { p->Whatever(); }
void DoForAllPlayers(std::function<void(Player*)> exec);
GridMap* GetGrid(float x, float y);
void EnsureGridCreated(const GridCoord&);
void EnsureGridCreated(GridCoord const& gridCoord);
[[nodiscard]] bool AllTransportsEmpty() const; // pussywizard
void AllTransportsRemovePassengers(); // pussywizard
[[nodiscard]] TransportsContainer const& GetAllTransports() const { return _transports; }
@ -659,13 +507,12 @@ public:
virtual std::string GetDebugInfo() const;
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
void LoadMap(int gx, int gy, bool reload = false);
uint32 GetCreatedGridsCount();
uint32 GetLoadedGridsCount();
uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y);
uint32 GetCreatedCellsInMapCount();
// Load MMap Data
void LoadMMap(int gx, int gy);
private:
template<class T> void InitializeObject(T* obj);
void AddCreatureToMoveList(Creature* c);
@ -679,33 +526,22 @@ private:
std::vector<GameObject*> _gameObjectsToMove;
std::vector<DynamicObject*> _dynamicObjectsToMove;
[[nodiscard]] bool IsGridLoaded(const GridCoord&) const;
void EnsureGridCreated_i(const GridCoord&);
bool EnsureGridLoaded(Cell const& cell);
MapGridType* GetMapGrid(uint16 const x, uint16 const y);
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
[[nodiscard]] NGridType* getNGrid(uint32 x, uint32 y) const
{
ASSERT(x < MAX_NUMBER_OF_GRIDS && y < MAX_NUMBER_OF_GRIDS);
return i_grids[x][y];
}
bool EnsureGridLoaded(Cell const&);
[[nodiscard]] bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x, y)->isGridObjectDataLoaded(); }
void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x, y)->setGridObjectDataLoaded(pLoaded); }
void setNGrid(NGridType* grid, uint32 x, uint32 y);
void ScriptsProcess();
void UpdateActiveCells(const float& x, const float& y, const uint32 t_diff);
void SendObjectUpdates();
protected:
// Type specific code for add/remove to/from grid
template<class T>
void AddToGrid(T* object, Cell const& cell);
std::mutex Lock;
std::mutex GridLock;
std::shared_mutex MMapLock;
MapGridManager _mapGridManager;
MapEntry const* i_mapEntry;
uint8 i_spawnMode;
uint32 i_InstanceId;
@ -739,10 +575,8 @@ private:
//InstanceMaps and BattlegroundMaps...
Map* m_parentMap;
NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
GridMap* GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP* TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP* TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
bool i_scriptLock;
std::unordered_set<WorldObject*> i_objectsToRemove;
@ -752,10 +586,6 @@ private:
typedef std::multimap<time_t, ScriptAction> ScriptScheduleMap;
ScriptScheduleMap m_scriptSchedule;
// Type specific code for add/remove to/from grid
template<class T>
void AddToGrid(T* object, Cell const& cell);
template<class T>
void DeleteFromWorld(T*);
@ -875,16 +705,14 @@ private:
template<class T, class CONTAINER>
inline void Map::Visit(Cell const& cell, TypeContainerVisitor<T, CONTAINER>& visitor)
{
const uint32 x = cell.GridX();
const uint32 y = cell.GridY();
const uint32 cell_x = cell.CellX();
const uint32 cell_y = cell.CellY();
uint32 const grid_x = cell.GridX();
uint32 const grid_y = cell.GridY();
if (!cell.NoCreate() || IsGridLoaded(GridCoord(x, y)))
{
EnsureGridLoaded(cell);
getNGrid(x, y)->VisitGrid(cell_x, cell_y, visitor);
}
// If grid is not loaded, nothing to visit.
if (!IsGridLoaded(GridCoord(grid_x, grid_y)))
return;
GetMapGrid(grid_x, grid_y)->VisitCell(cell.CellX(), cell.CellY(), visitor);
}
#endif

View File

@ -203,6 +203,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save,
InstanceMap* map = new InstanceMap(GetId(), InstanceId, difficulty, this);
ASSERT(map->IsDungeon());
m_InstancedMaps[InstanceId] = map;
map->LoadRespawnTimes();
map->LoadCorpseData();
@ -212,10 +213,11 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save,
else
map->CreateInstanceScript(false, "", 0);
map->OnCreateMap();
if (!save) // this is for sure a dungeon (assert above), no need to check here
sInstanceSaveMgr->AddInstanceSave(GetId(), InstanceId, difficulty);
m_InstancedMaps[InstanceId] = map;
return map;
}
@ -237,10 +239,13 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun
BattlegroundMap* map = new BattlegroundMap(GetId(), InstanceId, this, spawnMode);
ASSERT(map->IsBattlegroundOrArena());
m_InstancedMaps[InstanceId] = map;
map->SetBG(bg);
bg->SetBgMap(map);
m_InstancedMaps[InstanceId] = map;
map->OnCreateMap();
return map;
}

View File

@ -19,6 +19,7 @@
#include "Chat.h"
#include "DatabaseEnv.h"
#include "GridDefines.h"
#include "GridTerrainLoader.h"
#include "Group.h"
#include "InstanceSaveMgr.h"
#include "LFGMgr.h"
@ -83,13 +84,17 @@ Map* MapMgr::CreateBaseMap(uint32 id)
if (entry->Instanceable())
map = new MapInstanced(id);
else
{
map = new Map(id, 0, REGULAR_DIFFICULTY);
i_maps[id] = map;
if (!entry->Instanceable())
{
map->LoadRespawnTimes();
map->LoadCorpseData();
}
i_maps[id] = map;
map->OnCreateMap();
}
}
@ -303,7 +308,7 @@ bool MapMgr::ExistMapAndVMap(uint32 mapid, float x, float y)
int gx = 63 - p.x_coord;
int gy = 63 - p.y_coord;
return Map::ExistMap(mapid, gx, gy) && Map::ExistVMap(mapid, gx, gy);
return GridTerrainLoader::ExistMap(mapid, gx, gy) && GridTerrainLoader::ExistVMap(mapid, gx, gy);
}
bool MapMgr::IsValidMAP(uint32 mapid, bool startUp)

View File

@ -24,6 +24,7 @@
#include "MapInstanced.h"
#include "MapUpdater.h"
#include "Object.h"
#include "Timer.h"
class Transport;
class StaticTransport;

View File

@ -20,6 +20,7 @@
#include "GridDefines.h"
#include "Log.h"
#include "QueryResult.h"
#include "Timer.h"
WaypointMgr::WaypointMgr()
{

View File

@ -134,10 +134,9 @@ void ScriptMgr::OnDestroyMap(Map* map)
});
}
void ScriptMgr::OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy)
void ScriptMgr::OnLoadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy)
{
ASSERT(map);
ASSERT(gmap);
ForeachMaps<WorldMapScript>(map,
[&](WorldMapScript* script)
@ -158,7 +157,7 @@ void ScriptMgr::OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy)
});
}
void ScriptMgr::OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy)
void ScriptMgr::OnUnloadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy)
{
ASSERT(map);
ASSERT(gmap);

View File

@ -189,8 +189,8 @@ public: /* FormulaScript */
public: /* MapScript */
void OnCreateMap(Map* map);
void OnDestroyMap(Map* map);
void OnLoadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy);
void OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy);
void OnLoadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy);
void OnUnloadGridMap(Map* map, GridTerrainData* gmap, uint32 gx, uint32 gy);
void OnPlayerEnterMap(Map* map, Player* player);
void OnPlayerLeaveMap(Map* map, Player* player);
void OnMapUpdate(Map* map, uint32 diff);

View File

@ -98,10 +98,10 @@ public:
virtual void OnDestroy(TMap* /*map*/) { }
// Called when a grid map is loaded.
virtual void OnLoadGridMap(TMap* /*map*/, GridMap* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { }
virtual void OnLoadGridMap(TMap* /*map*/, GridTerrainData* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { }
// Called when a grid map is unloaded.
virtual void OnUnloadGridMap(TMap* /*map*/, GridMap* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { }
virtual void OnUnloadGridMap(TMap* /*map*/, GridTerrainData* /*gmap*/, uint32 /*gx*/, uint32 /*gy*/) { }
// Called when a player enters the map.
virtual void OnPlayerEnter(TMap* /*map*/, Player* /*player*/) { }

View File

@ -41,7 +41,7 @@ class CreatureAI;
class DynamicObject;
class GameObject;
class GameObjectAI;
class GridMap;
class GridTerrainData;
class Group;
class Guardian;
class Guild;

View File

@ -2160,10 +2160,6 @@ void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* refere
x = pos->GetPositionX();
y = pos->GetPositionY();
CellCoord p(Acore::ComputeCellCoord(x, y));
Cell cell(p);
cell.SetNoCreate();
Map* map = referer->GetMap();
if (searchInWorld)

View File

@ -1969,7 +1969,7 @@ void World::SetInitialWorldSettings()
if (map)
{
LOG_INFO("server.loading", ">> Loading All Grids For Map {}", map->GetId());
map->LoadAllCells();
map->LoadAllGrids();
}
}
}

View File

@ -104,7 +104,8 @@ public:
{ "moveflags", HandleDebugMoveflagsCommand, SEC_ADMINISTRATOR, Console::No },
{ "unitstate", HandleDebugUnitStateCommand, SEC_ADMINISTRATOR, Console::No },
{ "objectcount", HandleDebugObjectCountCommand, SEC_ADMINISTRATOR, Console::Yes},
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No }
{ "dummy", HandleDebugDummyCommand, SEC_ADMINISTRATOR, Console::No },
{ "mapdata", HandleDebugMapDataCommand, SEC_ADMINISTRATOR, Console::No }
};
static ChatCommandTable commandTable =
{
@ -1373,6 +1374,20 @@ public:
handler->SendSysMessage("This command does nothing right now. Edit your local core (cs_debug.cpp) to make it do whatever you need for testing.");
return true;
}
static bool HandleDebugMapDataCommand(ChatHandler* handler)
{
Cell cell(handler->GetPlayer()->GetPositionX(), handler->GetPlayer()->GetPositionY());
Map* map = handler->GetPlayer()->GetMap();
handler->PSendSysMessage("GridX {} GridY {}", cell.GridX(), cell.GridY());
handler->PSendSysMessage("CellX {} CellY {}", cell.CellX(), cell.CellY());
handler->PSendSysMessage("Created Grids: {} / {}", map->GetCreatedGridsCount(), MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS);
handler->PSendSysMessage("Loaded Grids: {} / {}", map->GetLoadedGridsCount(), MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS);
handler->PSendSysMessage("Created Cells In Grid: {} / {}", map->GetCreatedCellsInGridCount(cell.GridX(), cell.GridY()), MAX_NUMBER_OF_CELLS * MAX_NUMBER_OF_CELLS);
handler->PSendSysMessage("Created Cells In Map: {} / {}", map->GetCreatedCellsInMapCount(), TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP);
return true;
}
};
void AddSC_debug_commandscript()

View File

@ -25,6 +25,7 @@
#include "GameGraveyard.h"
#include "GameTime.h"
#include "GridNotifiers.h"
#include "GridTerrainLoader.h"
#include "Group.h"
#include "GuildMgr.h"
#include "IPLocation.h"
@ -589,8 +590,8 @@ public:
int gridX = 63 - gridCoord.x_coord;
int gridY = 63 - gridCoord.y_coord;
uint32 haveMap = Map::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0;
uint32 haveVMap = Map::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0;
uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0;
uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0;
uint32 haveMMAP = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()) ? 1 : 0;
if (haveVMap)
@ -2404,10 +2405,6 @@ public:
{
Player* player = handler->GetSession()->GetPlayer();
CellCoord p(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()));
Cell cell(p);
cell.SetNoCreate();
Acore::RespawnDo u_do;
Acore::WorldObjectWorker<Acore::RespawnDo> worker(player, u_do);
Cell::VisitGridObjects(player, worker, player->GetGridActivationRange());

View File

@ -172,7 +172,6 @@ struct boss_nightbane : public BossAI
{
if (action == ACTION_START_INTRO)
{
me->GetMap()->LoadGrid(-11260.0f, -1771.0f); // load grid at far end of intro path
me->GetMap()->SetVisibilityRange(DEFAULT_VISIBILITY_INSTANCE + 100.0f); // see nightbane
me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
_phase = PHASE_INTRO;

View File

@ -89,8 +89,6 @@ public:
if (_baronRunTime > 0)
if (Aura* aura = player->AddAura(SPELL_BARON_ULTIMATUM, player))
aura->SetDuration(_baronRunTime * MINUTE * IN_MILLISECONDS);
if (_barthilasrunProgress == DONE)
instance->LoadGrid(3663.229980f, -3619.139893f);
}
void OnCreatureCreate(Creature* creature) override
@ -261,7 +259,6 @@ public:
{
if (_zigguratState1 == 2 && _zigguratState2 == 2 && _zigguratState3 == 2)
{
instance->LoadGrid(4035.83f, -3336.31f);
if (Creature* baron = instance->GetCreature(_baronRivendareGUID))
baron->AI()->Talk(SAY_BRAON_ZIGGURAT_FALL_YELL);
@ -301,7 +298,6 @@ public:
DoCastSpellOnPlayers(SPELL_BARON_ULTIMATUM);
events.ScheduleEvent(EVENT_BARON_TIME, 60000);
instance->LoadGrid(4035.83f, -3336.31f);
if (Creature* baron = instance->GetCreature(_baronRivendareGUID))
baron->AI()->Talk(SAY_BARON_INIT_YELL);
}
@ -505,7 +501,6 @@ public:
case EVENT_BARON_TIME:
{
--_baronRunTime;
instance->LoadGrid(4035.83f, -3336.31f);
Creature* baron = instance->GetCreature(_baronRivendareGUID);
if (baron && !baron->IsInCombat())
{
@ -536,7 +531,6 @@ public:
}
case EVENT_EXECUTE_PRISONER:
{
instance->LoadGrid(4035.83f, -3336.31f);
Creature* baron = instance->GetCreature(_baronRivendareGUID);
if (baron && baron->IsAlive())
{

View File

@ -116,7 +116,6 @@ public:
++_defendersKilled;
if (_defendersKilled == DEFENDERS_COUNT)
{
instance->LoadGrid(-425.89f, -86.07f);
if (Creature* jammal = instance->GetCreature(_jammalanGUID))
jammal->AI()->Talk(0);
if (GameObject* forcefield = instance->GetGameObject(_forcefieldGUID))

View File

@ -103,8 +103,6 @@ public:
void OnPlayerEnter(Player* player) override
{
instance->LoadGrid(1477.94f, 643.22f);
instance->LoadGrid(1641.45f, 988.08f);
if (GameObject* gobj = GetGameObject(DATA_ICEBARRIER))
gobj->SendUpdateToPlayer(player);
}

View File

@ -227,10 +227,6 @@ public:
{
if (InstanceScript* instance = player->GetInstanceScript())
{
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
// Without this, the creature never says anything, because it doesn't load in time.
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
hakkar->setActive(true);
@ -254,10 +250,6 @@ public:
{
if (InstanceScript* instance = player->GetInstanceScript())
{
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
// Without this, the creature never says anything, because it doesn't load in time.
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
if (hakkar->GetAI())
@ -280,10 +272,6 @@ public:
{
if (InstanceScript* instance = player->GetInstanceScript())
{
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
// Without this, the creature never says anything, because it doesn't load in time.
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
if (hakkar->GetAI())
@ -306,10 +294,6 @@ public:
{
if (InstanceScript* instance = player->GetInstanceScript())
{
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
// Without this, the creature never says anything, because it doesn't load in time.
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
if (hakkar->GetAI())
@ -332,10 +316,6 @@ public:
{
if (InstanceScript* instance = player->GetInstanceScript())
{
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
// Without this, the creature never says anything, because it doesn't load in time.
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
{
if (hakkar->GetAI())

View File

@ -28,6 +28,7 @@
#include "firework_show_Undercity.h"
#include "GameObjectAI.h"
#include "GameObjectScript.h"
#include "Timer.h"
// <mapId, zoneId>, show
std::map<std::pair<uint32, uint32>, FireworkShow const *> const FireworkShowStore = {

View File

@ -67,8 +67,6 @@ public:
if (instance->GetPlayersCountExceptGMs() == 1)
SetData(DATA_ARTHAS_REPOSITION, 2);
EnsureGridLoaded();
if (plr->getRace() != RACE_HUMAN && plr->getRace() != RACE_DWARF && plr->getRace() != RACE_GNOME)
plr->CastSpell(plr, ((plr->getGender() == GENDER_MALE) ? SPELL_HUMAN_MALE : SPELL_HUMAN_FEMALE), true);
}
@ -224,7 +222,6 @@ public:
{
if (!arthas->IsAlive())
{
EnsureGridLoaded();
arthas->setDeathState(DeathState::Dead);
arthas->Respawn();
}
@ -352,16 +349,6 @@ public:
}
}
void EnsureGridLoaded()
{
instance->LoadGrid(LeaderIntroPos1.GetPositionX(), LeaderIntroPos1.GetPositionY());
instance->LoadGrid(LeaderIntroPos2.GetPositionX(), LeaderIntroPos2.GetPositionY());
instance->LoadGrid(LeaderIntroPos3.GetPositionX(), LeaderIntroPos3.GetPositionY());
instance->LoadGrid(LeaderIntroPos4.GetPositionX(), LeaderIntroPos4.GetPositionY());
instance->LoadGrid(LeaderIntroPos5.GetPositionX(), LeaderIntroPos5.GetPositionY());
instance->LoadGrid(LeaderIntroPos6.GetPositionX(), LeaderIntroPos6.GetPositionY());
}
std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;

View File

@ -69,8 +69,6 @@ public:
if (instance->GetPlayersCountExceptGMs() <= 1)
CleanupInstance();
EnsureGridLoaded();
if (_encounterProgress < ENCOUNTER_PROGRESS_BARRELS)
player->SendUpdateWorldState(WORLD_STATE_BARRELS_PLANTED, _barrelCount);
}
@ -197,9 +195,6 @@ public:
{
case EVENT_INITIAL_BARRELS_FLAME:
{
instance->LoadGrid(instancePositions[0].GetPositionX(), instancePositions[0].GetPositionY());
instance->LoadGrid(instancePositions[1].GetPositionX(), instancePositions[1].GetPositionY());
for (ObjectGuid const& guid : _prisonersSet)
if (Creature* orc = instance->GetCreature(guid))
{
@ -220,9 +215,6 @@ public:
}
case EVENT_FINAL_BARRELS_FLAME:
{
instance->LoadGrid(instancePositions[0].GetPositionX(), instancePositions[0].GetPositionY());
instance->LoadGrid(instancePositions[1].GetPositionX(), instancePositions[1].GetPositionY());
if (_encounterProgress == ENCOUNTER_PROGRESS_NONE)
{
Map::PlayerList const& players = instance->GetPlayers();
@ -250,7 +242,6 @@ public:
}
case EVENT_SUMMON_LIEUTENANT:
{
instance->LoadGrid(instancePositions[2].GetPositionX(), instancePositions[2].GetPositionY());
instance->SummonCreature(NPC_LIEUTENANT_DRAKE, instancePositions[2]);
break;
}
@ -261,7 +252,6 @@ public:
if (!thrall->IsAlive())
{
++_attemptsCount;
EnsureGridLoaded();
thrall->SetVisible(false);
Reposition(thrall);
thrall->setDeathState(DeathState::Dead);
@ -293,12 +283,6 @@ public:
}
}
void EnsureGridLoaded()
{
for (uint8 i = 0; i < THRALL_POSITIONS_COUNT; ++i)
instance->LoadGrid(thrallPositions[i].GetPositionX(), thrallPositions[i].GetPositionY());
}
void ReadSaveDataMore(std::istringstream& data) override
{
data >> _encounterProgress;

View File

@ -74,7 +74,6 @@ public:
// prevent getting stuck if event fails during boss break
_noBossSpawnDelay = true;
instance->LoadGrid(-2023.0f, 7121.0f);
if (Creature* medivh = GetCreature(DATA_MEDIVH))
{
medivh->Respawn();

View File

@ -95,11 +95,9 @@ public:
{
case TYPE_EAST_WING_PROGRESS:
_eastWingProgress = data;
instance->LoadGrid(-56.59f, -269.12f);
break;
case TYPE_WEST_WING_PROGRESS:
_westWingProgress = data;
instance->LoadGrid(132.626f, 625.913f);
break;
case TYPE_NORTH_WING_PROGRESS:
_northWingProgress = data;
@ -113,7 +111,6 @@ public:
_pylonsState |= data;
if (_pylonsState == ALL_PYLONS_OFF) // all five active, 31
{
instance->LoadGrid(-38.08f, 812.44f);
if (Creature* immol = instance->GetCreature(_immoltharGUID))
{
immol->setActive(true);

View File

@ -82,9 +82,6 @@ struct boss_kurinnaxx : public BossAI
{
if (killer)
{
killer->GetMap()->LoadGrid(-9502.80f, 2042.65f); // Ossirian grid
killer->GetMap()->LoadGrid(-8538.17f, 1486.09f); // Andorov run path grid
if (Player* player = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
{
if (Creature* creature = player->SummonCreature(NPC_ANDOROV, -8538.177f, 1486.0956f, 32.39054f, 3.7638654f, TEMPSUMMON_CORPSE_DESPAWN, 0))

View File

@ -87,7 +87,6 @@ public:
_rajaxWaveCounter == 0 && // if non-zero, encounter is in progress
!_andorovGUID) // cleared if he is dead
{
instance->LoadGrid(-8538.17f, 1486.09f); // Andorov run path grid
if (Creature* creature = player->SummonCreature(NPC_ANDOROV, -8538.177f, 1486.0956f, 32.39054f, 3.7638654f, TEMPSUMMON_CORPSE_DESPAWN, 0))
{
creature->setActive(true);

View File

@ -64,7 +64,6 @@ public:
if (type == TYPE_LORD_COBRAHN && _encounters[TYPE_LORD_SERPENTIS] != DONE)
{
instance->LoadGrid(-120.163f, -24.624f);
if (Creature* serpentis = instance->GetCreature(SerpentisGUID))
serpentis->AI()->Talk(SAY_SERPENTIS);
}
@ -72,7 +71,6 @@ public:
if (type != TYPE_MUTANUS && _encounters[TYPE_LORD_COBRAHN] == DONE && _encounters[TYPE_LORD_PYTHAS] == DONE &&
_encounters[TYPE_LADY_ANACONDRA] == DONE && _encounters[TYPE_LORD_SERPENTIS] == DONE)
{
instance->LoadGrid(-134.97f, 125.402f);
if (Creature* disciple = instance->GetCreature(DiscipleOfNaralexGUID))
disciple->AI()->Talk(SAY_DISCIPLE);
}

View File

@ -63,7 +63,6 @@ public:
{
if (GetBossState(DATA_HALION_INTRO_DONE) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE)
{
instance->LoadGrid(3156.0f, 537.0f);
if (Creature* halionController = instance->GetCreature(HalionControllerGUID))
halionController->AI()->DoAction(ACTION_INTRO_HALION);
}

View File

@ -325,7 +325,6 @@ public:
}
else
{
instance->LoadGrid(PathWaypoints[PATH_WP_COUNT - 1].GetPositionX(), PathWaypoints[PATH_WP_COUNT - 1].GetPositionY());
creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true);
creature->StopMovingOnCurrentPos();
}
@ -515,7 +514,6 @@ public:
{
break;
}
instance->LoadGrid(LeaderEscapePos.GetPositionX(), LeaderEscapePos.GetPositionY());
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
{
if (!c->IsAlive())
@ -567,7 +565,6 @@ public:
case DATA_LICH_KING:
if (data == DONE)
{
instance->LoadGrid(PathWaypoints[0].GetPositionX(), PathWaypoints[0].GetPositionY());
EncounterMask |= (1 << DATA_LICH_KING);
if (Creature* c = instance->GetCreature(NPC_LeaderGUID))
c->setActive(false);

View File

@ -78,7 +78,6 @@ public:
{
InstanceScript::OnPlayerEnter(player);
instance->LoadGrid(LeaderIntroPos.GetPositionX(), LeaderIntroPos.GetPositionY());
if (Creature* c = instance->GetCreature(GetGuidData(DATA_LEADER_FIRST_GUID)))
c->AI()->SetData(DATA_START_INTRO, 0);
}

View File

@ -1537,7 +1537,6 @@ public:
if (!instance->GetData(DATA_SINDRAGOSA_FROSTWYRMS) && instance->GetBossState(DATA_SINDRAGOSA) != IN_PROGRESS)
{
player->GetMap()->LoadGrid(SindragosaSpawnPos.GetPositionX(), SindragosaSpawnPos.GetPositionY());
if (Creature* sindragosa = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SINDRAGOSA)))
sindragosa->AI()->DoAction(ACTION_START_FROSTWYRM);
}

View File

@ -747,8 +747,6 @@ public:
me->setActive(true);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToAll(true);
// Load Grid with Sister Svalna
me->GetMap()->LoadGrid(4356.71f, 2484.33f);
if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
svalna->AI()->DoAction(ACTION_START_GAUNTLET);
for (uint32 i = 0; i < 4; ++i)

View File

@ -651,7 +651,6 @@ public:
FrostwyrmGUIDs.erase(creature->GetSpawnId());
if (FrostwyrmGUIDs.empty())
{
instance->LoadGrid(SindragosaSpawnPos.GetPositionX(), SindragosaSpawnPos.GetPositionY());
if (Creature* boss = instance->SummonCreature(NPC_SINDRAGOSA, SindragosaSpawnPos))
boss->AI()->DoAction(ACTION_START_FROSTWYRM);
}
@ -1190,7 +1189,6 @@ public:
if (GameObject* pillars = instance->GetGameObject(PillarsUnchainedGUID))
pillars->SetRespawnTime(7 * DAY);
instance->LoadGrid(JainaSpawnPos.GetPositionX(), JainaSpawnPos.GetPositionY());
instance->SummonCreature(NPC_LADY_JAINA_PROUDMOORE_QUEST, JainaSpawnPos);
instance->SummonCreature(NPC_MURADIN_BRONZEBEARD_QUEST, MuradinSpawnPos);
instance->SummonCreature(NPC_UTHER_THE_LIGHTBRINGER_QUEST, UtherSpawnPos);

View File

@ -821,8 +821,6 @@ public:
if (state == DONE)
{
_speakTimer = 1;
// Load KT's grid so he can talk
instance->LoadGrid(3763.43f, -5115.87f);
}
else if (state == NOT_STARTED)
{
@ -1061,8 +1059,6 @@ public:
switch (events.ExecuteEvent())
{
case EVENT_KELTHUZAD_WING_TAUNT:
// Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work.
instance->LoadGrid(3749.67f, -5114.06f);
if (Creature* kelthuzad = instance->GetCreature(_kelthuzadGUID))
{
kelthuzad->AI()->Talk(_currentWingTaunt);

View File

@ -178,7 +178,6 @@ public:
void OnPlayerEnter(Player* player) override
{
// mimiron tram:
instance->LoadGrid(2307.0f, 284.632f);
if (GameObject* MimironTram = instance->GetGameObject(m_mimironTramGUID))
{
player->UpdateVisibilityOf(MimironTram);
@ -537,10 +536,7 @@ public:
break;
case GO_KEEPERS_GATE:
if (GetData(TYPE_MIMIRON) == DONE && GetData(TYPE_FREYA) == DONE && GetData(TYPE_HODIR) == DONE && GetData(TYPE_THORIM) == DONE)
{
instance->LoadGrid(1903.0f, 248.0f);
gameObject->RemoveGameObjectFlag(GO_FLAG_LOCKED);
}
m_keepersgateGUID = gameObject->GetGUID();
break;
@ -752,8 +748,6 @@ public:
case EVENT_TOWER_OF_FROST_DESTROYED:
case EVENT_TOWER_OF_FLAMES_DESTROYED:
{
instance->LoadGrid(364.0f, -16.0f); //make sure leviathan is loaded
instance->LoadGrid(364.0f, 32.0f); //make sure Mimiron's and Thorim's Targetting Crystal are loaded
m_leviathanTowers[type - EVENT_TOWER_OF_LIFE_DESTROYED] = data;
for (uint8 i = 0; i < 2; ++i)
{

View File

@ -89,7 +89,7 @@ void UpdateCreatureHalaa(ObjectGuid::LowType spawnId, Map* map, float x, float y
sObjectMgr->AddCreatureToGrid(spawnId, &data);
// Spawn if necessary (loaded grids only)
if (!map->Instanceable() && !map->IsRemovalGrid(x, y))
if (!map->Instanceable() && !map->IsGridCreated(x, y))
{
Creature* creature = new Creature();
if (!creature->LoadCreatureFromDB(spawnId, map, true, true))

View File

@ -125,7 +125,6 @@ struct boss_kelidan_the_breaker : public BossAI
{
Talk(SAY_DIE);
_JustDied();
me->GetMap()->LoadGrid(0, -111.0f);
}
void ApplyImmunities(bool apply)

View File

@ -99,7 +99,6 @@ public:
if (type == DATA_ENTERED_ROOM && data == DATA_ENTERED_ROOM && RescueTimer == 100 * MINUTE * IN_MILLISECONDS)
{
DoCastSpellOnPlayers(SPELL_KARGATHS_EXECUTIONER_1);
instance->LoadGrid(230, -80);
if (Creature* kargath = GetCreature(DATA_KARGATH))
sCreatureTextMgr->SendChat(kargath, GetTeamIdInInstance() == TEAM_ALLIANCE ? 3 : 4, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP);