mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-15 04:32:35 -04:00
Happy new year Conflicts: src/server/bnetserver/Authentication/AuthCodes.h src/server/bnetserver/Authentication/BattlenetPacketCrypt.cpp src/server/bnetserver/Authentication/BattlenetPacketCrypt.h src/server/bnetserver/Packets/AchievementPackets.h src/server/bnetserver/Packets/AuthenticationPackets.cpp src/server/bnetserver/Packets/AuthenticationPackets.h src/server/bnetserver/Packets/BitStream.cpp src/server/bnetserver/Packets/BitStream.h src/server/bnetserver/Packets/CachePackets.cpp src/server/bnetserver/Packets/CachePackets.h src/server/bnetserver/Packets/ChatPackets.h src/server/bnetserver/Packets/ConnectionPackets.cpp src/server/bnetserver/Packets/ConnectionPackets.h src/server/bnetserver/Packets/FriendsPackets.cpp src/server/bnetserver/Packets/FriendsPackets.h src/server/bnetserver/Packets/PacketManager.cpp src/server/bnetserver/Packets/PacketManager.h src/server/bnetserver/Packets/Packets.h src/server/bnetserver/Packets/PacketsBase.cpp src/server/bnetserver/Packets/PacketsBase.h src/server/bnetserver/Packets/PresencePackets.cpp src/server/bnetserver/Packets/PresencePackets.h src/server/bnetserver/Packets/ProfilePackets.h src/server/bnetserver/Packets/SupportPackets.h src/server/bnetserver/Packets/WoWRealmPackets.cpp src/server/bnetserver/Packets/WoWRealmPackets.h src/server/bnetserver/Realms/RealmList.cpp src/server/bnetserver/Realms/WorldListener.cpp src/server/bnetserver/Realms/WorldListener.h src/server/bnetserver/Server/ComponentManager.cpp src/server/bnetserver/Server/ComponentManager.h src/server/bnetserver/Server/ModuleManager.cpp src/server/bnetserver/Server/ModuleManager.h src/server/bnetserver/Server/Session.cpp src/server/bnetserver/Server/Session.h src/server/bnetserver/Server/SessionManager.cpp src/server/bnetserver/Server/SessionManager.h src/server/game/Accounts/BattlenetAccountMgr.cpp src/server/game/Accounts/BattlenetAccountMgr.h src/server/game/Battlegrounds/Zones/BattlegroundBFG.cpp src/server/game/Battlegrounds/Zones/BattlegroundBFG.h src/server/game/Battlegrounds/Zones/BattlegroundTP.cpp src/server/game/Battlegrounds/Zones/BattlegroundTP.h src/server/game/Entities/AreaTrigger/AreaTrigger.cpp src/server/game/Entities/AreaTrigger/AreaTrigger.h src/server/game/Entities/Item/ItemTemplate.cpp src/server/game/Guilds/GuildFinderMgr.cpp src/server/game/Guilds/GuildFinderMgr.h src/server/game/Handlers/GuildFinderHandler.cpp src/server/game/Handlers/VoidStorageHandler.cpp src/server/game/Movement/MovementStructures.cpp src/server/game/Movement/MovementStructures.h src/server/game/Movement/PathGenerator.cpp src/server/game/Server/BattlenetServerManager.cpp src/server/game/Server/BattlenetServerManager.h src/server/game/Server/Packet.cpp src/server/game/Server/Packet.h src/server/game/Server/Packets/AchievementPackets.cpp src/server/game/Server/Packets/AchievementPackets.h src/server/game/Server/Packets/AuctionHousePackets.cpp src/server/game/Server/Packets/AuctionHousePackets.h src/server/game/Server/Packets/AuthenticationPackets.cpp src/server/game/Server/Packets/AuthenticationPackets.h src/server/game/Server/Packets/BattlegroundPackets.cpp src/server/game/Server/Packets/BattlegroundPackets.h src/server/game/Server/Packets/ChannelPackets.cpp src/server/game/Server/Packets/ChannelPackets.h src/server/game/Server/Packets/CharacterPackets.cpp src/server/game/Server/Packets/CharacterPackets.h src/server/game/Server/Packets/ChatPackets.cpp src/server/game/Server/Packets/ChatPackets.h src/server/game/Server/Packets/ClientConfigPackets.cpp src/server/game/Server/Packets/ClientConfigPackets.h src/server/game/Server/Packets/CombatLogPackets.cpp src/server/game/Server/Packets/CombatLogPackets.h src/server/game/Server/Packets/CombatPackets.cpp src/server/game/Server/Packets/CombatPackets.h src/server/game/Server/Packets/EquipmentSetPackets.cpp src/server/game/Server/Packets/EquipmentSetPackets.h src/server/game/Server/Packets/GameObjectPackets.cpp src/server/game/Server/Packets/GameObjectPackets.h src/server/game/Server/Packets/GuildPackets.cpp src/server/game/Server/Packets/GuildPackets.h src/server/game/Server/Packets/ItemPackets.cpp src/server/game/Server/Packets/ItemPackets.h src/server/game/Server/Packets/LootPackets.h src/server/game/Server/Packets/MiscPackets.cpp src/server/game/Server/Packets/MiscPackets.h src/server/game/Server/Packets/MovementPackets.cpp src/server/game/Server/Packets/MovementPackets.h src/server/game/Server/Packets/NPCPackets.cpp src/server/game/Server/Packets/NPCPackets.h src/server/game/Server/Packets/QueryPackets.cpp src/server/game/Server/Packets/QueryPackets.h src/server/game/Server/Packets/QuestPackets.cpp src/server/game/Server/Packets/QuestPackets.h src/server/game/Server/Packets/ReputationPackets.cpp src/server/game/Server/Packets/ReputationPackets.h src/server/game/Server/Packets/SpellPackets.cpp src/server/game/Server/Packets/SpellPackets.h src/server/game/Server/Packets/SystemPackets.cpp src/server/game/Server/Packets/SystemPackets.h src/server/game/Server/Packets/TalentPackets.cpp src/server/game/Server/Packets/TalentPackets.h src/server/game/Server/Packets/TradePackets.h src/server/game/Server/Packets/WorldStatePackets.cpp src/server/game/Server/Packets/WorldStatePackets.h src/server/game/Server/WorldSocket.cpp src/server/ipc/CMakeLists.txt src/server/ipc/Commands.cpp src/server/ipc/Commands.h src/server/ipc/ZMQTask.cpp src/server/ipc/ZMQTask.h src/server/ipc/ZmqContext.cpp src/server/ipc/ZmqContext.h src/server/ipc/ZmqListener.cpp src/server/ipc/ZmqListener.h src/server/ipc/ZmqMux.cpp src/server/ipc/ZmqMux.h src/server/ipc/ZmqWorker.cpp src/server/ipc/ZmqWorker.h src/server/scripts/Commands/cs_battlenet_account.cpp src/server/scripts/Commands/cs_mmaps.cpp src/server/scripts/EasternKingdoms/BaradinHold/boss_alizabal.cpp src/server/scripts/EasternKingdoms/BaradinHold/boss_occuthar.cpp src/server/scripts/EasternKingdoms/BaradinHold/boss_pit_lord_argaloth.cpp src/server/scripts/EasternKingdoms/BaradinHold/instance_baradin_hold.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.h src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_ascendant_lord_obsidius.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_beauty.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_corla.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_karsh_steelbender.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_romogg_bonecrusher.cpp src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockCaverns/instance_blackrock_caverns.cpp src/server/scripts/EasternKingdoms/Deadmines/deadmines.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_daakara.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_halazzi.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_janalai.cpp src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp src/server/scripts/EasternKingdoms/ZulAman/instance_zulaman.cpp src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp src/server/scripts/EasternKingdoms/ZulAman/zulaman.h src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo_the_godbreaker.cpp src/server/scripts/EasternKingdoms/ZulGurub/boss_kilnara.cpp src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp src/server/scripts/EasternKingdoms/zone_ironforge.cpp src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp src/server/scripts/EasternKingdoms/zone_tirisfal_glades.cpp src/server/scripts/Kalimdor/Firelands/boss_alysrazor.cpp src/server/scripts/Kalimdor/Firelands/firelands.h src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp src/server/scripts/Kalimdor/HallsOfOrigination/boss_anraphet.cpp src/server/scripts/Kalimdor/HallsOfOrigination/boss_earthrager_ptah.cpp src/server/scripts/Kalimdor/HallsOfOrigination/boss_temple_guardian_anhuur.cpp src/server/scripts/Kalimdor/HallsOfOrigination/halls_of_origination.h src/server/scripts/Kalimdor/HallsOfOrigination/instance_halls_of_origination.cpp src/server/scripts/Kalimdor/zone_azshara.cpp src/server/scripts/Kalimdor/zone_darkshore.cpp src/server/scripts/Kalimdor/zone_felwood.cpp src/server/scripts/Kalimdor/zone_moonglade.cpp src/server/scripts/Kalimdor/zone_orgrimmar.cpp src/server/scripts/Kalimdor/zone_stonetalon_mountains.cpp src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp src/server/scripts/Maelstrom/Stonecore/stonecore.cpp src/server/scripts/Maelstrom/Stonecore/stonecore.h src/server/shared/Cryptography/Authentication/AuthCrypt.h src/server/shared/Cryptography/Authentication/PacketCrypt.cpp src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp src/server/shared/Cryptography/HmacHash.cpp src/server/shared/Cryptography/SHA256.cpp src/server/shared/Cryptography/SHA256.h src/server/shared/Database/Implementation/HotfixDatabase.cpp src/server/shared/Database/Implementation/HotfixDatabase.h src/server/shared/Realm/Realm.cpp src/server/shared/Realm/Realm.h src/tools/connection_patcher/CMakeLists.txt src/tools/connection_patcher/Constants/BinaryTypes.hpp src/tools/connection_patcher/Helper.cpp src/tools/connection_patcher/Helper.hpp src/tools/connection_patcher/Patcher.cpp src/tools/connection_patcher/Patcher.hpp src/tools/connection_patcher/Patches/Common.hpp src/tools/connection_patcher/Patches/Mac.hpp src/tools/connection_patcher/Patches/Windows.hpp src/tools/connection_patcher/Patterns/Common.hpp src/tools/connection_patcher/Patterns/Mac.hpp src/tools/connection_patcher/Patterns/Windows.hpp src/tools/connection_patcher/Program.cpp src/tools/map_extractor/loadlib/DBFilesClientList.h
1009 lines
35 KiB
C++
1009 lines
35 KiB
C++
/*
|
|
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 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 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 <limits.h>
|
|
|
|
#include "PathCommon.h"
|
|
#include "MapBuilder.h"
|
|
|
|
#include "MapTree.h"
|
|
#include "ModelInstance.h"
|
|
|
|
#include "DetourNavMeshBuilder.h"
|
|
#include "DetourNavMesh.h"
|
|
#include "DetourCommon.h"
|
|
|
|
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
|
#define MMAP_VERSION 5
|
|
|
|
struct MmapTileHeader
|
|
{
|
|
uint32 mmapMagic;
|
|
uint32 dtVersion;
|
|
uint32 mmapVersion;
|
|
uint32 size;
|
|
bool usesLiquids : 1;
|
|
|
|
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
|
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
|
|
};
|
|
|
|
namespace MMAP
|
|
{
|
|
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
|
|
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
|
|
bool debugOutput, bool bigBaseUnit, const char* offMeshFilePath) :
|
|
m_terrainBuilder (NULL),
|
|
m_debugOutput (debugOutput),
|
|
m_offMeshFilePath (offMeshFilePath),
|
|
m_skipContinents (skipContinents),
|
|
m_skipJunkMaps (skipJunkMaps),
|
|
m_skipBattlegrounds (skipBattlegrounds),
|
|
m_maxWalkableAngle (maxWalkableAngle),
|
|
m_bigBaseUnit (bigBaseUnit),
|
|
m_rcContext (NULL),
|
|
_cancelationToken (false)
|
|
{
|
|
m_terrainBuilder = new TerrainBuilder(skipLiquid);
|
|
|
|
m_rcContext = new rcContext(false);
|
|
|
|
discoverTiles();
|
|
}
|
|
|
|
/**************************************************************************/
|
|
MapBuilder::~MapBuilder()
|
|
{
|
|
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
|
{
|
|
(*it).m_tiles->clear();
|
|
delete (*it).m_tiles;
|
|
}
|
|
|
|
delete m_terrainBuilder;
|
|
delete m_rcContext;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::discoverTiles()
|
|
{
|
|
std::vector<std::string> files;
|
|
uint32 mapID, tileX, tileY, tileID, count = 0;
|
|
char filter[12];
|
|
|
|
printf("Discovering maps... ");
|
|
getDirContents(files, "maps");
|
|
for (uint32 i = 0; i < files.size(); ++i)
|
|
{
|
|
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
|
if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
|
|
{
|
|
m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
|
|
count++;
|
|
}
|
|
}
|
|
|
|
files.clear();
|
|
getDirContents(files, "vmaps", "*.vmtree");
|
|
for (uint32 i = 0; i < files.size(); ++i)
|
|
{
|
|
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
|
if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end())
|
|
{
|
|
m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>));
|
|
count++;
|
|
}
|
|
}
|
|
printf("found %u.\n", count);
|
|
|
|
count = 0;
|
|
printf("Discovering tiles... ");
|
|
for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr)
|
|
{
|
|
std::set<uint32>* tiles = (*itr).m_tiles;
|
|
mapID = (*itr).m_mapId;
|
|
|
|
sprintf(filter, "%03u*.vmtile", mapID);
|
|
files.clear();
|
|
getDirContents(files, "vmaps", filter);
|
|
for (uint32 i = 0; i < files.size(); ++i)
|
|
{
|
|
tileX = uint32(atoi(files[i].substr(7,2).c_str()));
|
|
tileY = uint32(atoi(files[i].substr(4,2).c_str()));
|
|
tileID = StaticMapTree::packTileID(tileY, tileX);
|
|
|
|
tiles->insert(tileID);
|
|
count++;
|
|
}
|
|
|
|
sprintf(filter, "%03u*", mapID);
|
|
files.clear();
|
|
getDirContents(files, "maps", filter);
|
|
for (uint32 i = 0; i < files.size(); ++i)
|
|
{
|
|
tileY = uint32(atoi(files[i].substr(3,2).c_str()));
|
|
tileX = uint32(atoi(files[i].substr(5,2).c_str()));
|
|
tileID = StaticMapTree::packTileID(tileX, tileY);
|
|
|
|
if (tiles->insert(tileID).second)
|
|
count++;
|
|
}
|
|
}
|
|
printf("found %u.\n\n", count);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
std::set<uint32>* MapBuilder::getTileList(uint32 mapID)
|
|
{
|
|
TileList::iterator itr = std::find(m_tiles.begin(), m_tiles.end(), mapID);
|
|
if (itr != m_tiles.end())
|
|
return (*itr).m_tiles;
|
|
|
|
std::set<uint32>* tiles = new std::set<uint32>();
|
|
m_tiles.emplace_back(MapTiles(mapID, tiles));
|
|
return tiles;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
void MapBuilder::WorkerThread()
|
|
{
|
|
while (1)
|
|
{
|
|
uint32 mapId;
|
|
|
|
_queue.WaitAndPop(mapId);
|
|
|
|
if (_cancelationToken)
|
|
return;
|
|
|
|
buildMap(mapId);
|
|
}
|
|
}
|
|
|
|
void MapBuilder::buildAllMaps(int threads)
|
|
{
|
|
for (int i = 0; i < threads; ++i)
|
|
{
|
|
_workerThreads.push_back(std::thread(&MapBuilder::WorkerThread, this));
|
|
}
|
|
|
|
m_tiles.sort([](MapTiles a, MapTiles b)
|
|
{
|
|
return a.m_tiles->size() > b.m_tiles->size();
|
|
});
|
|
|
|
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
|
{
|
|
uint32 mapId = it->m_mapId;
|
|
if (!shouldSkipMap(mapId))
|
|
{
|
|
if (threads > 0)
|
|
_queue.Push(mapId);
|
|
else
|
|
buildMap(mapId);
|
|
}
|
|
}
|
|
|
|
while (!_queue.Empty())
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
}
|
|
|
|
_cancelationToken = true;
|
|
|
|
_queue.Cancel();
|
|
|
|
for (auto& thread : _workerThreads)
|
|
{
|
|
thread.join();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY)
|
|
{
|
|
maxX = INT_MAX;
|
|
maxY = INT_MAX;
|
|
minX = INT_MIN;
|
|
minY = INT_MIN;
|
|
|
|
float bmin[3] = { 0, 0, 0 };
|
|
float bmax[3] = { 0, 0, 0 };
|
|
float lmin[3] = { 0, 0, 0 };
|
|
float lmax[3] = { 0, 0, 0 };
|
|
MeshData meshData;
|
|
|
|
// make sure we process maps which don't have tiles
|
|
// initialize the static tree, which loads WDT models
|
|
if (!m_terrainBuilder->loadVMap(mapID, 64, 64, meshData))
|
|
return;
|
|
|
|
// get the coord bounds of the model data
|
|
if (meshData.solidVerts.size() + meshData.liquidVerts.size() == 0)
|
|
return;
|
|
|
|
// get the coord bounds of the model data
|
|
if (meshData.solidVerts.size() && meshData.liquidVerts.size())
|
|
{
|
|
rcCalcBounds(meshData.solidVerts.getCArray(), meshData.solidVerts.size() / 3, bmin, bmax);
|
|
rcCalcBounds(meshData.liquidVerts.getCArray(), meshData.liquidVerts.size() / 3, lmin, lmax);
|
|
rcVmin(bmin, lmin);
|
|
rcVmax(bmax, lmax);
|
|
}
|
|
else if (meshData.solidVerts.size())
|
|
rcCalcBounds(meshData.solidVerts.getCArray(), meshData.solidVerts.size() / 3, bmin, bmax);
|
|
else
|
|
rcCalcBounds(meshData.liquidVerts.getCArray(), meshData.liquidVerts.size() / 3, lmin, lmax);
|
|
|
|
// convert coord bounds to grid bounds
|
|
maxX = 32 - bmin[0] / GRID_SIZE;
|
|
maxY = 32 - bmin[2] / GRID_SIZE;
|
|
minX = 32 - bmax[0] / GRID_SIZE;
|
|
minY = 32 - bmax[2] / GRID_SIZE;
|
|
}
|
|
|
|
void MapBuilder::buildMeshFromFile(char* name)
|
|
{
|
|
FILE* file = fopen(name, "rb");
|
|
if (!file)
|
|
return;
|
|
|
|
printf("Building mesh from file\n");
|
|
int tileX, tileY, mapId;
|
|
if (fread(&mapId, sizeof(int), 1, file) != 1)
|
|
{
|
|
fclose(file);
|
|
return;
|
|
}
|
|
if (fread(&tileX, sizeof(int), 1, file) != 1)
|
|
{
|
|
fclose(file);
|
|
return;
|
|
}
|
|
if (fread(&tileY, sizeof(int), 1, file) != 1)
|
|
{
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
dtNavMesh* navMesh = NULL;
|
|
buildNavMesh(mapId, navMesh);
|
|
if (!navMesh)
|
|
{
|
|
printf("Failed creating navmesh! \n");
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
uint32 verticesCount, indicesCount;
|
|
if (fread(&verticesCount, sizeof(uint32), 1, file) != 1)
|
|
{
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
if (fread(&indicesCount, sizeof(uint32), 1, file) != 1)
|
|
{
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
float* verts = new float[verticesCount];
|
|
int* inds = new int[indicesCount];
|
|
|
|
if (fread(verts, sizeof(float), verticesCount, file) != verticesCount)
|
|
{
|
|
fclose(file);
|
|
delete[] verts;
|
|
delete[] inds;
|
|
return;
|
|
}
|
|
|
|
if (fread(inds, sizeof(int), indicesCount, file) != indicesCount)
|
|
{
|
|
fclose(file);
|
|
delete[] verts;
|
|
delete[] inds;
|
|
return;
|
|
}
|
|
|
|
MeshData data;
|
|
|
|
for (uint32 i = 0; i < verticesCount; ++i)
|
|
data.solidVerts.append(verts[i]);
|
|
delete[] verts;
|
|
|
|
for (uint32 i = 0; i < indicesCount; ++i)
|
|
data.solidTris.append(inds[i]);
|
|
delete[] inds;
|
|
|
|
TerrainBuilder::cleanVertices(data.solidVerts, data.solidTris);
|
|
// get bounds of current tile
|
|
float bmin[3], bmax[3];
|
|
getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
|
|
|
|
// build navmesh tile
|
|
buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
|
|
fclose(file);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY)
|
|
{
|
|
dtNavMesh* navMesh = NULL;
|
|
buildNavMesh(mapID, navMesh);
|
|
if (!navMesh)
|
|
{
|
|
printf("Failed creating navmesh! \n");
|
|
return;
|
|
}
|
|
|
|
buildTile(mapID, tileX, tileY, navMesh);
|
|
dtFreeNavMesh(navMesh);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::buildMap(uint32 mapID)
|
|
{
|
|
#ifndef __APPLE__
|
|
//printf("[Thread %u] Building map %03u:\n", uint32(ACE_Thread::self()), mapID);
|
|
#endif
|
|
|
|
std::set<uint32>* tiles = getTileList(mapID);
|
|
|
|
// make sure we process maps which don't have tiles
|
|
if (!tiles->size())
|
|
{
|
|
// convert coord bounds to grid bounds
|
|
uint32 minX, minY, maxX, maxY;
|
|
getGridBounds(mapID, minX, minY, maxX, maxY);
|
|
|
|
// add all tiles within bounds to tile list.
|
|
for (uint32 i = minX; i <= maxX; ++i)
|
|
for (uint32 j = minY; j <= maxY; ++j)
|
|
tiles->insert(StaticMapTree::packTileID(i, j));
|
|
}
|
|
|
|
if (!tiles->empty())
|
|
{
|
|
// build navMesh
|
|
dtNavMesh* navMesh = NULL;
|
|
buildNavMesh(mapID, navMesh);
|
|
if (!navMesh)
|
|
{
|
|
printf("[Map %03i] Failed creating navmesh!\n", mapID);
|
|
return;
|
|
}
|
|
|
|
// now start building mmtiles for each tile
|
|
printf("[Map %03i] We have %u tiles. \n", mapID, (unsigned int)tiles->size());
|
|
for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
|
|
{
|
|
uint32 tileX, tileY;
|
|
|
|
// unpack tile coords
|
|
StaticMapTree::unpackTileID((*it), tileX, tileY);
|
|
|
|
if (shouldSkipTile(mapID, tileX, tileY))
|
|
continue;
|
|
|
|
buildTile(mapID, tileX, tileY, navMesh);
|
|
}
|
|
|
|
dtFreeNavMesh(navMesh);
|
|
}
|
|
|
|
printf("[Map %03i] Complete!\n", mapID);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
|
|
{
|
|
printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY);
|
|
|
|
MeshData meshData;
|
|
|
|
// get heightmap data
|
|
m_terrainBuilder->loadMap(mapID, tileX, tileY, meshData);
|
|
|
|
// get model data
|
|
m_terrainBuilder->loadVMap(mapID, tileY, tileX, meshData);
|
|
|
|
// if there is no data, give up now
|
|
if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
|
|
return;
|
|
|
|
// remove unused vertices
|
|
TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
|
|
TerrainBuilder::cleanVertices(meshData.liquidVerts, meshData.liquidTris);
|
|
|
|
// gather all mesh data for final data check, and bounds calculation
|
|
G3D::Array<float> allVerts;
|
|
allVerts.append(meshData.liquidVerts);
|
|
allVerts.append(meshData.solidVerts);
|
|
|
|
if (!allVerts.size())
|
|
return;
|
|
|
|
// get bounds of current tile
|
|
float bmin[3], bmax[3];
|
|
getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
|
|
|
|
m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_offMeshFilePath);
|
|
|
|
// build navmesh tile
|
|
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::buildNavMesh(uint32 mapID, dtNavMesh* &navMesh)
|
|
{
|
|
std::set<uint32>* tiles = getTileList(mapID);
|
|
|
|
// old code for non-statically assigned bitmask sizes:
|
|
///*** calculate number of bits needed to store tiles & polys ***/
|
|
//int tileBits = dtIlog2(dtNextPow2(tiles->size()));
|
|
//if (tileBits < 1) tileBits = 1; // need at least one bit!
|
|
//int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits;
|
|
|
|
int polyBits = STATIC_POLY_BITS;
|
|
|
|
int maxTiles = tiles->size();
|
|
int maxPolysPerTile = 1 << polyBits;
|
|
|
|
/*** calculate bounds of map ***/
|
|
|
|
uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
|
|
for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
|
|
{
|
|
StaticMapTree::unpackTileID(*it, tileX, tileY);
|
|
|
|
if (tileX > tileXMax)
|
|
tileXMax = tileX;
|
|
else if (tileX < tileXMin)
|
|
tileXMin = tileX;
|
|
|
|
if (tileY > tileYMax)
|
|
tileYMax = tileY;
|
|
else if (tileY < tileYMin)
|
|
tileYMin = tileY;
|
|
}
|
|
|
|
// use Max because '32 - tileX' is negative for values over 32
|
|
float bmin[3], bmax[3];
|
|
getTileBounds(tileXMax, tileYMax, NULL, 0, bmin, bmax);
|
|
|
|
/*** now create the navmesh ***/
|
|
|
|
// navmesh creation params
|
|
dtNavMeshParams navMeshParams;
|
|
memset(&navMeshParams, 0, sizeof(dtNavMeshParams));
|
|
navMeshParams.tileWidth = GRID_SIZE;
|
|
navMeshParams.tileHeight = GRID_SIZE;
|
|
rcVcopy(navMeshParams.orig, bmin);
|
|
navMeshParams.maxTiles = maxTiles;
|
|
navMeshParams.maxPolys = maxPolysPerTile;
|
|
|
|
navMesh = dtAllocNavMesh();
|
|
printf("[Map %03i] Creating navMesh...\n", mapID);
|
|
if (!navMesh->init(&navMeshParams))
|
|
{
|
|
printf("[Map %03i] Failed creating navmesh! \n", mapID);
|
|
return;
|
|
}
|
|
|
|
char fileName[25];
|
|
sprintf(fileName, "mmaps/%03u.mmap", mapID);
|
|
|
|
FILE* file = fopen(fileName, "wb");
|
|
if (!file)
|
|
{
|
|
dtFreeNavMesh(navMesh);
|
|
char message[1024];
|
|
sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName);
|
|
perror(message);
|
|
return;
|
|
}
|
|
|
|
// now that we know navMesh params are valid, we can write them to file
|
|
fwrite(&navMeshParams, sizeof(dtNavMeshParams), 1, file);
|
|
fclose(file);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
|
|
MeshData &meshData, float bmin[3], float bmax[3],
|
|
dtNavMesh* navMesh)
|
|
{
|
|
// console output
|
|
char tileString[20];
|
|
sprintf(tileString, "[Map %03i] [%02i,%02i]: ", mapID, tileX, tileY);
|
|
printf("%s Building movemap tiles...\n", tileString);
|
|
|
|
IntermediateValues iv;
|
|
|
|
float* tVerts = meshData.solidVerts.getCArray();
|
|
int tVertCount = meshData.solidVerts.size() / 3;
|
|
int* tTris = meshData.solidTris.getCArray();
|
|
int tTriCount = meshData.solidTris.size() / 3;
|
|
|
|
float* lVerts = meshData.liquidVerts.getCArray();
|
|
int lVertCount = meshData.liquidVerts.size() / 3;
|
|
int* lTris = meshData.liquidTris.getCArray();
|
|
int lTriCount = meshData.liquidTris.size() / 3;
|
|
uint8* lTriFlags = meshData.liquidType.getCArray();
|
|
|
|
// 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 )
|
|
const static float BASE_UNIT_DIM = m_bigBaseUnit ? 0.5333333f : 0.2666666f;
|
|
|
|
// All are in UNIT metrics!
|
|
const static int VERTEX_PER_MAP = int(GRID_SIZE/BASE_UNIT_DIM + 0.5f);
|
|
const static int VERTEX_PER_TILE = m_bigBaseUnit ? 40 : 80; // must divide VERTEX_PER_MAP
|
|
const static int TILES_PER_MAP = VERTEX_PER_MAP/VERTEX_PER_TILE;
|
|
|
|
rcConfig config;
|
|
memset(&config, 0, sizeof(rcConfig));
|
|
|
|
rcVcopy(config.bmin, bmin);
|
|
rcVcopy(config.bmax, bmax);
|
|
|
|
config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
|
|
config.cs = BASE_UNIT_DIM;
|
|
config.ch = BASE_UNIT_DIM;
|
|
config.walkableSlopeAngle = m_maxWalkableAngle;
|
|
config.tileSize = VERTEX_PER_TILE;
|
|
config.walkableRadius = m_bigBaseUnit ? 1 : 2;
|
|
config.borderSize = config.walkableRadius + 3;
|
|
config.maxEdgeLen = VERTEX_PER_TILE + 1; // anything bigger than tileSize
|
|
config.walkableHeight = m_bigBaseUnit ? 3 : 6;
|
|
// a value >= 3|6 allows npcs to walk over some fences
|
|
// a value >= 4|8 allows npcs to walk over all fences
|
|
config.walkableClimb = m_bigBaseUnit ? 4 : 8;
|
|
config.minRegionArea = rcSqr(60);
|
|
config.mergeRegionArea = rcSqr(50);
|
|
config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
|
|
config.detailSampleDist = config.cs * 64;
|
|
config.detailSampleMaxError = config.ch * 2;
|
|
|
|
// this sets the dimensions of the heightfield - should maybe happen before border padding
|
|
rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
|
|
|
|
// allocate subregions : tiles
|
|
Tile* tiles = new Tile[TILES_PER_MAP * TILES_PER_MAP];
|
|
|
|
// Initialize per tile config.
|
|
rcConfig tileCfg = config;
|
|
tileCfg.width = config.tileSize + config.borderSize*2;
|
|
tileCfg.height = config.tileSize + config.borderSize*2;
|
|
|
|
// merge per tile poly and detail meshes
|
|
rcPolyMesh** pmmerge = new rcPolyMesh*[TILES_PER_MAP * TILES_PER_MAP];
|
|
rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[TILES_PER_MAP * TILES_PER_MAP];
|
|
int nmerge = 0;
|
|
// build all tiles
|
|
for (int y = 0; y < TILES_PER_MAP; ++y)
|
|
{
|
|
for (int x = 0; x < TILES_PER_MAP; ++x)
|
|
{
|
|
Tile& tile = tiles[x + y * TILES_PER_MAP];
|
|
|
|
// Calculate the per tile bounding box.
|
|
tileCfg.bmin[0] = config.bmin[0] + float(x*config.tileSize - config.borderSize)*config.cs;
|
|
tileCfg.bmin[2] = config.bmin[2] + float(y*config.tileSize - config.borderSize)*config.cs;
|
|
tileCfg.bmax[0] = config.bmin[0] + float((x+1)*config.tileSize + config.borderSize)*config.cs;
|
|
tileCfg.bmax[2] = config.bmin[2] + float((y+1)*config.tileSize + config.borderSize)*config.cs;
|
|
|
|
// build heightfield
|
|
tile.solid = rcAllocHeightfield();
|
|
if (!tile.solid || !rcCreateHeightfield(m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
|
|
{
|
|
printf("%s Failed building heightfield! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
// mark all walkable tiles, both liquids and solids
|
|
unsigned char* triFlags = new unsigned char[tTriCount];
|
|
memset(triFlags, NAV_GROUND, tTriCount*sizeof(unsigned char));
|
|
rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
|
|
rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb);
|
|
delete[] triFlags;
|
|
|
|
rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *tile.solid);
|
|
rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
|
|
rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid);
|
|
|
|
rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
|
|
|
|
// compact heightfield spans
|
|
tile.chf = rcAllocCompactHeightfield();
|
|
if (!tile.chf || !rcBuildCompactHeightfield(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf))
|
|
{
|
|
printf("%s Failed compacting heightfield! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
// build polymesh intermediates
|
|
if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, *tile.chf))
|
|
{
|
|
printf("%s Failed eroding area! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
if (!rcBuildDistanceField(m_rcContext, *tile.chf))
|
|
{
|
|
printf("%s Failed building distance field! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
if (!rcBuildRegions(m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
|
|
{
|
|
printf("%s Failed building regions! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
tile.cset = rcAllocContourSet();
|
|
if (!tile.cset || !rcBuildContours(m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset))
|
|
{
|
|
printf("%s Failed building contours! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
// build polymesh
|
|
tile.pmesh = rcAllocPolyMesh();
|
|
if (!tile.pmesh || !rcBuildPolyMesh(m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh))
|
|
{
|
|
printf("%s Failed building polymesh! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
tile.dmesh = rcAllocPolyMeshDetail();
|
|
if (!tile.dmesh || !rcBuildPolyMeshDetail(m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.dmesh))
|
|
{
|
|
printf("%s Failed building polymesh detail! \n", tileString);
|
|
continue;
|
|
}
|
|
|
|
// free those up
|
|
// we may want to keep them in the future for debug
|
|
// but right now, we don't have the code to merge them
|
|
rcFreeHeightField(tile.solid);
|
|
tile.solid = NULL;
|
|
rcFreeCompactHeightfield(tile.chf);
|
|
tile.chf = NULL;
|
|
rcFreeContourSet(tile.cset);
|
|
tile.cset = NULL;
|
|
|
|
pmmerge[nmerge] = tile.pmesh;
|
|
dmmerge[nmerge] = tile.dmesh;
|
|
nmerge++;
|
|
}
|
|
}
|
|
|
|
iv.polyMesh = rcAllocPolyMesh();
|
|
if (!iv.polyMesh)
|
|
{
|
|
printf("%s alloc iv.polyMesh FIALED!\n", tileString);
|
|
delete[] pmmerge;
|
|
delete[] dmmerge;
|
|
delete[] tiles;
|
|
return;
|
|
}
|
|
rcMergePolyMeshes(m_rcContext, pmmerge, nmerge, *iv.polyMesh);
|
|
|
|
iv.polyMeshDetail = rcAllocPolyMeshDetail();
|
|
if (!iv.polyMeshDetail)
|
|
{
|
|
printf("%s alloc m_dmesh FIALED!\n", tileString);
|
|
delete[] pmmerge;
|
|
delete[] dmmerge;
|
|
delete[] tiles;
|
|
return;
|
|
}
|
|
rcMergePolyMeshDetails(m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail);
|
|
|
|
// free things up
|
|
delete[] pmmerge;
|
|
delete[] dmmerge;
|
|
delete[] tiles;
|
|
|
|
// set polygons as walkable
|
|
// TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
|
|
for (int i = 0; i < iv.polyMesh->npolys; ++i)
|
|
if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA)
|
|
iv.polyMesh->flags[i] = iv.polyMesh->areas[i];
|
|
|
|
// setup mesh parameters
|
|
dtNavMeshCreateParams params;
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.verts = iv.polyMesh->verts;
|
|
params.vertCount = iv.polyMesh->nverts;
|
|
params.polys = iv.polyMesh->polys;
|
|
params.polyAreas = iv.polyMesh->areas;
|
|
params.polyFlags = iv.polyMesh->flags;
|
|
params.polyCount = iv.polyMesh->npolys;
|
|
params.nvp = iv.polyMesh->nvp;
|
|
params.detailMeshes = iv.polyMeshDetail->meshes;
|
|
params.detailVerts = iv.polyMeshDetail->verts;
|
|
params.detailVertsCount = iv.polyMeshDetail->nverts;
|
|
params.detailTris = iv.polyMeshDetail->tris;
|
|
params.detailTriCount = iv.polyMeshDetail->ntris;
|
|
|
|
params.offMeshConVerts = meshData.offMeshConnections.getCArray();
|
|
params.offMeshConCount = meshData.offMeshConnections.size()/6;
|
|
params.offMeshConRad = meshData.offMeshConnectionRads.getCArray();
|
|
params.offMeshConDir = meshData.offMeshConnectionDirs.getCArray();
|
|
params.offMeshConAreas = meshData.offMeshConnectionsAreas.getCArray();
|
|
params.offMeshConFlags = meshData.offMeshConnectionsFlags.getCArray();
|
|
|
|
params.walkableHeight = BASE_UNIT_DIM*config.walkableHeight; // agent height
|
|
params.walkableRadius = BASE_UNIT_DIM*config.walkableRadius; // agent radius
|
|
params.walkableClimb = BASE_UNIT_DIM*config.walkableClimb; // keep less that walkableHeight (aka agent height)!
|
|
params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) / GRID_SIZE;
|
|
params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) / GRID_SIZE;
|
|
rcVcopy(params.bmin, bmin);
|
|
rcVcopy(params.bmax, bmax);
|
|
params.cs = config.cs;
|
|
params.ch = config.ch;
|
|
params.tileLayer = 0;
|
|
params.buildBvTree = true;
|
|
|
|
// will hold final navmesh
|
|
unsigned char* navData = NULL;
|
|
int navDataSize = 0;
|
|
|
|
do
|
|
{
|
|
// these values are checked within dtCreateNavMeshData - handle them here
|
|
// so we have a clear error message
|
|
if (params.nvp > DT_VERTS_PER_POLYGON)
|
|
{
|
|
printf("%s Invalid verts-per-polygon value! \n", tileString);
|
|
break;
|
|
}
|
|
if (params.vertCount >= 0xffff)
|
|
{
|
|
printf("%s Too many vertices! \n", tileString);
|
|
break;
|
|
}
|
|
if (!params.vertCount || !params.verts)
|
|
{
|
|
// occurs mostly when adjacent tiles have models
|
|
// loaded but those models don't span into this tile
|
|
|
|
// message is an annoyance
|
|
//printf("%sNo vertices to build tile! \n", tileString);
|
|
break;
|
|
}
|
|
if (!params.polyCount || !params.polys ||
|
|
TILES_PER_MAP*TILES_PER_MAP == params.polyCount)
|
|
{
|
|
// we have flat tiles with no actual geometry - don't build those, its useless
|
|
// keep in mind that we do output those into debug info
|
|
// drop tiles with only exact count - some tiles may have geometry while having less tiles
|
|
printf("%s No polygons to build on tile! \n", tileString);
|
|
break;
|
|
}
|
|
if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
|
|
{
|
|
printf("%s No detail mesh to build tile! \n", tileString);
|
|
break;
|
|
}
|
|
|
|
printf("%s Building navmesh tile...\n", tileString);
|
|
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
|
{
|
|
printf("%s Failed building navmesh tile! \n", tileString);
|
|
break;
|
|
}
|
|
|
|
dtTileRef tileRef = 0;
|
|
printf("%s Adding tile to navmesh...\n", tileString);
|
|
// DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
|
|
// is removed via removeTile()
|
|
dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
|
|
if (!tileRef || dtResult != DT_SUCCESS)
|
|
{
|
|
printf("%s Failed adding tile to navmesh! \n", tileString);
|
|
break;
|
|
}
|
|
|
|
// file output
|
|
char fileName[255];
|
|
sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX);
|
|
FILE* file = fopen(fileName, "wb");
|
|
if (!file)
|
|
{
|
|
char message[1024];
|
|
sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName);
|
|
perror(message);
|
|
navMesh->removeTile(tileRef, NULL, NULL);
|
|
break;
|
|
}
|
|
|
|
printf("%s Writing to file...\n", tileString);
|
|
|
|
// write header
|
|
MmapTileHeader header;
|
|
header.usesLiquids = m_terrainBuilder->usesLiquids();
|
|
header.size = uint32(navDataSize);
|
|
fwrite(&header, sizeof(MmapTileHeader), 1, file);
|
|
|
|
// write data
|
|
fwrite(navData, sizeof(unsigned char), navDataSize, file);
|
|
fclose(file);
|
|
|
|
// now that tile is written to disk, we can unload it
|
|
navMesh->removeTile(tileRef, NULL, NULL);
|
|
}
|
|
while (0);
|
|
|
|
if (m_debugOutput)
|
|
{
|
|
// restore padding so that the debug visualization is correct
|
|
for (int i = 0; i < iv.polyMesh->nverts; ++i)
|
|
{
|
|
unsigned short* v = &iv.polyMesh->verts[i*3];
|
|
v[0] += (unsigned short)config.borderSize;
|
|
v[2] += (unsigned short)config.borderSize;
|
|
}
|
|
|
|
iv.generateObjFile(mapID, tileX, tileY, meshData);
|
|
iv.writeIV(mapID, tileX, tileY);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
|
|
{
|
|
// this is for elevation
|
|
if (verts && vertCount)
|
|
rcCalcBounds(verts, vertCount, bmin, bmax);
|
|
else
|
|
{
|
|
bmin[1] = FLT_MIN;
|
|
bmax[1] = FLT_MAX;
|
|
}
|
|
|
|
// this is for width and depth
|
|
bmax[0] = (32 - int(tileX)) * GRID_SIZE;
|
|
bmax[2] = (32 - int(tileY)) * GRID_SIZE;
|
|
bmin[0] = bmax[0] - GRID_SIZE;
|
|
bmin[2] = bmax[2] - GRID_SIZE;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
bool MapBuilder::shouldSkipMap(uint32 mapID)
|
|
{
|
|
if (m_skipContinents)
|
|
switch (mapID)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 530:
|
|
case 571:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (m_skipJunkMaps)
|
|
switch (mapID)
|
|
{
|
|
case 13: // test.wdt
|
|
case 25: // ScottTest.wdt
|
|
case 29: // Test.wdt
|
|
case 42: // Colin.wdt
|
|
case 169: // EmeraldDream.wdt (unused, and very large)
|
|
case 451: // development.wdt
|
|
case 573: // ExteriorTest.wdt
|
|
case 597: // CraigTest.wdt
|
|
case 605: // development_nonweighted.wdt
|
|
case 606: // QA_DVD.wdt
|
|
return true;
|
|
default:
|
|
if (isTransportMap(mapID))
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
if (m_skipBattlegrounds)
|
|
switch (mapID)
|
|
{
|
|
case 30: // AV
|
|
case 37: // ?
|
|
case 489: // WSG
|
|
case 529: // AB
|
|
case 566: // EotS
|
|
case 607: // SotA
|
|
case 628: // IoC
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
bool MapBuilder::isTransportMap(uint32 mapID)
|
|
{
|
|
switch (mapID)
|
|
{
|
|
// transport maps
|
|
case 582:
|
|
case 584:
|
|
case 586:
|
|
case 587:
|
|
case 588:
|
|
case 589:
|
|
case 590:
|
|
case 591:
|
|
case 592:
|
|
case 593:
|
|
case 594:
|
|
case 596:
|
|
case 610:
|
|
case 612:
|
|
case 613:
|
|
case 614:
|
|
case 620:
|
|
case 621:
|
|
case 622:
|
|
case 623:
|
|
case 641:
|
|
case 642:
|
|
case 647:
|
|
case 672:
|
|
case 673:
|
|
case 712:
|
|
case 713:
|
|
case 718:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************/
|
|
bool MapBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY)
|
|
{
|
|
char fileName[255];
|
|
sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX);
|
|
FILE* file = fopen(fileName, "rb");
|
|
if (!file)
|
|
return false;
|
|
|
|
MmapTileHeader header;
|
|
int count = fread(&header, sizeof(MmapTileHeader), 1, file);
|
|
fclose(file);
|
|
if (count != 1)
|
|
return false;
|
|
|
|
if (header.mmapMagic != MMAP_MAGIC || header.dtVersion != uint32(DT_NAVMESH_VERSION))
|
|
return false;
|
|
|
|
if (header.mmapVersion != MMAP_VERSION)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|