/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by the * Free Software Foundation; either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef _MAP_BUILDER_H #define _MAP_BUILDER_H #include #include #include #include #include #include "Optional.h" #include "TerrainBuilder.h" #include "DetourNavMesh.h" #include "PCQueue.h" #include "Recast.h" using namespace VMAP; namespace MMAP { struct MapTiles { MapTiles() : m_mapId(uint32(-1)) {} MapTiles(uint32 id, std::set* tiles) : m_mapId(id), m_tiles(tiles) {} ~MapTiles() = default; uint32 m_mapId; std::set* m_tiles{nullptr}; bool operator==(uint32 id) const { return m_mapId == id; } }; typedef std::list TileList; struct Tile { Tile() {} ~Tile() { rcFreeCompactHeightfield(chf); rcFreeContourSet(cset); rcFreeHeightField(solid); rcFreePolyMesh(pmesh); rcFreePolyMeshDetail(dmesh); } rcCompactHeightfield* chf{nullptr}; rcHeightfield* solid{nullptr}; rcContourSet* cset{nullptr}; rcPolyMesh* pmesh{nullptr}; rcPolyMeshDetail* dmesh{nullptr}; }; struct TileConfig { TileConfig(bool bigBaseUnit) { // these are WORLD UNIT based metrics // this are basic unit dimentions // value have to divide GRID_SIZE(533.3333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc ) BASE_UNIT_DIM = bigBaseUnit ? 0.5333333f : 0.2666666f; // All are in UNIT metrics! VERTEX_PER_MAP = int(GRID_SIZE / BASE_UNIT_DIM + 0.5f); VERTEX_PER_TILE = bigBaseUnit ? 40 : 80; // must divide VERTEX_PER_MAP TILES_PER_MAP = VERTEX_PER_MAP / VERTEX_PER_TILE; } float BASE_UNIT_DIM; int VERTEX_PER_MAP; int VERTEX_PER_TILE; int TILES_PER_MAP; }; struct TileInfo { TileInfo() : m_mapId(uint32(-1)), m_tileX(), m_tileY(), m_navMeshParams() {} uint32 m_mapId; uint32 m_tileX; uint32 m_tileY; dtNavMeshParams m_navMeshParams; }; /// @todo: move this to its own file. For now it will stay here to keep the changes to a minimum, especially in the cpp file class MapBuilder; class TileBuilder { public: TileBuilder(MapBuilder* mapBuilder, bool skipLiquid, bool bigBaseUnit, bool debugOutput); TileBuilder(TileBuilder&&) = default; ~TileBuilder(); void WorkerThread(); void WaitCompletion(); void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh); // move map building void buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, float bmin[3], float bmax[3], dtNavMesh* navMesh); bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const; private: bool m_bigBaseUnit; bool m_debugOutput; MapBuilder* m_mapBuilder; TerrainBuilder* m_terrainBuilder; std::thread m_workerThread; // build performance - not really used for now rcContext* m_rcContext; }; class MapBuilder { friend class TileBuilder; public: MapBuilder(float maxWalkableAngle, bool skipLiquid, bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds, bool debugOutput, bool bigBaseUnit, int mapid, char const* offMeshFilePath, unsigned int threads); ~MapBuilder(); void buildMeshFromFile(char* name); // builds an mmap tile for the specified map and its mesh void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY); // builds list of maps, then builds all of mmap tiles (based on the skip settings) void buildMaps(Optional mapID); private: // builds all mmap tiles for the specified map id (ignores skip settings) void buildMap(uint32 mapID); // detect maps and tiles void discoverTiles(); std::set* getTileList(uint32 mapID); void buildNavMesh(uint32 mapID, dtNavMesh*& navMesh); void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const; void getGridBounds(uint32 mapID, uint32& minX, uint32& minY, uint32& maxX, uint32& maxY) const; bool shouldSkipMap(uint32 mapID) const; bool isTransportMap(uint32 mapID) const; bool isContinentMap(uint32 mapID) const; rcConfig GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const; uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone) const; uint32 currentPercentageDone() const; TerrainBuilder* m_terrainBuilder{nullptr}; TileList m_tiles; bool m_debugOutput; const char* m_offMeshFilePath; unsigned int m_threads; bool m_skipContinents; bool m_skipJunkMaps; bool m_skipBattlegrounds; bool m_skipLiquid; float m_maxWalkableAngle; bool m_bigBaseUnit; int32 m_mapid; std::atomic m_totalTiles; std::atomic m_totalTilesProcessed; // build performance - not really used for now rcContext* m_rcContext{nullptr}; std::vector m_tileBuilders; ProducerConsumerQueue _queue; std::atomic _cancelationToken; }; } #endif