mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +00:00
Initial Mangos Three Commit
This commit is contained in:
parent
bb91aa5933
commit
7665a09232
2444 changed files with 625144 additions and 0 deletions
156
src/tools/Extractor_projects/CMakeLists.txt
Normal file
156
src/tools/Extractor_projects/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
# the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
#
|
||||
# Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
#
|
||||
# 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# Used for install targets
|
||||
set(TOOLS_DIR "tools")
|
||||
|
||||
set(SHARED_SRCS
|
||||
shared/dbcfile.cpp
|
||||
shared/ExtractorCommon.cpp
|
||||
shared/dbcfile.h
|
||||
shared/ExtractorCommon.h
|
||||
)
|
||||
|
||||
#=======================================================#
|
||||
#map-extractor
|
||||
#=======================================================#
|
||||
add_executable(map-extractor
|
||||
map-extractor/System.cpp
|
||||
${SHARED_SRCS}
|
||||
$<$<BOOL:${WIN32}>:map-extractor/map-extractor.rc>
|
||||
)
|
||||
|
||||
target_include_directories(map-extractor
|
||||
PUBLIC
|
||||
shared
|
||||
map-extractor
|
||||
)
|
||||
|
||||
target_link_libraries(map-extractor
|
||||
PUBLIC
|
||||
loadlib
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS map-extractor
|
||||
DESTINATION "${BIN_DIR}/${TOOLS_DIR}"
|
||||
)
|
||||
|
||||
if(WIN32 AND MSVC)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:map-extractor>
|
||||
DESTINATION ${BIN_DIR}/${TOOLS_DIR}
|
||||
OPTIONAL)
|
||||
endif()
|
||||
|
||||
#=======================================================#
|
||||
#vmap-extractor
|
||||
#=======================================================#
|
||||
add_executable(vmap-extractor
|
||||
vmap-extractor/adtfile.cpp
|
||||
vmap-extractor/adtfile.h
|
||||
vmap-extractor/assembler.cpp
|
||||
vmap-extractor/model.cpp
|
||||
vmap-extractor/model.h
|
||||
vmap-extractor/modelheaders.h
|
||||
vmap-extractor/vec3d.h
|
||||
vmap-extractor/vmapexport.cpp
|
||||
vmap-extractor/vmapexport.h
|
||||
vmap-extractor/wdtfile.cpp
|
||||
vmap-extractor/wdtfile.h
|
||||
vmap-extractor/wmo.cpp
|
||||
vmap-extractor/wmo.h
|
||||
${SHARED_SRCS}
|
||||
$<$<BOOL:${WIN32}>:vmap-extractor/vmap-extractor.rc>
|
||||
)
|
||||
|
||||
target_include_directories(vmap-extractor
|
||||
PUBLIC
|
||||
shared
|
||||
vmap-extractor
|
||||
)
|
||||
|
||||
target_link_libraries(vmap-extractor
|
||||
PUBLIC
|
||||
loadlib
|
||||
vmap2
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS vmap-extractor
|
||||
DESTINATION ${BIN_DIR}/${TOOLS_DIR}
|
||||
)
|
||||
|
||||
if(WIN32 AND MSVC)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:vmap-extractor>
|
||||
DESTINATION ${BIN_DIR}/${TOOLS_DIR}
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
|
||||
#=======================================================#
|
||||
#mmap-extractor
|
||||
#=======================================================#
|
||||
add_executable(mmap-extractor
|
||||
Movemap-Generator/generator.cpp
|
||||
Movemap-Generator/IntermediateValues.cpp
|
||||
Movemap-Generator/IntermediateValues.h
|
||||
Movemap-Generator/MangosMap.h
|
||||
Movemap-Generator/MapBuilder.cpp
|
||||
Movemap-Generator/MapBuilder.h
|
||||
Movemap-Generator/MMapCommon.h
|
||||
Movemap-Generator/TerrainBuilder.cpp
|
||||
Movemap-Generator/TerrainBuilder.h
|
||||
Movemap-Generator/TileMsgBlock.h
|
||||
Movemap-Generator/TileThreadPool.cpp
|
||||
Movemap-Generator/TileThreadPool.h
|
||||
Movemap-Generator/VMapExtensions.cpp
|
||||
shared/ExtractorCommon.cpp
|
||||
shared/ExtractorCommon.h
|
||||
$<$<BOOL:${WIN32}>:Movemap-Generator/Movemap-Generator.rc>
|
||||
)
|
||||
|
||||
target_include_directories(mmap-extractor
|
||||
PUBLIC
|
||||
shared
|
||||
Movemap-Generator
|
||||
)
|
||||
|
||||
target_link_libraries(mmap-extractor
|
||||
PUBLIC
|
||||
vmap2
|
||||
shared
|
||||
RecastNavigation::Recast
|
||||
Threads::Threads
|
||||
DL::DL
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS mmap-extractor
|
||||
DESTINATION ${BIN_DIR}/${TOOLS_DIR}
|
||||
)
|
||||
|
||||
if(WIN32 AND MSVC)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:mmap-extractor>
|
||||
DESTINATION ${BIN_DIR}/${TOOLS_DIR}
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
|
|
@ -0,0 +1,327 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "IntermediateValues.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
IntermediateValues::~IntermediateValues()
|
||||
{
|
||||
rcFreeCompactHeightfield(compactHeightfield);
|
||||
rcFreeHeightField(heightfield);
|
||||
rcFreeContourSet(contours);
|
||||
rcFreePolyMesh(polyMesh);
|
||||
rcFreePolyMeshDetail(polyMeshDetail);
|
||||
}
|
||||
|
||||
void IntermediateValues::writeIV(int mapID, int tileX, int tileY)
|
||||
{
|
||||
char fileName[255];
|
||||
char tileString[25];
|
||||
sprintf(tileString, "[%02u,%02u]: ", tileX, tileY);
|
||||
|
||||
printf("%sWriting debug output... \r", tileString);
|
||||
|
||||
string name("meshes/%03u%02i%02i.");
|
||||
|
||||
#define DEBUG_WRITE(fileExtension,data) \
|
||||
do { \
|
||||
sprintf(fileName, (name + fileExtension).c_str(), mapID, tileY, tileX); \
|
||||
FILE* file = fopen(fileName, "wb"); \
|
||||
if (!file) \
|
||||
{ \
|
||||
char message[1024]; \
|
||||
sprintf(message, "%sFailed to open %s for writing!\n", tileString, fileName); \
|
||||
perror(message); \
|
||||
} \
|
||||
else \
|
||||
debugWrite(file, data); \
|
||||
if(file) fclose(file); \
|
||||
printf("%sWriting debug output... \r", tileString); \
|
||||
} while (false)
|
||||
|
||||
if (heightfield)
|
||||
{
|
||||
DEBUG_WRITE("hf", heightfield);
|
||||
}
|
||||
if (compactHeightfield)
|
||||
{
|
||||
DEBUG_WRITE("chf", compactHeightfield);
|
||||
}
|
||||
if (contours)
|
||||
{
|
||||
DEBUG_WRITE("cs", contours);
|
||||
}
|
||||
if (polyMesh)
|
||||
{
|
||||
DEBUG_WRITE("pmesh", polyMesh);
|
||||
}
|
||||
if (polyMeshDetail)
|
||||
{
|
||||
DEBUG_WRITE("dmesh", polyMeshDetail);
|
||||
}
|
||||
|
||||
#undef DEBUG_WRITE
|
||||
}
|
||||
|
||||
void IntermediateValues::debugWrite(FILE* file, const rcHeightfield* mesh)
|
||||
{
|
||||
if (!file || !mesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&(mesh->cs), sizeof(float), 1, file);
|
||||
fwrite(&(mesh->ch), sizeof(float), 1, file);
|
||||
fwrite(&(mesh->width), sizeof(int), 1, file);
|
||||
fwrite(&(mesh->height), sizeof(int), 1, file);
|
||||
fwrite(mesh->bmin, sizeof(float), 3, file);
|
||||
fwrite(mesh->bmax, sizeof(float), 3, file);
|
||||
|
||||
for (int y = 0; y < mesh->height; ++y)
|
||||
for (int x = 0; x < mesh->width; ++x)
|
||||
{
|
||||
rcSpan* span = mesh->spans[x + y * mesh->width];
|
||||
|
||||
// first, count the number of spans
|
||||
int spanCount = 0;
|
||||
while (span)
|
||||
{
|
||||
spanCount++;
|
||||
span = span->next;
|
||||
}
|
||||
|
||||
// write the span count
|
||||
fwrite(&spanCount, sizeof(int), 1, file);
|
||||
|
||||
// write the spans
|
||||
span = mesh->spans[x + y * mesh->width];
|
||||
while (span)
|
||||
{
|
||||
fwrite(span, sizeof(rcSpan), 1, file);
|
||||
span = span->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntermediateValues::debugWrite(FILE* file, const rcCompactHeightfield* chf)
|
||||
{
|
||||
if (!file | !chf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&(chf->width), sizeof(chf->width), 1, file);
|
||||
fwrite(&(chf->height), sizeof(chf->height), 1, file);
|
||||
fwrite(&(chf->spanCount), sizeof(chf->spanCount), 1, file);
|
||||
|
||||
fwrite(&(chf->walkableHeight), sizeof(chf->walkableHeight), 1, file);
|
||||
fwrite(&(chf->walkableClimb), sizeof(chf->walkableClimb), 1, file);
|
||||
|
||||
fwrite(&(chf->maxDistance), sizeof(chf->maxDistance), 1, file);
|
||||
fwrite(&(chf->maxRegions), sizeof(chf->maxRegions), 1, file);
|
||||
|
||||
fwrite(chf->bmin, sizeof(chf->bmin), 1, file);
|
||||
fwrite(chf->bmax, sizeof(chf->bmax), 1, file);
|
||||
|
||||
fwrite(&(chf->cs), sizeof(chf->cs), 1, file);
|
||||
fwrite(&(chf->ch), sizeof(chf->ch), 1, file);
|
||||
|
||||
int tmp = 0;
|
||||
if (chf->cells)
|
||||
{
|
||||
tmp |= 1;
|
||||
}
|
||||
if (chf->spans)
|
||||
{
|
||||
tmp |= 2;
|
||||
}
|
||||
if (chf->dist)
|
||||
{
|
||||
tmp |= 4;
|
||||
}
|
||||
if (chf->areas)
|
||||
{
|
||||
tmp |= 8;
|
||||
}
|
||||
|
||||
fwrite(&tmp, sizeof(tmp), 1, file);
|
||||
|
||||
if (chf->cells)
|
||||
{
|
||||
fwrite(chf->cells, sizeof(rcCompactCell), chf->width * chf->height, file);
|
||||
}
|
||||
if (chf->spans)
|
||||
{
|
||||
fwrite(chf->spans, sizeof(rcCompactSpan), chf->spanCount, file);
|
||||
}
|
||||
if (chf->dist)
|
||||
{
|
||||
fwrite(chf->dist, sizeof(unsigned short), chf->spanCount, file);
|
||||
}
|
||||
if (chf->areas)
|
||||
{
|
||||
fwrite(chf->areas, sizeof(unsigned char), chf->spanCount, file);
|
||||
}
|
||||
}
|
||||
|
||||
void IntermediateValues::debugWrite(FILE* file, const rcContourSet* cs)
|
||||
{
|
||||
if (!file || !cs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&(cs->cs), sizeof(float), 1, file);
|
||||
fwrite(&(cs->ch), sizeof(float), 1, file);
|
||||
fwrite(cs->bmin, sizeof(float), 3, file);
|
||||
fwrite(cs->bmax, sizeof(float), 3, file);
|
||||
fwrite(&(cs->nconts), sizeof(int), 1, file);
|
||||
for (int i = 0; i < cs->nconts; ++i)
|
||||
{
|
||||
fwrite(&cs->conts[i].area, sizeof(unsigned char), 1, file);
|
||||
fwrite(&cs->conts[i].reg, sizeof(unsigned short), 1, file);
|
||||
fwrite(&cs->conts[i].nverts, sizeof(int), 1, file);
|
||||
fwrite(cs->conts[i].verts, sizeof(int), cs->conts[i].nverts * 4, file);
|
||||
fwrite(&cs->conts[i].nrverts, sizeof(int), 1, file);
|
||||
fwrite(cs->conts[i].rverts, sizeof(int), cs->conts[i].nrverts * 4, file);
|
||||
}
|
||||
}
|
||||
|
||||
void IntermediateValues::debugWrite(FILE* file, const rcPolyMesh* mesh)
|
||||
{
|
||||
if (!file || !mesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&(mesh->cs), sizeof(float), 1, file);
|
||||
fwrite(&(mesh->ch), sizeof(float), 1, file);
|
||||
fwrite(&(mesh->nvp), sizeof(int), 1, file);
|
||||
fwrite(mesh->bmin, sizeof(float), 3, file);
|
||||
fwrite(mesh->bmax, sizeof(float), 3, file);
|
||||
fwrite(&(mesh->nverts), sizeof(int), 1, file);
|
||||
fwrite(mesh->verts, sizeof(unsigned short), mesh->nverts * 3, file);
|
||||
fwrite(&(mesh->npolys), sizeof(int), 1, file);
|
||||
fwrite(mesh->polys, sizeof(unsigned short), mesh->npolys * mesh->nvp * 2, file);
|
||||
fwrite(mesh->flags, sizeof(unsigned short), mesh->npolys, file);
|
||||
fwrite(mesh->areas, sizeof(unsigned char), mesh->npolys, file);
|
||||
fwrite(mesh->regs, sizeof(unsigned short), mesh->npolys, file);
|
||||
}
|
||||
|
||||
void IntermediateValues::debugWrite(FILE* file, const rcPolyMeshDetail* mesh)
|
||||
{
|
||||
if (!file || !mesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&(mesh->nverts), sizeof(int), 1, file);
|
||||
fwrite(mesh->verts, sizeof(float), mesh->nverts * 3, file);
|
||||
fwrite(&(mesh->ntris), sizeof(int), 1, file);
|
||||
fwrite(mesh->tris, sizeof(char), mesh->ntris * 4, file);
|
||||
fwrite(&(mesh->nmeshes), sizeof(int), 1, file);
|
||||
fwrite(mesh->meshes, sizeof(int), mesh->nmeshes * 4, file);
|
||||
}
|
||||
|
||||
void IntermediateValues::generateObjFile(int mapID, int tileX, int tileY, MeshData& meshData)
|
||||
{
|
||||
char objFileName[255];
|
||||
sprintf(objFileName, "meshes/map%03u%02u%02u.obj", mapID, tileY, tileX);
|
||||
|
||||
FILE* objFile = fopen(objFileName, "wb");
|
||||
if (!objFile)
|
||||
{
|
||||
char message[1024];
|
||||
sprintf(message, "Failed to open %s for writing!\n", objFileName);
|
||||
perror(message);
|
||||
return;
|
||||
}
|
||||
|
||||
G3D::Array<float> allVerts;
|
||||
G3D::Array<int> allTris;
|
||||
|
||||
allTris.append(meshData.liquidTris);
|
||||
allVerts.append(meshData.liquidVerts);
|
||||
TerrainBuilder::copyIndices(meshData.solidTris, allTris, allVerts.size() / 3);
|
||||
allVerts.append(meshData.solidVerts);
|
||||
|
||||
float* verts = allVerts.getCArray();
|
||||
int vertCount = allVerts.size() / 3;
|
||||
int* tris = allTris.getCArray();
|
||||
int triCount = allTris.size() / 3;
|
||||
|
||||
for (int i = 0; i < allVerts.size() / 3; i++)
|
||||
{
|
||||
fprintf(objFile, "v %f %f %f\n", verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < allTris.size() / 3; i++)
|
||||
{
|
||||
fprintf(objFile, "f %i %i %i\n", tris[i * 3] + 1, tris[i * 3 + 1] + 1, tris[i * 3 + 2] + 1);
|
||||
}
|
||||
|
||||
fclose(objFile);
|
||||
|
||||
|
||||
char tileString[25];
|
||||
sprintf(tileString, "[%02u,%02u]: ", tileY, tileX);
|
||||
printf("%sWriting debug output... \r", tileString);
|
||||
|
||||
sprintf(objFileName, "meshes/%03u.map", mapID);
|
||||
|
||||
objFile = fopen(objFileName, "wb");
|
||||
if (!objFile)
|
||||
{
|
||||
char message[1024];
|
||||
sprintf(message, "Failed to open %s for writing!\n", objFileName);
|
||||
perror(message);
|
||||
return;
|
||||
}
|
||||
|
||||
char b = '\0';
|
||||
fwrite(&b, sizeof(char), 1, objFile);
|
||||
fclose(objFile);
|
||||
|
||||
sprintf(objFileName, "meshes/%03u%02u%02u.mesh", mapID, tileY, tileX);
|
||||
objFile = fopen(objFileName, "wb");
|
||||
if (!objFile)
|
||||
{
|
||||
char message[1024];
|
||||
sprintf(message, "Failed to open %s for writing!\n", objFileName);
|
||||
perror(message);
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(&vertCount, sizeof(int), 1, objFile);
|
||||
fwrite(verts, sizeof(float), vertCount * 3, objFile);
|
||||
fflush(objFile);
|
||||
|
||||
fwrite(&triCount, sizeof(int), 1, objFile);
|
||||
fwrite(tris, sizeof(int), triCount * 3, objFile);
|
||||
fflush(objFile);
|
||||
|
||||
fclose(objFile);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_H_INTERMEDIATE_VALUES
|
||||
#define MANGOS_H_INTERMEDIATE_VALUES
|
||||
|
||||
#include <Recast.h>
|
||||
#include <DetourNavMesh.h>
|
||||
|
||||
#include "MMapCommon.h"
|
||||
#include "TerrainBuilder.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
/**
|
||||
* @brief this class gathers all debug info holding and output
|
||||
*
|
||||
*/
|
||||
struct IntermediateValues
|
||||
{
|
||||
rcHeightfield* heightfield; /**< TODO */
|
||||
rcCompactHeightfield* compactHeightfield; /**< TODO */
|
||||
rcContourSet* contours; /**< TODO */
|
||||
rcPolyMesh* polyMesh; /**< TODO */
|
||||
rcPolyMeshDetail* polyMeshDetail; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
IntermediateValues() : compactHeightfield(NULL), heightfield(NULL),
|
||||
contours(NULL), polyMesh(NULL), polyMeshDetail(NULL) {}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~IntermediateValues();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
*/
|
||||
void writeIV(int mapID, int tileX, int tileY);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param mesh
|
||||
*/
|
||||
void debugWrite(FILE* file, const rcHeightfield* mesh);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param chf
|
||||
*/
|
||||
void debugWrite(FILE* file, const rcCompactHeightfield* chf);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param cs
|
||||
*/
|
||||
void debugWrite(FILE* file, const rcContourSet* cs);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param mesh
|
||||
*/
|
||||
void debugWrite(FILE* file, const rcPolyMesh* mesh);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param mesh
|
||||
*/
|
||||
void debugWrite(FILE* file, const rcPolyMeshDetail* mesh);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param meshData
|
||||
*/
|
||||
void generateObjFile(int mapID, int tileX, int tileY, MeshData& meshData);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
173
src/tools/Extractor_projects/Movemap-Generator/MMapCommon.h
Normal file
173
src/tools/Extractor_projects/Movemap-Generator/MMapCommon.h
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_H_MMAP_COMMON
|
||||
#define MANGOS_H_MMAP_COMMON
|
||||
|
||||
// stop warning spam from ACE includes
|
||||
#ifdef WIN32
|
||||
# pragma warning( disable : 4996 )
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <errno.h>
|
||||
#include "Platform/Define.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param filter
|
||||
* @param str
|
||||
* @return bool
|
||||
*/
|
||||
inline bool matchWildcardFilter(const char* filter, const char* str)
|
||||
{
|
||||
if (!filter || !str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// end on null character
|
||||
while (*filter && *str)
|
||||
{
|
||||
if (*filter == '*')
|
||||
{
|
||||
if (*++filter == '\0') // wildcard at end of filter means all remaing chars match
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (*filter == *str)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (*str == '\0')
|
||||
{ return false; } // reached end of string without matching next filter character
|
||||
str++;
|
||||
}
|
||||
}
|
||||
else if (*filter != *str)
|
||||
{ return false; } // mismatch
|
||||
|
||||
filter++;
|
||||
str++;
|
||||
}
|
||||
|
||||
return ((*filter == '\0' || (*filter == '*' && *++filter == '\0')) && *str == '\0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
enum ListFilesResult
|
||||
{
|
||||
LISTFILE_DIRECTORY_NOT_FOUND = 0,
|
||||
LISTFILE_OK = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param fileList
|
||||
* @param dirpath
|
||||
* @param filter
|
||||
* @param includeSubDirs
|
||||
* @return ListFilesResult
|
||||
*/
|
||||
inline ListFilesResult getDirContents(vector<string>& fileList, string dirpath = ".", string filter = "*", bool includeSubDirs = false)
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA findFileInfo;
|
||||
string directory;
|
||||
|
||||
directory = dirpath + "/" + filter;
|
||||
|
||||
hFind = FindFirstFile(directory.c_str(), &findFileInfo);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return LISTFILE_DIRECTORY_NOT_FOUND;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (includeSubDirs || (findFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
||||
{
|
||||
fileList.push_back(string(findFileInfo.cFileName));
|
||||
}
|
||||
}
|
||||
while (FindNextFile(hFind, &findFileInfo));
|
||||
|
||||
FindClose(hFind);
|
||||
|
||||
#else
|
||||
const char* p = dirpath.c_str();
|
||||
DIR* dirp = opendir(p);
|
||||
struct dirent* dp;
|
||||
|
||||
while (dirp)
|
||||
{
|
||||
errno = 0;
|
||||
if ((dp = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (matchWildcardFilter(filter.c_str(), dp->d_name))
|
||||
{
|
||||
fileList.push_back(string(dp->d_name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirp)
|
||||
{
|
||||
closedir(dirp);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LISTFILE_DIRECTORY_NOT_FOUND;
|
||||
}
|
||||
#endif
|
||||
|
||||
return LISTFILE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
123
src/tools/Extractor_projects/Movemap-Generator/MangosMap.h
Normal file
123
src/tools/Extractor_projects/Movemap-Generator/MangosMap.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_H_MMAP_MANGOS_MAP
|
||||
#define MANGOS_H_MMAP_MANGOS_MAP
|
||||
|
||||
// following is copied from src/game/GridMap.h (too many useless includes there to use original file)
|
||||
namespace MaNGOS
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct GridMapFileHeader
|
||||
{
|
||||
uint32 mapMagic; /**< TODO */
|
||||
uint32 versionMagic; /**< TODO */
|
||||
uint32 buildMagic;
|
||||
uint32 areaMapOffset; /**< TODO */
|
||||
uint32 areaMapSize; /**< TODO */
|
||||
uint32 heightMapOffset; /**< TODO */
|
||||
uint32 heightMapSize; /**< TODO */
|
||||
uint32 liquidMapOffset; /**< TODO */
|
||||
uint32 liquidMapSize; /**< TODO */
|
||||
uint32 holesOffset; /**< TODO */
|
||||
uint32 holesSize; /**< TODO */
|
||||
};
|
||||
|
||||
// ==============mmaps don't use area==============
|
||||
//#define MAP_AREA_NO_AREA 0x0001
|
||||
|
||||
//struct GridMapAreaHeader
|
||||
//{
|
||||
// uint32 fourcc;
|
||||
// uint16 flags;
|
||||
// uint16 gridArea;
|
||||
//};
|
||||
|
||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct GridMapHeightHeader
|
||||
{
|
||||
uint32 fourcc; /**< TODO */
|
||||
uint32 flags; /**< TODO */
|
||||
float gridHeight; /**< TODO */
|
||||
float gridMaxHeight; /**< TODO */
|
||||
};
|
||||
|
||||
#define MAP_LIQUID_NO_TYPE 0x0001
|
||||
#define MAP_LIQUID_NO_HEIGHT 0x0002
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct GridMapLiquidHeader
|
||||
{
|
||||
uint32 fourcc; /**< TODO */
|
||||
uint16 flags; /**< TODO */
|
||||
uint16 liquidType; /**< TODO */
|
||||
uint8 offsetX; /**< TODO */
|
||||
uint8 offsetY; /**< TODO */
|
||||
uint8 width; /**< TODO */
|
||||
uint8 height; /**< TODO */
|
||||
float liquidLevel; /**< TODO */
|
||||
};
|
||||
|
||||
//enum GridMapLiquidStatus
|
||||
//{
|
||||
// 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_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 MAP_LIQUID_TYPE_WMO_WATER 0x20
|
||||
|
||||
//struct GridMapLiquidData
|
||||
//{
|
||||
// uint32 type;
|
||||
// float level;
|
||||
// float depth_level;
|
||||
//};
|
||||
}
|
||||
|
||||
#endif
|
||||
922
src/tools/Extractor_projects/Movemap-Generator/MapBuilder.cpp
Normal file
922
src/tools/Extractor_projects/Movemap-Generator/MapBuilder.cpp
Normal file
|
|
@ -0,0 +1,922 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <DetourNavMeshBuilder.h>
|
||||
#include <DetourCommon.h>
|
||||
|
||||
#include "MMapCommon.h"
|
||||
#include "MapBuilder.h"
|
||||
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
#include "ExtractorCommon.h"
|
||||
|
||||
#include "TileMsgBlock.h"
|
||||
|
||||
using namespace VMAP;
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
MapBuilder::MapBuilder(char const* magic, float maxWalkableAngle, bool skipLiquid,
|
||||
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
|
||||
bool debugOutput, bool bigBaseUnit, const char* offMeshFilePath) :
|
||||
m_terrainBuilder(NULL),
|
||||
m_debugOutput(debugOutput),
|
||||
m_skipContinents(skipContinents),
|
||||
m_skipJunkMaps(skipJunkMaps),
|
||||
m_skipBattlegrounds(skipBattlegrounds),
|
||||
m_maxWalkableAngle(maxWalkableAngle),
|
||||
m_bigBaseUnit(bigBaseUnit),
|
||||
m_rcContext(NULL),
|
||||
m_offMeshFilePath(offMeshFilePath),
|
||||
m_magic(magic),
|
||||
m_numThreads(-1), m_threadPool(NULL), m_poolActivated(false)
|
||||
{
|
||||
m_terrainBuilder = new TerrainBuilder(skipLiquid);
|
||||
|
||||
m_rcContext = new rcContext(false);
|
||||
|
||||
discoverTiles();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
MapBuilder::~MapBuilder()
|
||||
{
|
||||
if (activated())
|
||||
{
|
||||
delete m_threadPool;
|
||||
m_poolActivated = false;
|
||||
}
|
||||
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
||||
{
|
||||
(*it).second->clear();
|
||||
delete(*it).second;
|
||||
}
|
||||
|
||||
delete m_terrainBuilder;
|
||||
delete m_rcContext;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
int MapBuilder::activate(int num_threads)
|
||||
{
|
||||
int result = -1;
|
||||
m_numThreads = num_threads;
|
||||
m_threadPool = new TileThreadPool();
|
||||
|
||||
if (m_threadPool && m_numThreads && !m_poolActivated)
|
||||
{
|
||||
result = m_threadPool->start(m_numThreads);
|
||||
if (result != -1)
|
||||
{
|
||||
m_poolActivated = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::discoverTiles()
|
||||
{
|
||||
vector<string> files;
|
||||
int mapID;
|
||||
uint32 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 (m_tiles.find(mapID) == m_tiles.end())
|
||||
{
|
||||
m_tiles.insert(pair<uint32, set<uint32>*>(mapID, new 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()));
|
||||
m_tiles.insert(pair<uint32, set<uint32>*>(mapID, new 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)
|
||||
{
|
||||
set<uint32>* tiles = (*itr).second;
|
||||
mapID = (*itr).first;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
set<uint32>* MapBuilder::getTileList(int mapID)
|
||||
{
|
||||
TileList::iterator itr = m_tiles.find(mapID);
|
||||
if (itr != m_tiles.end())
|
||||
{
|
||||
return (*itr).second;
|
||||
}
|
||||
|
||||
set<uint32>* tiles = new set<uint32>();
|
||||
m_tiles.insert(pair<uint32, set<uint32>*>(mapID, tiles));
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildAllMaps()
|
||||
{
|
||||
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
||||
{
|
||||
uint32 mapID = (*it).first;
|
||||
if (!shouldSkipMap(mapID,m_skipContinents,m_skipJunkMaps,m_skipBattlegrounds))
|
||||
{
|
||||
buildMap(mapID, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (activated())
|
||||
{
|
||||
Tile_Message_Block *finish_mb = new Tile_Message_Block(NULL);
|
||||
finish_mb->msg_type(ACE_Message_Block::MB_HANGUP);
|
||||
m_threadPool->putq(finish_mb);
|
||||
m_threadPool->wait();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildMap(int mapID, bool standAlone)
|
||||
{
|
||||
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->size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// build navMesh
|
||||
dtNavMesh* navMesh = NULL;
|
||||
dtNavMeshParams* meshParams = NULL;
|
||||
buildNavMesh(mapID, navMesh, meshParams);
|
||||
if (!navMesh)
|
||||
{
|
||||
printf("Failed creating navmesh for map %03u! \n", mapID);
|
||||
if (meshParams)
|
||||
{
|
||||
delete meshParams;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (activated())
|
||||
{ dtFreeNavMesh(navMesh); } // each tile will get it's own pointer to navMesh
|
||||
|
||||
// now start building/scheduling mmtiles for each tile
|
||||
printf(" %s map %03u [%u tiles]\n", activated() ? "Scheduling" : "Building", mapID, (unsigned int)tiles->size());
|
||||
for (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;
|
||||
}
|
||||
|
||||
if (!activated())
|
||||
{
|
||||
buildTile(mapID, tileX, tileY, navMesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
dtNavMesh *mesh = NULL;
|
||||
buildNavMesh(mapID, mesh, meshParams); //meshParams is not null, so we get a new pointer to dtNavMesh
|
||||
if (mesh)
|
||||
{
|
||||
TileBuilder* tb = new TileBuilder(this, mapID, tileX, tileY, mesh);
|
||||
Tile_Message_Block *mb = new Tile_Message_Block(tb);
|
||||
if (m_threadPool->putq(mb) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activated() && standAlone)
|
||||
{
|
||||
Tile_Message_Block *finish_mb = new Tile_Message_Block(NULL);
|
||||
finish_mb->msg_type(ACE_Message_Block::MB_HANGUP);
|
||||
m_threadPool->putq(finish_mb);
|
||||
m_threadPool->wait();
|
||||
}
|
||||
|
||||
if (!activated())
|
||||
{
|
||||
dtFreeNavMesh(navMesh);
|
||||
}
|
||||
|
||||
if (meshParams)
|
||||
{
|
||||
delete meshParams;
|
||||
}
|
||||
|
||||
if (!activated())
|
||||
{
|
||||
printf(" Map %03u complete!\n\n", mapID);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildSingleTile(int mapID, int tileX, int tileY)
|
||||
{
|
||||
dtNavMesh* navMesh = NULL;
|
||||
dtNavMeshParams* meshParams = NULL;
|
||||
buildNavMesh(mapID, navMesh, meshParams);
|
||||
if (!navMesh)
|
||||
{
|
||||
printf("Failed creating navmesh! \n");
|
||||
return;
|
||||
}
|
||||
|
||||
buildTile(mapID, tileX, tileY, navMesh);
|
||||
dtFreeNavMesh(navMesh);
|
||||
if (meshParams)
|
||||
{
|
||||
delete meshParams;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildTile(int mapID, int tileX, int tileY, dtNavMesh* navMesh)
|
||||
{
|
||||
MeshData meshData;
|
||||
|
||||
// get heightmap data
|
||||
m_terrainBuilder->loadMap(mapID, tileX, tileY, meshData, m_magic);
|
||||
|
||||
// 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);
|
||||
|
||||
printf(" Building map %03u - Tile [%02u,%02u]\n", mapID, tileX, tileY);
|
||||
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::getGridBounds(int 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 };
|
||||
float bmax[3] = { 0 };
|
||||
float lmin[3] = { 0 };
|
||||
float lmax[3] = { 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::buildNavMesh(int mapID, dtNavMesh*& navMesh, dtNavMeshParams*& navMeshParams)
|
||||
{
|
||||
bool isFirstNavMesh = navMeshParams ? false : true;
|
||||
|
||||
if (isFirstNavMesh)
|
||||
{
|
||||
set<uint32>* tiles = getTileList(mapID);
|
||||
int polyBits = DT_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 (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
|
||||
navMeshParams = new dtNavMeshParams();
|
||||
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();
|
||||
if (!navMesh->init(navMeshParams))
|
||||
{
|
||||
printf("Failed creating navmesh! \n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFirstNavMesh)
|
||||
{
|
||||
char fileName[25];
|
||||
sprintf(fileName, "mmaps/%03u.mmap", mapID);
|
||||
|
||||
FILE* file = fopen(fileName, "wb");
|
||||
if (!file)
|
||||
{
|
||||
dtFreeNavMesh(navMesh);
|
||||
char message[1024];
|
||||
sprintf(message, "Failed to open %s for writing!\n", 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(int mapID, int tileX, int tileY,
|
||||
MeshData& meshData, float bmin[3], float bmax[3],
|
||||
dtNavMesh* navMesh)
|
||||
{
|
||||
// console output
|
||||
char tileString[10];
|
||||
sprintf(tileString, "[%02i,%02i] ", tileX, tileY);
|
||||
|
||||
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.33333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc )
|
||||
const static float BASE_UNIT_DIM = m_bigBaseUnit ? 0.533333f : 0.266666f;
|
||||
|
||||
// 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;
|
||||
config.walkableClimb = m_bigBaseUnit ? 2 : 4; // keep less than walkableHeight
|
||||
config.minRegionArea = rcSqr(60);
|
||||
config.mergeRegionArea = rcSqr(50);
|
||||
config.maxSimplificationError = 2.0f; // eliminates most jagged edges (tinny 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;
|
||||
memcpy(&tileCfg, &config, sizeof(rcConfig));
|
||||
tileCfg.width = config.tileSize + config.borderSize * 2;
|
||||
tileCfg.height = config.tileSize + config.borderSize * 2;
|
||||
|
||||
// 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] + (x * config.tileSize - config.borderSize) * config.cs;
|
||||
tileCfg.bmin[2] = config.bmin[2] + (y * config.tileSize - config.borderSize) * config.cs;
|
||||
tileCfg.bmax[0] = config.bmin[0] + ((x + 1) * config.tileSize + config.borderSize) * config.cs;
|
||||
tileCfg.bmax[2] = config.bmin[2] + ((y + 1) * config.tileSize + config.borderSize) * config.cs;
|
||||
|
||||
float tbmin[2], tbmax[2];
|
||||
tbmin[0] = tileCfg.bmin[0];
|
||||
tbmin[1] = tileCfg.bmin[2];
|
||||
tbmax[0] = tileCfg.bmax[0];
|
||||
tbmax[1] = tileCfg.bmax[2];
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// merge per tile poly and detail meshes
|
||||
rcPolyMesh** pmmerge = new rcPolyMesh*[TILES_PER_MAP * TILES_PER_MAP];
|
||||
if (!pmmerge)
|
||||
{
|
||||
printf("%s alloc pmmerge FAILED! \n", tileString);
|
||||
delete [] tiles;
|
||||
return;
|
||||
}
|
||||
|
||||
rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[TILES_PER_MAP * TILES_PER_MAP];
|
||||
if (!dmmerge)
|
||||
{
|
||||
printf("%s alloc dmmerge FAILED! \n", tileString);
|
||||
delete [] pmmerge;
|
||||
delete [] tiles;
|
||||
return;
|
||||
}
|
||||
|
||||
int nmerge = 0;
|
||||
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];
|
||||
if (tile.pmesh)
|
||||
{
|
||||
pmmerge[nmerge] = tile.pmesh;
|
||||
dmmerge[nmerge] = tile.dmesh;
|
||||
nmerge++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iv.polyMesh = rcAllocPolyMesh();
|
||||
if (!iv.polyMesh)
|
||||
{
|
||||
printf("%s alloc iv.polyMesh FAILED! \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 FAILED! \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;
|
||||
|
||||
#if defined (CATA)
|
||||
// remove padding for extraction
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
// 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);
|
||||
continue;
|
||||
}
|
||||
if (params.vertCount >= 0xffff)
|
||||
{
|
||||
printf("%s Too many vertices! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
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(" No polygons to build on tile - %s \n", tileString);
|
||||
continue;
|
||||
}
|
||||
if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
|
||||
{
|
||||
printf(" No detail mesh to build tile - %s \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
||||
{
|
||||
printf(" Failed building navmesh tile - %s \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
dtTileRef tileRef = 0;
|
||||
// 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 || dtStatusFailed(dtResult))
|
||||
{
|
||||
printf(" Failed adding tile %s to navmesh ! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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, "Failed to open %s for writing!\n", fileName);
|
||||
perror(message);
|
||||
navMesh->removeTile(tileRef, NULL, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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(int tileX, int 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::shouldSkipTile(int mapID, int tileX, int 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;
|
||||
size_t file_read = fread(&header, sizeof(MmapTileHeader), 1, file);
|
||||
fclose(file);
|
||||
|
||||
if (header.mmapMagic != MMAP_MAGIC || header.dtVersion != DT_NAVMESH_VERSION || file_read <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.mmapVersion != MMAP_VERSION)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
253
src/tools/Extractor_projects/Movemap-Generator/MapBuilder.h
Normal file
253
src/tools/Extractor_projects/Movemap-Generator/MapBuilder.h
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_H_MAP_BUILDER
|
||||
#define MANGOS_H_MAP_BUILDER
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <Recast.h>
|
||||
#include <DetourNavMesh.h>
|
||||
|
||||
#include "TerrainBuilder.h"
|
||||
#include "IntermediateValues.h"
|
||||
|
||||
#include "IVMapManager.h"
|
||||
#include "WorldModel.h"
|
||||
|
||||
#include "TileThreadPool.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace VMAP;
|
||||
// G3D namespace typedefs conflicts with ACE typedefs
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef map<uint32, set<uint32>*> TileList;
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct Tile
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~Tile()
|
||||
{
|
||||
rcFreeCompactHeightfield(chf);
|
||||
rcFreeContourSet(cset);
|
||||
rcFreeHeightField(solid);
|
||||
rcFreePolyMesh(pmesh);
|
||||
rcFreePolyMeshDetail(dmesh);
|
||||
}
|
||||
rcCompactHeightfield* chf; /**< TODO */
|
||||
rcHeightfield* solid; /**< TODO */
|
||||
rcContourSet* cset; /**< TODO */
|
||||
rcPolyMesh* pmesh; /**< TODO */
|
||||
rcPolyMeshDetail* dmesh; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class MapBuilder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param maxWalkableAngle
|
||||
* @param skipLiquid
|
||||
* @param skipContinents
|
||||
* @param skipJunkMaps
|
||||
* @param skipBattlegrounds
|
||||
* @param debugOutput
|
||||
* @param bigBaseUnit
|
||||
* @param offMeshFilePath
|
||||
*/
|
||||
MapBuilder(const char* magic,
|
||||
float maxWalkableAngle = 60.f,
|
||||
bool skipLiquid = false,
|
||||
bool skipContinents = false,
|
||||
bool skipJunkMaps = true,
|
||||
bool skipBattlegrounds = false,
|
||||
bool debugOutput = false,
|
||||
bool bigBaseUnit = false,
|
||||
const char* offMeshFilePath = NULL);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~MapBuilder();
|
||||
|
||||
/**
|
||||
* @brief builds all mmap tiles for the specified map id (ignores skip settings)
|
||||
*
|
||||
* @param mapID
|
||||
*/
|
||||
void buildMap(int mapID, bool standAlone = true);
|
||||
|
||||
/**
|
||||
* @brief builds an mmap tile for the specified map and its mesh
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
*/
|
||||
void buildSingleTile(int mapID, int tileX, int tileY);
|
||||
|
||||
/**
|
||||
* @brief builds list of maps, then builds all of mmap tiles (based on the skip settings)
|
||||
*
|
||||
*/
|
||||
void buildAllMaps();
|
||||
|
||||
int activate(int num_threads);
|
||||
|
||||
bool activated() const { return m_poolActivated; }
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param navMesh
|
||||
*/
|
||||
void buildTile(int mapID, int tileX, int tileY, dtNavMesh* navMesh);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief detect maps and tiles
|
||||
*
|
||||
*/
|
||||
void discoverTiles();
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @return set<uint32>
|
||||
*/
|
||||
set<uint32>* getTileList(int mapID);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param navMesh
|
||||
*/
|
||||
void buildNavMesh(int mapID, dtNavMesh*& navMesh, dtNavMeshParams*& navMeshParams);
|
||||
|
||||
|
||||
/**
|
||||
* @brief move map building
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param meshData
|
||||
* @param bmin[]
|
||||
* @param bmax[]
|
||||
* @param navMesh
|
||||
*/
|
||||
void buildMoveMapTile(int mapID,
|
||||
int tileX,
|
||||
int tileY,
|
||||
MeshData& meshData,
|
||||
float bmin[3],
|
||||
float bmax[3],
|
||||
dtNavMesh* navMesh);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param verts
|
||||
* @param vertCount
|
||||
* @param bmin
|
||||
* @param bmax
|
||||
*/
|
||||
void getTileBounds(int tileX, int tileY,
|
||||
float* verts, int vertCount,
|
||||
float* bmin, float* bmax);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param minX
|
||||
* @param minY
|
||||
* @param maxX
|
||||
* @param maxY
|
||||
*/
|
||||
void getGridBounds(int mapID, uint32& minX, uint32& minY, uint32& maxX, uint32& maxY);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @return bool
|
||||
*/
|
||||
bool shouldSkipTile(int mapID, int tileX, int tileY);
|
||||
|
||||
TerrainBuilder* m_terrainBuilder; /**< TODO */
|
||||
TileList m_tiles; /**< TODO */
|
||||
|
||||
bool m_debugOutput; /**< TODO */
|
||||
|
||||
const char* m_offMeshFilePath; /**< TODO */
|
||||
bool m_skipContinents; /**< TODO */
|
||||
bool m_skipJunkMaps; /**< TODO */
|
||||
bool m_skipBattlegrounds; /**< TODO */
|
||||
|
||||
float m_maxWalkableAngle; /**< TODO */
|
||||
bool m_bigBaseUnit; /**< TODO */
|
||||
char const* m_magic;
|
||||
|
||||
int m_numThreads;
|
||||
TileThreadPool* m_threadPool;
|
||||
bool m_poolActivated;
|
||||
|
||||
rcContext* m_rcContext; /**< build performance - not really used for now */
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
IDI_APPICON ICON DISCARDABLE "../tools.ico"
|
||||
64
src/tools/Extractor_projects/Movemap-Generator/README.md
Normal file
64
src/tools/Extractor_projects/Movemap-Generator/README.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
mmap generator
|
||||
==============
|
||||
The *movement map generator* will extract pathfinding information from the
|
||||
game client in order to enable the *mangos* server to let creatures walk
|
||||
on the terrain as naturally as possible.
|
||||
|
||||
Please note that due to the complex nature of the process, the extraction and
|
||||
generation process may require a high amount of computing power any time.
|
||||
|
||||
Depending on your system, you should except ranges from four hours up to a full
|
||||
day for a full map generation of all in-game zones. Reducing the amount of zones
|
||||
generated will also reduce the time needed to wait.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
You will need a working installation of the [World of Warcraft][1] client patched
|
||||
to version 1.12.x.
|
||||
|
||||
Usage
|
||||
-----
|
||||
The `mmap-generator` command can be used with a set of parameters to fine-tune the
|
||||
process of movement map generation.
|
||||
|
||||
* `--offMeshInput [file.*]`: Path to file containing off mesh connections data,
|
||||
with a single mesh connection per line. Format must be:
|
||||
|
||||
`map_id tile_x,tile_y (start_x start_y start_z) (end_x end_y end_z) size //optional comments`
|
||||
|
||||
* `--silent`: Make us script friendly. Do not wait for user input on error or
|
||||
completion.
|
||||
* `--bigBaseUnit [true|false]`: Generate tile/map using bigger basic unit. Use this
|
||||
option only if you have unexpected gaps. If set to `false`, we will use normal
|
||||
metrics.
|
||||
* `--maxAngle [#]`: the maximum walkable inclination angle. By default this is set
|
||||
to `60`. Float values between 45 and 90 degrees are allowed.
|
||||
* `--skipLiquid`: skip liquid data for maps. Skipping liquid maps is disabled by
|
||||
default.
|
||||
* `--skipContinents [true|false]`: skip building continents. Disabled by default.
|
||||
Available continents are `0` (*Eastern Kingdoms*), and `1` (*Kalimdor*).
|
||||
* `--skipJunkMaps [true|false]`: skip junk maps, including some unused maps,
|
||||
transport maps, and some other maps. Junk maps are skipped by default.
|
||||
* `--skipBattlegrounds [true|false]`: skip battleground maps. By default battleground
|
||||
maps are included.
|
||||
* `--debugOutput [true|false]`: create debugging files for use with RecastDemo. If you
|
||||
are only creating movement maps for use with MaNGOS, you do not need debugging
|
||||
files built. By default, debugging files are not created.
|
||||
* `--tile [#,#]`: Build the specified tile seperate number with a comma ','.
|
||||
Must specify a map number (see below). If this option is not used, all tiles are
|
||||
built. If only one number is specified, builds the map specified by it.
|
||||
This command will build the map regardless of --skip* option settings. If you do
|
||||
not specify a map number, builds all maps that pass the filters specified by
|
||||
`--skip*` options.
|
||||
* `-h`, `--help`: show usage information.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
* `mmap-generator`: builds maps using the default settings (see above for defaults)
|
||||
* `mmap-generator --skipContinents true`: builds the default maps, except continents
|
||||
* `mmap-generator 0`: builds all tiles of map 0
|
||||
* `mmap-generator 0 --tile 34,46`: builds only tile 34,46 of map 0 (this is the southern face of blackrock mountain)
|
||||
|
||||
|
||||
[1]: http://blizzard.com/games/wow/ "World of Warcraft"
|
||||
|
|
@ -0,0 +1,997 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "TerrainBuilder.h"
|
||||
|
||||
#include "MMapCommon.h"
|
||||
#include "MapBuilder.h"
|
||||
|
||||
#include "VMapManager2.h"
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid(skipLiquid) { }
|
||||
TerrainBuilder::~TerrainBuilder() { }
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc)
|
||||
{
|
||||
switch (portion)
|
||||
{
|
||||
case ENTIRE:
|
||||
loopStart = 0;
|
||||
loopEnd = V8_SIZE_SQ;
|
||||
loopInc = 1;
|
||||
break;
|
||||
case TOP:
|
||||
loopStart = 0;
|
||||
loopEnd = V8_SIZE;
|
||||
loopInc = 1;
|
||||
break;
|
||||
case LEFT:
|
||||
loopStart = 0;
|
||||
loopEnd = V8_SIZE_SQ - V8_SIZE + 1;
|
||||
loopInc = V8_SIZE;
|
||||
break;
|
||||
case RIGHT:
|
||||
loopStart = V8_SIZE - 1;
|
||||
loopEnd = V8_SIZE_SQ;
|
||||
loopInc = V8_SIZE;
|
||||
break;
|
||||
case BOTTOM:
|
||||
loopStart = V8_SIZE_SQ - V8_SIZE;
|
||||
loopEnd = V8_SIZE_SQ;
|
||||
loopInc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData,char const* MAP_VERSION_MAGIC)
|
||||
{
|
||||
if (loadMap(mapID, tileX, tileY, meshData, ENTIRE, MAP_VERSION_MAGIC))
|
||||
{
|
||||
loadMap(mapID, tileX + 1, tileY, meshData, LEFT, MAP_VERSION_MAGIC);
|
||||
loadMap(mapID, tileX - 1, tileY, meshData, RIGHT, MAP_VERSION_MAGIC);
|
||||
loadMap(mapID, tileX, tileY + 1, meshData, TOP, MAP_VERSION_MAGIC);
|
||||
loadMap(mapID, tileX, tileY - 1, meshData, BOTTOM, MAP_VERSION_MAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, Spot portion,char const* MAP_VERSION_MAGIC)
|
||||
{
|
||||
char mapFileName[255];
|
||||
sprintf(mapFileName, "maps/%03u%02u%02u.map", mapID, tileY, tileX);
|
||||
|
||||
FILE* mapFile = fopen(mapFileName, "rb");
|
||||
if (!mapFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GridMapFileHeader fheader;
|
||||
size_t file_read = fread(&fheader, sizeof(GridMapFileHeader), 1, mapFile);
|
||||
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fheader.versionMagic != *((uint32 const*)(MAP_VERSION_MAGIC)))
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("%s is the wrong version, please extract new .map files\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
GridMapHeightHeader hheader;
|
||||
fseek(mapFile, fheader.heightMapOffset, SEEK_SET);
|
||||
file_read = fread(&hheader, sizeof(GridMapHeightHeader), 1, mapFile);
|
||||
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool haveTerrain = !(hheader.flags & MAP_HEIGHT_NO_HEIGHT);
|
||||
bool haveLiquid = fheader.liquidMapOffset && !m_skipLiquid;
|
||||
|
||||
// no data in this map file
|
||||
if (!haveTerrain && !haveLiquid)
|
||||
{
|
||||
fclose(mapFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// data used later
|
||||
uint16 holes[16][16];
|
||||
memset(holes, 0, sizeof(holes));
|
||||
uint8 liquid_type[16][16];
|
||||
memset(liquid_type, 0, sizeof(liquid_type));
|
||||
G3D::Array<int> ltriangles;
|
||||
G3D::Array<int> ttriangles;
|
||||
|
||||
// terrain data
|
||||
if (haveTerrain)
|
||||
{
|
||||
int i;
|
||||
float heightMultiplier;
|
||||
float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ];
|
||||
|
||||
if (hheader.flags & MAP_HEIGHT_AS_INT8)
|
||||
{
|
||||
uint8 v9[V9_SIZE_SQ];
|
||||
uint8 v8[V8_SIZE_SQ];
|
||||
file_read = fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
file_read = fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;
|
||||
|
||||
for (i = 0; i < V9_SIZE_SQ; ++i)
|
||||
{
|
||||
V9[i] = (float)v9[i] * heightMultiplier + hheader.gridHeight;
|
||||
}
|
||||
|
||||
for (i = 0; i < V8_SIZE_SQ; ++i)
|
||||
{
|
||||
V8[i] = (float)v8[i] * heightMultiplier + hheader.gridHeight;
|
||||
}
|
||||
}
|
||||
else if (hheader.flags & MAP_HEIGHT_AS_INT16)
|
||||
{
|
||||
uint16 v9[V9_SIZE_SQ];
|
||||
uint16 v8[V8_SIZE_SQ];
|
||||
file_read = fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
file_read = fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;
|
||||
|
||||
for (i = 0; i < V9_SIZE_SQ; ++i)
|
||||
{
|
||||
V9[i] = (float)v9[i] * heightMultiplier + hheader.gridHeight;
|
||||
}
|
||||
|
||||
for (i = 0; i < V8_SIZE_SQ; ++i)
|
||||
{
|
||||
V8[i] = (float)v8[i] * heightMultiplier + hheader.gridHeight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file_read = fread(V9, sizeof(float), V9_SIZE_SQ, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
file_read = fread(V8, sizeof(float), V8_SIZE_SQ, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// hole data
|
||||
memset(holes, 0, fheader.holesSize);
|
||||
fseek(mapFile, fheader.holesOffset, SEEK_SET);
|
||||
file_read = fread(holes, fheader.holesSize, 1, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = meshData.solidVerts.size() / 3;
|
||||
float xoffset = (float(tileX) - 32) * GRID_SIZE;
|
||||
float yoffset = (float(tileY) - 32) * GRID_SIZE;
|
||||
|
||||
float coord[3];
|
||||
|
||||
for (i = 0; i < V9_SIZE_SQ; ++i)
|
||||
{
|
||||
getHeightCoord(i, GRID_V9, xoffset, yoffset, coord, V9);
|
||||
meshData.solidVerts.append(coord[0]);
|
||||
meshData.solidVerts.append(coord[2]);
|
||||
meshData.solidVerts.append(coord[1]);
|
||||
}
|
||||
|
||||
for (i = 0; i < V8_SIZE_SQ; ++i)
|
||||
{
|
||||
getHeightCoord(i, GRID_V8, xoffset, yoffset, coord, V8);
|
||||
meshData.solidVerts.append(coord[0]);
|
||||
meshData.solidVerts.append(coord[2]);
|
||||
meshData.solidVerts.append(coord[1]);
|
||||
}
|
||||
|
||||
int j, indices[3], loopStart, loopEnd, loopInc;
|
||||
getLoopVars(portion, loopStart, loopEnd, loopInc);
|
||||
for (i = loopStart; i < loopEnd; i += loopInc)
|
||||
for (j = TOP; j <= BOTTOM; j += 1)
|
||||
{
|
||||
getHeightTriangle(i, Spot(j), indices);
|
||||
ttriangles.append(indices[2] + count);
|
||||
ttriangles.append(indices[1] + count);
|
||||
ttriangles.append(indices[0] + count);
|
||||
}
|
||||
}
|
||||
|
||||
// liquid data
|
||||
if (haveLiquid)
|
||||
{
|
||||
GridMapLiquidHeader lheader;
|
||||
fseek(mapFile, fheader.liquidMapOffset, SEEK_SET);
|
||||
file_read = fread(&lheader, sizeof(GridMapLiquidHeader), 1, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
float* liquid_map = NULL;
|
||||
|
||||
if (!(lheader.flags & MAP_LIQUID_NO_TYPE))
|
||||
{
|
||||
file_read = fread(liquid_type, sizeof(liquid_type), 1, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
|
||||
{
|
||||
liquid_map = new float [lheader.width * lheader.height];
|
||||
file_read = fread(liquid_map, sizeof(float), lheader.width * lheader.height, mapFile);
|
||||
if (file_read <= 0)
|
||||
{
|
||||
fclose(mapFile);
|
||||
delete [] liquid_map;
|
||||
printf("Could not read map data from %s.\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (liquid_type && liquid_map)
|
||||
{
|
||||
int count = meshData.liquidVerts.size() / 3;
|
||||
float xoffset = (float(tileX) - 32) * GRID_SIZE;
|
||||
float yoffset = (float(tileY) - 32) * GRID_SIZE;
|
||||
|
||||
float coord[3];
|
||||
int row, col;
|
||||
|
||||
// generate coordinates
|
||||
if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
|
||||
{
|
||||
int j = 0;
|
||||
for (int i = 0; i < V9_SIZE_SQ; ++i)
|
||||
{
|
||||
row = i / V9_SIZE;
|
||||
col = i % V9_SIZE;
|
||||
|
||||
if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height ||
|
||||
col < lheader.offsetX || col >= lheader.offsetX + lheader.width)
|
||||
{
|
||||
// dummy vert using invalid height
|
||||
meshData.liquidVerts.append((xoffset + col * GRID_PART_SIZE) * -1, INVALID_MAP_LIQ_HEIGHT, (yoffset + row * GRID_PART_SIZE) * -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map);
|
||||
meshData.liquidVerts.append(coord[0]);
|
||||
meshData.liquidVerts.append(coord[2]);
|
||||
meshData.liquidVerts.append(coord[1]);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < V9_SIZE_SQ; ++i)
|
||||
{
|
||||
row = i / V9_SIZE;
|
||||
col = i % V9_SIZE;
|
||||
meshData.liquidVerts.append((xoffset + col * GRID_PART_SIZE) * -1, lheader.liquidLevel, (yoffset + row * GRID_PART_SIZE) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
delete [] liquid_map;
|
||||
|
||||
int indices[3], loopStart, loopEnd, loopInc, triInc;
|
||||
getLoopVars(portion, loopStart, loopEnd, loopInc);
|
||||
triInc = BOTTOM - TOP;
|
||||
|
||||
// generate triangles
|
||||
for (int i = loopStart; i < loopEnd; i += loopInc)
|
||||
for (int j = TOP; j <= BOTTOM; j += triInc)
|
||||
{
|
||||
getHeightTriangle(i, Spot(j), indices, true);
|
||||
ltriangles.append(indices[2] + count);
|
||||
ltriangles.append(indices[1] + count);
|
||||
ltriangles.append(indices[0] + count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(mapFile);
|
||||
|
||||
// now that we have gathered the data, we can figure out which parts to keep:
|
||||
// liquid above ground, ground above liquid
|
||||
int loopStart, loopEnd, loopInc, tTriCount = 4;
|
||||
bool useTerrain, useLiquid;
|
||||
|
||||
float* lverts = meshData.liquidVerts.getCArray();
|
||||
int* ltris = ltriangles.getCArray();
|
||||
|
||||
float* tverts = meshData.solidVerts.getCArray();
|
||||
int* ttris = ttriangles.getCArray();
|
||||
|
||||
if (ltriangles.size() + ttriangles.size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make a copy of liquid vertices
|
||||
// used to pad right-bottom frame due to lost vertex data at extraction
|
||||
float* lverts_copy = NULL;
|
||||
if (meshData.liquidVerts.size())
|
||||
{
|
||||
lverts_copy = new float[meshData.liquidVerts.size()];
|
||||
memcpy(lverts_copy, lverts, sizeof(float)*meshData.liquidVerts.size());
|
||||
}
|
||||
|
||||
getLoopVars(portion, loopStart, loopEnd, loopInc);
|
||||
for (int i = loopStart; i < loopEnd; i += loopInc)
|
||||
{
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
// default is true, will change to false if needed
|
||||
useTerrain = true;
|
||||
useLiquid = true;
|
||||
uint8 liquidType = MAP_LIQUID_TYPE_NO_WATER;
|
||||
|
||||
// if there is no liquid, don't use liquid
|
||||
if (!liquid_type || !meshData.liquidVerts.size() || !ltriangles.size())
|
||||
{
|
||||
useLiquid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
liquidType = getLiquidType(i, liquid_type);
|
||||
switch (liquidType)
|
||||
{
|
||||
default:
|
||||
useLiquid = false;
|
||||
break;
|
||||
case MAP_LIQUID_TYPE_WATER:
|
||||
case MAP_LIQUID_TYPE_OCEAN:
|
||||
// merge different types of water
|
||||
liquidType = NAV_WATER;
|
||||
break;
|
||||
case MAP_LIQUID_TYPE_MAGMA:
|
||||
liquidType = NAV_MAGMA;
|
||||
break;
|
||||
case MAP_LIQUID_TYPE_SLIME:
|
||||
liquidType = NAV_SLIME;
|
||||
break;
|
||||
case MAP_LIQUID_TYPE_DARK_WATER:
|
||||
// players should not be here, so logically neither should creatures
|
||||
useTerrain = false;
|
||||
useLiquid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if there is no terrain, don't use terrain
|
||||
if (!ttriangles.size())
|
||||
{
|
||||
useTerrain = false;
|
||||
}
|
||||
|
||||
// while extracting ADT data we are losing right-bottom vertices
|
||||
// this code adds fair approximation of lost data
|
||||
if (useLiquid)
|
||||
{
|
||||
float quadHeight = 0;
|
||||
uint32 validCount = 0;
|
||||
for (uint32 idx = 0; idx < 3; idx++)
|
||||
{
|
||||
float h = lverts_copy[ltris[idx] * 3 + 1];
|
||||
if (h != INVALID_MAP_LIQ_HEIGHT && h < INVALID_MAP_LIQ_HEIGHT_MAX)
|
||||
{
|
||||
quadHeight += h;
|
||||
validCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// update vertex height data
|
||||
if (validCount > 0 && validCount < 3)
|
||||
{
|
||||
quadHeight /= validCount;
|
||||
for (uint32 idx = 0; idx < 3; idx++)
|
||||
{
|
||||
float h = lverts[ltris[idx] * 3 + 1];
|
||||
if (h == INVALID_MAP_LIQ_HEIGHT || h > INVALID_MAP_LIQ_HEIGHT_MAX)
|
||||
{
|
||||
lverts[ltris[idx] * 3 + 1] = quadHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no valid vertexes - don't use this poly at all
|
||||
if (validCount == 0)
|
||||
{
|
||||
useLiquid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if there is a hole here, don't use the terrain
|
||||
if (useTerrain)
|
||||
{
|
||||
useTerrain = !isHole(i, holes);
|
||||
}
|
||||
|
||||
// we use only one terrain kind per quad - pick higher one
|
||||
if (useTerrain && useLiquid)
|
||||
{
|
||||
float minLLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
|
||||
float maxLLevel = INVALID_MAP_LIQ_HEIGHT;
|
||||
for (uint32 x = 0; x < 3; x++)
|
||||
{
|
||||
float h = lverts[ltris[x] * 3 + 1];
|
||||
if (minLLevel > h)
|
||||
{
|
||||
minLLevel = h;
|
||||
}
|
||||
|
||||
if (maxLLevel < h)
|
||||
{
|
||||
maxLLevel = h;
|
||||
}
|
||||
}
|
||||
|
||||
float maxTLevel = INVALID_MAP_LIQ_HEIGHT;
|
||||
float minTLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
|
||||
for (uint32 x = 0; x < 6; x++)
|
||||
{
|
||||
float h = tverts[ttris[x] * 3 + 1];
|
||||
if (maxTLevel < h)
|
||||
{
|
||||
maxTLevel = h;
|
||||
}
|
||||
|
||||
if (minTLevel > h)
|
||||
{
|
||||
minTLevel = h;
|
||||
}
|
||||
}
|
||||
|
||||
// terrain under the liquid?
|
||||
if (minLLevel > maxTLevel)
|
||||
{
|
||||
useTerrain = false;
|
||||
}
|
||||
|
||||
//liquid under the terrain?
|
||||
if (minTLevel > maxLLevel)
|
||||
{
|
||||
useLiquid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// store the result
|
||||
if (useLiquid)
|
||||
{
|
||||
meshData.liquidType.append(liquidType);
|
||||
for (int k = 0; k < 3; ++k)
|
||||
{
|
||||
meshData.liquidTris.append(ltris[k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (useTerrain)
|
||||
for (int k = 0; k < 3 * tTriCount / 2; ++k)
|
||||
{
|
||||
meshData.solidTris.append(ttris[k]);
|
||||
}
|
||||
|
||||
// advance to next set of triangles
|
||||
ltris += 3;
|
||||
ttris += 3 * tTriCount / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (lverts_copy)
|
||||
{
|
||||
delete [] lverts_copy;
|
||||
}
|
||||
|
||||
return meshData.solidTris.size() || meshData.liquidTris.size();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v)
|
||||
{
|
||||
// wow coords: x, y, height
|
||||
// coord is mirroed about the horizontal axes
|
||||
switch (grid)
|
||||
{
|
||||
case GRID_V9:
|
||||
coord[0] = (xOffset + index % (V9_SIZE) * GRID_PART_SIZE) * -1.f;
|
||||
coord[1] = (yOffset + (int)(index / (V9_SIZE)) * GRID_PART_SIZE) * -1.f;
|
||||
coord[2] = v[index];
|
||||
break;
|
||||
case GRID_V8:
|
||||
coord[0] = (xOffset + index % (V8_SIZE) * GRID_PART_SIZE + GRID_PART_SIZE / 2.f) * -1.f;
|
||||
coord[1] = (yOffset + (int)(index / (V8_SIZE)) * GRID_PART_SIZE + GRID_PART_SIZE / 2.f) * -1.f;
|
||||
coord[2] = v[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::getHeightTriangle(int square, Spot triangle, int* indices, bool liquid/* = false*/)
|
||||
{
|
||||
int rowOffset = square / V8_SIZE;
|
||||
if (!liquid)
|
||||
switch (triangle)
|
||||
{
|
||||
case TOP:
|
||||
indices[0] = square + rowOffset; // 0-----1 .... 128
|
||||
indices[1] = square + 1 + rowOffset; // |\ T /|
|
||||
indices[2] = (V9_SIZE_SQ) + square; // | \ / |
|
||||
break; // |L 0 R| .. 127
|
||||
case LEFT: // | / \ |
|
||||
indices[0] = square + rowOffset; // |/ B \|
|
||||
indices[1] = (V9_SIZE_SQ) + square; // 129---130 ... 386
|
||||
indices[2] = square + V9_SIZE + rowOffset; // |\ /|
|
||||
break; // | \ / |
|
||||
case RIGHT: // | 128 | .. 255
|
||||
indices[0] = square + 1 + rowOffset; // | / \ |
|
||||
indices[1] = square + V9_SIZE + 1 + rowOffset; // |/ \|
|
||||
indices[2] = (V9_SIZE_SQ) + square; // 258---259 ... 515
|
||||
break;
|
||||
case BOTTOM:
|
||||
indices[0] = (V9_SIZE_SQ) + square;
|
||||
indices[1] = square + V9_SIZE + 1 + rowOffset;
|
||||
indices[2] = square + V9_SIZE + rowOffset;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
else
|
||||
switch (triangle)
|
||||
{
|
||||
// 0-----1 .... 128
|
||||
case TOP: // |\ |
|
||||
indices[0] = square + rowOffset; // | \ T |
|
||||
indices[1] = square + 1 + rowOffset; // | \ |
|
||||
indices[2] = square + V9_SIZE + 1 + rowOffset; // | B \ |
|
||||
break; // | \|
|
||||
case BOTTOM: // 129---130 ... 386
|
||||
indices[0] = square + rowOffset; // |\ |
|
||||
indices[1] = square + V9_SIZE + 1 + rowOffset; // | \ |
|
||||
indices[2] = square + V9_SIZE + rowOffset; // | \ |
|
||||
break; // | \ |
|
||||
default: break; // | \|
|
||||
} // 258---259 ... 515
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v)
|
||||
{
|
||||
// wow coords: x, y, height
|
||||
// coord is mirroed about the horizontal axes
|
||||
coord[0] = (xOffset + index % (V9_SIZE) * GRID_PART_SIZE) * -1.f;
|
||||
coord[1] = (yOffset + (int)(index / (V9_SIZE)) * GRID_PART_SIZE) * -1.f;
|
||||
coord[2] = v[index2];
|
||||
}
|
||||
|
||||
static uint16 holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
|
||||
static uint16 holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
|
||||
|
||||
/**************************************************************************/
|
||||
bool TerrainBuilder::isHole(int square, const uint16 holes[16][16])
|
||||
{
|
||||
int row = square / 128;
|
||||
int col = square % 128;
|
||||
int cellRow = row / 8; // 8 squares per cell
|
||||
int cellCol = col / 8;
|
||||
int holeRow = row % 8 / 2;
|
||||
int holeCol = (square - (row * 128 + cellCol * 8)) / 2;
|
||||
|
||||
uint16 hole = holes[cellRow][cellCol];
|
||||
|
||||
return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
uint8 TerrainBuilder::getLiquidType(int square, const uint8 liquid_type[16][16])
|
||||
{
|
||||
int row = square / 128;
|
||||
int col = square % 128;
|
||||
int cellRow = row / 8; // 8 squares per cell
|
||||
int cellCol = col / 8;
|
||||
|
||||
return liquid_type[cellRow][cellCol];
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData)
|
||||
{
|
||||
IVMapManager* vmapManager = new VMapManager2();
|
||||
VMAPLoadResult result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
|
||||
bool retval = false;
|
||||
|
||||
do
|
||||
{
|
||||
if (result == VMAP_LOAD_RESULT_ERROR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceTreeMap instanceTrees;
|
||||
((VMapManager2*)vmapManager)->getInstanceMapTree(instanceTrees);
|
||||
|
||||
if (!instanceTrees[mapID])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ModelInstance* models = NULL;
|
||||
uint32 count = 0;
|
||||
instanceTrees[mapID]->getModelInstances(models, count);
|
||||
|
||||
if (!models)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
{
|
||||
ModelInstance instance = models[i];
|
||||
|
||||
// model instances exist in tree even though there are instances of that model in this tile
|
||||
WorldModel* worldModel = instance.getWorldModel();
|
||||
if (!worldModel)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we have a model to add to the meshdata
|
||||
retval = true;
|
||||
|
||||
vector<GroupModel> groupModels;
|
||||
worldModel->getGroupModels(groupModels);
|
||||
|
||||
// all M2s need to have triangle indices reversed
|
||||
bool isM2 = instance.name.find(".m2") != instance.name.npos || instance.name.find(".M2") != instance.name.npos;
|
||||
|
||||
// transform data
|
||||
float scale = instance.iScale;
|
||||
G3D::Matrix3 rotation = G3D::Matrix3::fromEulerAnglesXYZ(G3D::pi() * instance.iRot.z / -180.f, G3D::pi() * instance.iRot.x / -180.f, G3D::pi() * instance.iRot.y / -180.f);
|
||||
Vector3 position = instance.iPos;
|
||||
position.x -= 32 * GRID_SIZE;
|
||||
position.y -= 32 * GRID_SIZE;
|
||||
|
||||
for (vector<GroupModel>::iterator it = groupModels.begin(); it != groupModels.end(); ++it)
|
||||
{
|
||||
vector<Vector3> tempVertices;
|
||||
vector<Vector3> transformedVertices;
|
||||
vector<MeshTriangle> tempTriangles;
|
||||
WmoLiquid* liquid = NULL;
|
||||
|
||||
(*it).getMeshData(tempVertices, tempTriangles, liquid);
|
||||
|
||||
// first handle collision mesh
|
||||
transform(tempVertices, transformedVertices, scale, rotation, position);
|
||||
|
||||
int offset = meshData.solidVerts.size() / 3;
|
||||
|
||||
copyVertices(transformedVertices, meshData.solidVerts);
|
||||
copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
|
||||
|
||||
// now handle liquid data
|
||||
if (liquid)
|
||||
{
|
||||
vector<Vector3> liqVerts;
|
||||
vector<int> liqTris;
|
||||
uint32 tilesX, tilesY, vertsX, vertsY;
|
||||
Vector3 corner;
|
||||
liquid->getPosInfo(tilesX, tilesY, corner);
|
||||
vertsX = tilesX + 1;
|
||||
vertsY = tilesY + 1;
|
||||
uint8* flags = liquid->GetFlagsStorage();
|
||||
float* data = liquid->GetHeightStorage();
|
||||
uint8 type = NAV_EMPTY;
|
||||
|
||||
// convert liquid type to NavTerrain
|
||||
switch (liquid->GetType())
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
type = NAV_WATER;
|
||||
break;
|
||||
case 2:
|
||||
type = NAV_MAGMA;
|
||||
break;
|
||||
case 3:
|
||||
type = NAV_SLIME;
|
||||
break;
|
||||
}
|
||||
|
||||
// indexing is weird...
|
||||
// after a lot of trial and error, this is what works:
|
||||
// vertex = y*vertsX+x
|
||||
// tile = x*tilesY+y
|
||||
// flag = y*tilesY+x
|
||||
|
||||
Vector3 vert;
|
||||
for (uint32 x = 0; x < vertsX; ++x)
|
||||
for (uint32 y = 0; y < vertsY; ++y)
|
||||
{
|
||||
vert = Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y * vertsX + x]);
|
||||
vert = vert * rotation * scale + position;
|
||||
vert.x *= -1.f;
|
||||
vert.y *= -1.f;
|
||||
liqVerts.push_back(vert);
|
||||
}
|
||||
|
||||
int idx1, idx2, idx3, idx4;
|
||||
uint32 square;
|
||||
for (uint32 x = 0; x < tilesX; ++x)
|
||||
for (uint32 y = 0; y < tilesY; ++y)
|
||||
if ((flags[x + y * tilesX] & 0x0f) != 0x0f)
|
||||
{
|
||||
square = x * tilesY + y;
|
||||
idx1 = square + x;
|
||||
idx2 = square + 1 + x;
|
||||
idx3 = square + tilesY + 1 + 1 + x;
|
||||
idx4 = square + tilesY + 1 + x;
|
||||
|
||||
// top triangle
|
||||
liqTris.push_back(idx3);
|
||||
liqTris.push_back(idx2);
|
||||
liqTris.push_back(idx1);
|
||||
// bottom triangle
|
||||
liqTris.push_back(idx4);
|
||||
liqTris.push_back(idx3);
|
||||
liqTris.push_back(idx1);
|
||||
}
|
||||
|
||||
uint32 liqOffset = meshData.liquidVerts.size() / 3;
|
||||
for (uint32 i = 0; i < liqVerts.size(); ++i)
|
||||
{
|
||||
meshData.liquidVerts.append(liqVerts[i].y, liqVerts[i].z, liqVerts[i].x);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < liqTris.size() / 3; ++i)
|
||||
{
|
||||
meshData.liquidTris.append(liqTris[i * 3 + 1] + liqOffset, liqTris[i * 3 + 2] + liqOffset, liqTris[i * 3] + liqOffset);
|
||||
meshData.liquidType.append(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (false);
|
||||
|
||||
vmapManager->unloadMap(mapID, tileX, tileY);
|
||||
delete vmapManager;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::transform(vector<Vector3>& source, vector<Vector3>& transformedVertices, float scale, G3D::Matrix3& rotation, Vector3& position)
|
||||
{
|
||||
for (vector<Vector3>::iterator it = source.begin(); it != source.end(); ++it)
|
||||
{
|
||||
// apply tranform, then mirror along the horizontal axes
|
||||
Vector3 v((*it) * rotation * scale + position);
|
||||
v.x *= -1.f;
|
||||
v.y *= -1.f;
|
||||
transformedVertices.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::copyVertices(vector<Vector3>& source, G3D::Array<float>& dest)
|
||||
{
|
||||
for (vector<Vector3>::iterator it = source.begin(); it != source.end(); ++it)
|
||||
{
|
||||
dest.push_back((*it).y);
|
||||
dest.push_back((*it).z);
|
||||
dest.push_back((*it).x);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::copyIndices(vector<MeshTriangle>& source, G3D::Array<int>& dest, int offset, bool flip)
|
||||
{
|
||||
if (flip)
|
||||
{
|
||||
for (vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
|
||||
{
|
||||
dest.push_back((*it).idx2 + offset);
|
||||
dest.push_back((*it).idx1 + offset);
|
||||
dest.push_back((*it).idx0 + offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
|
||||
{
|
||||
dest.push_back((*it).idx0 + offset);
|
||||
dest.push_back((*it).idx1 + offset);
|
||||
dest.push_back((*it).idx2 + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::copyIndices(G3D::Array<int>& source, G3D::Array<int>& dest, int offset)
|
||||
{
|
||||
int* src = source.getCArray();
|
||||
for (int32 i = 0; i < source.size(); ++i)
|
||||
{
|
||||
dest.append(src[i] + offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::cleanVertices(G3D::Array<float>& verts, G3D::Array<int>& tris)
|
||||
{
|
||||
map<int, int> vertMap;
|
||||
|
||||
int* t = tris.getCArray();
|
||||
float* v = verts.getCArray();
|
||||
|
||||
// collect all the vertex indices from triangle
|
||||
for (int i = 0; i < tris.size(); ++i)
|
||||
{
|
||||
if (vertMap.find(t[i]) != vertMap.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
vertMap.insert(std::pair<int, int>(t[i], 0));
|
||||
}
|
||||
|
||||
// collect the vertices
|
||||
G3D::Array<float> cleanVerts;
|
||||
int index, count = 0;
|
||||
for (map<int, int>::iterator it = vertMap.begin(); it != vertMap.end(); ++it)
|
||||
{
|
||||
index = (*it).first;
|
||||
(*it).second = count;
|
||||
cleanVerts.append(v[index * 3], v[index * 3 + 1], v[index * 3 + 2]);
|
||||
count++;
|
||||
}
|
||||
verts.fastClear();
|
||||
verts.append(cleanVerts);
|
||||
cleanVerts.clear();
|
||||
|
||||
// update triangles to use new indices
|
||||
for (int i = 0; i < tris.size(); ++i)
|
||||
{
|
||||
map<int, int>::iterator it;
|
||||
if ((it = vertMap.find(t[i])) == vertMap.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
t[i] = (*it).second;
|
||||
}
|
||||
|
||||
vertMap.clear();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, const char* offMeshFilePath)
|
||||
{
|
||||
// no meshfile input given?
|
||||
if (offMeshFilePath == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(offMeshFilePath, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
printf(" loadOffMeshConnections:: input file %s not found!\n", offMeshFilePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// pretty silly thing, as we parse entire file and load only the tile we need
|
||||
// but we don't expect this file to be too large
|
||||
char* buf = new char[512];
|
||||
while (fgets(buf, 512, fp))
|
||||
{
|
||||
float p0[3], p1[3];
|
||||
int mid, tx, ty;
|
||||
float size;
|
||||
if (10 != sscanf(buf, "%d %d,%d (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty,
|
||||
&p0[0], &p0[1], &p0[2], &p1[0], &p1[1], &p1[2], &size))
|
||||
{ continue; }
|
||||
|
||||
if ((mapID == mid) && (tileX == tx) && (tileY == ty))
|
||||
{
|
||||
meshData.offMeshConnections.append(p0[1]);
|
||||
meshData.offMeshConnections.append(p0[2]);
|
||||
meshData.offMeshConnections.append(p0[0]);
|
||||
|
||||
meshData.offMeshConnections.append(p1[1]);
|
||||
meshData.offMeshConnections.append(p1[2]);
|
||||
meshData.offMeshConnections.append(p1[0]);
|
||||
|
||||
meshData.offMeshConnectionDirs.append(1); // 1 - both direction, 0 - one sided
|
||||
meshData.offMeshConnectionRads.append(size); // agent size equivalent
|
||||
// can be used same way as polygon flags
|
||||
meshData.offMeshConnectionsAreas.append((unsigned char)0xFF);
|
||||
meshData.offMeshConnectionsFlags.append((unsigned short)0xFF); // all movement masks can make this path
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete [] buf;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
302
src/tools/Extractor_projects/Movemap-Generator/TerrainBuilder.h
Normal file
302
src/tools/Extractor_projects/Movemap-Generator/TerrainBuilder.h
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_H_MMAP_TERRAIN_BUILDER
|
||||
#define MANGOS_H_MMAP_TERRAIN_BUILDER
|
||||
|
||||
#include "MMapCommon.h"
|
||||
#include "MangosMap.h"
|
||||
#include "MoveMapSharedDefines.h"
|
||||
|
||||
#include "WorldModel.h"
|
||||
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Matrix3.h"
|
||||
|
||||
using namespace MaNGOS;
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
enum Spot
|
||||
{
|
||||
TOP = 1,
|
||||
RIGHT = 2,
|
||||
LEFT = 3,
|
||||
BOTTOM = 4,
|
||||
ENTIRE = 5
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
enum Grid
|
||||
{
|
||||
GRID_V8,
|
||||
GRID_V9
|
||||
};
|
||||
|
||||
static const int V9_SIZE = 129; /**< TODO */
|
||||
static const int V9_SIZE_SQ = V9_SIZE* V9_SIZE; /**< TODO */
|
||||
static const int V8_SIZE = 128; /**< TODO */
|
||||
static const int V8_SIZE_SQ = V8_SIZE* V8_SIZE; /**< TODO */
|
||||
static const float GRID_SIZE = 533.33333f; /**< TODO */
|
||||
static const float GRID_PART_SIZE = GRID_SIZE / V8_SIZE; /**< TODO */
|
||||
|
||||
// see contrib/extractor/system.cpp, CONF_use_minHeight
|
||||
static const float INVALID_MAP_LIQ_HEIGHT = -500.f; /**< TODO */
|
||||
static const float INVALID_MAP_LIQ_HEIGHT_MAX = 5000.0f; /**< TODO */
|
||||
|
||||
// see following files:
|
||||
// src/tools/map-extractor/system.cpp
|
||||
// src/game/GridMap.cpp
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct MeshData
|
||||
{
|
||||
G3D::Array<float> solidVerts; /**< TODO */
|
||||
G3D::Array<int> solidTris; /**< TODO */
|
||||
|
||||
G3D::Array<float> liquidVerts; /**< TODO */
|
||||
G3D::Array<int> liquidTris; /**< TODO */
|
||||
G3D::Array<uint8> liquidType; /**< TODO */
|
||||
|
||||
// offmesh connection data
|
||||
G3D::Array<float> offMeshConnections; // [p0y,p0z,p0x,p1y,p1z,p1x] - per connection /**< TODO */
|
||||
G3D::Array<float> offMeshConnectionRads; /**< TODO */
|
||||
G3D::Array<unsigned char> offMeshConnectionDirs; /**< TODO */
|
||||
G3D::Array<unsigned char> offMeshConnectionsAreas; /**< TODO */
|
||||
G3D::Array<unsigned short> offMeshConnectionsFlags; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class TerrainBuilder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param skipLiquid
|
||||
*/
|
||||
TerrainBuilder(bool skipLiquid);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~TerrainBuilder();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param meshData
|
||||
*/
|
||||
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, char const* MAP_VERSION_MAGIC);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param meshData
|
||||
* @return bool
|
||||
*/
|
||||
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param meshData
|
||||
* @param offMeshFilePath
|
||||
*/
|
||||
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, const char* offMeshFilePath);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool usesLiquids() { return !m_skipLiquid; }
|
||||
|
||||
/**
|
||||
* @brief vert and triangle methods
|
||||
*
|
||||
* @param original
|
||||
* @param transformed
|
||||
* @param scale
|
||||
* @param rotation
|
||||
* @param position
|
||||
*/
|
||||
static void transform(vector<G3D::Vector3>& original, vector<G3D::Vector3>& transformed,
|
||||
float scale, G3D::Matrix3& rotation, G3D::Vector3& position);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param source
|
||||
* @param dest
|
||||
*/
|
||||
static void copyVertices(vector<G3D::Vector3>& source, G3D::Array<float>& dest);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param source
|
||||
* @param dest
|
||||
* @param offest
|
||||
* @param flip
|
||||
*/
|
||||
static void copyIndices(vector<VMAP::MeshTriangle>& source, G3D::Array<int>& dest, int offest, bool flip);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param src
|
||||
* @param dest
|
||||
* @param offset
|
||||
*/
|
||||
static void copyIndices(G3D::Array<int>& src, G3D::Array<int>& dest, int offset);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param verts
|
||||
* @param tris
|
||||
*/
|
||||
static void cleanVertices(G3D::Array<float>& verts, G3D::Array<int>& tris);
|
||||
private:
|
||||
/**
|
||||
* @brief Loads a portion of a map's terrain
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param meshData
|
||||
* @param portion
|
||||
* @return bool
|
||||
*/
|
||||
bool loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, Spot portion, char const* MAP_VERSION_MAGIC);
|
||||
|
||||
/**
|
||||
* @brief Sets loop variables for selecting only certain parts of a map's terrain
|
||||
*
|
||||
* @param portion
|
||||
* @param loopStart
|
||||
* @param loopEnd
|
||||
* @param loopInc
|
||||
*/
|
||||
void getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc);
|
||||
|
||||
bool m_skipLiquid; /**< Controls whether liquids are loaded */
|
||||
|
||||
/**
|
||||
* @brief Load the map terrain from file
|
||||
*
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param vertices
|
||||
* @param triangles
|
||||
* @param portion
|
||||
* @return bool
|
||||
*/
|
||||
bool loadHeightMap(uint32 mapID, uint32 tileX, uint32 tileY, G3D::Array<float>& vertices, G3D::Array<int>& triangles, Spot portion);
|
||||
|
||||
/**
|
||||
* @brief Get the vector coordinate for a specific position
|
||||
*
|
||||
* @param index
|
||||
* @param grid
|
||||
* @param xOffset
|
||||
* @param yOffset
|
||||
* @param coord
|
||||
* @param v
|
||||
*/
|
||||
void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v);
|
||||
|
||||
/**
|
||||
* @brief Get the triangle's vector indices for a specific position
|
||||
*
|
||||
* @param square
|
||||
* @param triangle
|
||||
* @param indices
|
||||
* @param liquid
|
||||
*/
|
||||
void getHeightTriangle(int square, Spot triangle, int* indices, bool liquid = false);
|
||||
|
||||
/**
|
||||
* @brief Determines if the specific position's triangles should be rendered
|
||||
*
|
||||
* @param square
|
||||
* @param holes[][]
|
||||
* @return bool
|
||||
*/
|
||||
bool isHole(int square, const uint16 holes[16][16]);
|
||||
|
||||
/**
|
||||
* @brief Get the liquid vector coordinate for a specific position
|
||||
*
|
||||
* @param index
|
||||
* @param index2
|
||||
* @param xOffset
|
||||
* @param yOffset
|
||||
* @param coord
|
||||
* @param v
|
||||
*/
|
||||
void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v);
|
||||
|
||||
/**
|
||||
* @brief Get the liquid type for a specific position
|
||||
*
|
||||
* @param square
|
||||
* @param liquid_type[][]
|
||||
* @return uint8
|
||||
*/
|
||||
uint8 getLiquidType(int square, const uint8 liquid_type[16][16]);
|
||||
|
||||
/**
|
||||
* @brief hide parameterless constructor
|
||||
*
|
||||
*/
|
||||
TerrainBuilder();
|
||||
/**
|
||||
* @brief hide copy constructor
|
||||
*
|
||||
* @param tb
|
||||
*/
|
||||
TerrainBuilder(const TerrainBuilder& tb);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef TILE_MESSAGE_BLOCK_H
|
||||
#define TILE_MESSAGE_BLOCK_H
|
||||
|
||||
#include "ace/Message_Block.h"
|
||||
#include "MapBuilder.h"
|
||||
|
||||
class TileBuilder
|
||||
{
|
||||
public:
|
||||
TileBuilder(MMAP::MapBuilder* builder, int mapID, int tileX, int tileY, dtNavMesh* mesh) :
|
||||
m_navMesh(mesh), m_tileY(tileY), m_tileX(tileX), m_mapID(mapID), m_builder(builder) {}
|
||||
~TileBuilder() { delete m_navMesh; }
|
||||
void Work() { m_builder->buildTile(m_mapID, m_tileX, m_tileY, m_navMesh); }
|
||||
private:
|
||||
int m_mapID;
|
||||
int m_tileX;
|
||||
int m_tileY;
|
||||
MMAP::MapBuilder* m_builder;
|
||||
dtNavMesh* m_navMesh;
|
||||
};
|
||||
|
||||
|
||||
class Tile_Message_Block : public ACE_Message_Block
|
||||
{
|
||||
public:
|
||||
typedef ACE_Message_Block BASE;
|
||||
|
||||
Tile_Message_Block(TileBuilder* _tileBuilder, size_t size = 0) : BASE(size), m_tileBuilder(_tileBuilder) {}
|
||||
~Tile_Message_Block() { delete m_tileBuilder; }
|
||||
|
||||
TileBuilder* GetTileBuilder() const { return m_tileBuilder; }
|
||||
|
||||
protected:
|
||||
Tile_Message_Block& operator=(const Tile_Message_Block&);
|
||||
Tile_Message_Block(const Tile_Message_Block&);
|
||||
|
||||
TileBuilder* m_tileBuilder;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "TileThreadPool.h"
|
||||
#include "TileMsgBlock.h"
|
||||
|
||||
TileThreadPool::TileThreadPool(): m_barrier(0)
|
||||
{
|
||||
}
|
||||
|
||||
TileThreadPool::~TileThreadPool()
|
||||
{
|
||||
ACE_Message_Block *msg;
|
||||
this->getq(msg);
|
||||
msg->release();
|
||||
|
||||
delete m_barrier;
|
||||
}
|
||||
|
||||
int TileThreadPool::start(int threads)
|
||||
{
|
||||
m_barrier = new ACE_Barrier(threads);
|
||||
return this->activate(THR_NEW_LWP, threads);
|
||||
}
|
||||
|
||||
int TileThreadPool::svc(void)
|
||||
{
|
||||
m_barrier->wait();
|
||||
|
||||
ACE_Message_Block *msg;
|
||||
while (1)
|
||||
{
|
||||
if (this->getq(msg) == -1)
|
||||
{
|
||||
ACE_ERROR_RETURN((LM_ERROR, "%p\n", "getq"), -1);
|
||||
}
|
||||
|
||||
if (msg->msg_type() == ACE_Message_Block::MB_HANGUP)
|
||||
{
|
||||
this->putq(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
Tile_Message_Block *mb = (Tile_Message_Block*)msg;
|
||||
mb->GetTileBuilder()->Work();
|
||||
|
||||
msg->release ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef TILE_THREAD_POOL_H
|
||||
#define TILE_THREAD_POOL_H
|
||||
|
||||
#include "ace/Task.h"
|
||||
#include "ace/Barrier.h"
|
||||
|
||||
|
||||
class TileThreadPool : public ACE_Task<ACE_MT_SYNCH>
|
||||
{
|
||||
public:
|
||||
TileThreadPool();
|
||||
~TileThreadPool();
|
||||
int start(int threads = 1);
|
||||
virtual int svc(void);
|
||||
|
||||
protected:
|
||||
ACE_Barrier *m_barrier;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "MapTree.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "WorldModel.h"
|
||||
#include "ModelInstance.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
// Need direct access to encapsulated VMAP data, so we add functions for MMAP generator
|
||||
// maybe add MapBuilder as friend to all of the below classes would be better?
|
||||
|
||||
// declared in src/shared/vmap/MapTree.h
|
||||
void StaticMapTree::getModelInstances(ModelInstance*& models, uint32& count)
|
||||
{
|
||||
models = iTreeValues;
|
||||
count = iNTreeValues;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/VMapManager2.h
|
||||
void VMapManager2::getInstanceMapTree(InstanceTreeMap& instanceMapTree)
|
||||
{
|
||||
instanceMapTree = iInstanceMapTrees;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/WorldModel.h
|
||||
void WorldModel::getGroupModels(vector<GroupModel>& groupModels)
|
||||
{
|
||||
groupModels = this->groupModels;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/WorldModel.h
|
||||
void GroupModel::getMeshData(vector<Vector3>& vertices, vector<MeshTriangle>& triangles, WmoLiquid*& liquid)
|
||||
{
|
||||
vertices = this->vertices;
|
||||
triangles = this->triangles;
|
||||
liquid = iLiquid;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/ModelInstance.h
|
||||
WorldModel* const ModelInstance::getWorldModel()
|
||||
{
|
||||
return iModel;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/WorldModel.h
|
||||
void WmoLiquid::getPosInfo(uint32& tilesX, uint32& tilesY, Vector3& corner) const
|
||||
{
|
||||
tilesX = iTilesX;
|
||||
tilesY = iTilesY;
|
||||
corner = iCorner;
|
||||
}
|
||||
}
|
||||
443
src/tools/Extractor_projects/Movemap-Generator/generator.cpp
Normal file
443
src/tools/Extractor_projects/Movemap-Generator/generator.cpp
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "ace/High_Res_Timer.h"
|
||||
#include "MMapCommon.h"
|
||||
#include "MapBuilder.h"
|
||||
#include "ExtractorCommon.h"
|
||||
|
||||
using namespace MMAP;
|
||||
|
||||
bool checkDirectories(bool debugOutput)
|
||||
{
|
||||
vector<string> dirFiles;
|
||||
|
||||
if (getDirContents(dirFiles, "maps") == LISTFILE_DIRECTORY_NOT_FOUND || !dirFiles.size())
|
||||
{
|
||||
printf(" 'maps' directory is empty or does not exist\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dirFiles.clear();
|
||||
if (getDirContents(dirFiles, "vmaps", "*.vmtree") == LISTFILE_DIRECTORY_NOT_FOUND || !dirFiles.size())
|
||||
{
|
||||
printf(" 'vmaps' directory is empty or does not exist\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dirFiles.clear();
|
||||
if (getDirContents(dirFiles, "mmaps") == LISTFILE_DIRECTORY_NOT_FOUND)
|
||||
{
|
||||
//printf(" 'mmaps' directory does not exist\n");
|
||||
CreateDir(std::string("mmaps"));
|
||||
}
|
||||
|
||||
dirFiles.clear();
|
||||
if (debugOutput)
|
||||
{
|
||||
if (getDirContents(dirFiles, "meshes") == LISTFILE_DIRECTORY_NOT_FOUND)
|
||||
{
|
||||
printf(" 'meshes' directory does not exist (no place to put debugOutput files)\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void printUsage(char* prg)
|
||||
{
|
||||
printf(" Usage: %s [OPTION]\n\n", prg);
|
||||
printf(" Generate movement maps from extracted client maps.\n");
|
||||
printf(" -h, --help show the usage\n");
|
||||
printf(" --threads [#] number of worker threads (default 0).\n");
|
||||
printf(" --maxAngle [#] max walkable inclination angle.\n");
|
||||
printf(" --tile [#,#] build the specified tile.\n");
|
||||
printf(" --skipLiquid [true|false] skip liquid data for maps.\n");
|
||||
printf(" --skipContinents [true|false] skip continents.\n");
|
||||
printf(" --skipJunkMaps [true|false] skip unused junk maps.\n");
|
||||
printf(" --skipBattlegrounds [true|false] skip battleground maps.\n");
|
||||
printf(" --bigBaseUnit [true|false] generate tile/map using bigger basic unit.\n");
|
||||
printf(" --offMeshInput [file.*] path to file containing off mesh.\n");
|
||||
printf(" connections data\n");
|
||||
printf(" --debugOutput [true|false] create debugging files for use with\n");
|
||||
printf(" RecastDemo.\n");
|
||||
printf(" --silent No questions asked.\n");
|
||||
printf(" [#] Build only the map specified by #.\n");
|
||||
printf("\n");
|
||||
printf(" Examples:\n");
|
||||
printf(" - generate all movement maps:\n");
|
||||
printf(" %s\n", prg);
|
||||
printf(" - generate only map 0:\n");
|
||||
printf(" %s 0\n", prg);
|
||||
printf(" - build tile 34,46 of map 0:\n");
|
||||
printf(" %s --tile 34,46\n", prg);
|
||||
}
|
||||
|
||||
bool handleArgs(int argc, char** argv,
|
||||
int& mapnum,
|
||||
int& tileX,
|
||||
int& tileY,
|
||||
float& maxAngle,
|
||||
bool& skipLiquid,
|
||||
bool& skipContinents,
|
||||
bool& skipJunkMaps,
|
||||
bool& skipBattlegrounds,
|
||||
bool& debugOutput,
|
||||
bool& silent,
|
||||
bool& bigBaseUnit,
|
||||
int& num_threads,
|
||||
char*& offMeshInputPath)
|
||||
{
|
||||
char* param = NULL;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "--maxAngle") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float maxangle = atof(param);
|
||||
if (maxangle <= 90.f && maxangle >= 45.f)
|
||||
{
|
||||
maxAngle = maxangle;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--maxAngle', using default\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--threads") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int nThreads = atoi(param);
|
||||
if (nThreads)
|
||||
{
|
||||
num_threads = nThreads;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--threads', using single threaded build\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--tile") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char* stileX = strtok(param, ",");
|
||||
char* stileY = strtok(NULL, ",");
|
||||
int tilex = atoi(stileX);
|
||||
int tiley = atoi(stileY);
|
||||
|
||||
if ((tilex > 0 && tilex < 64) || (tilex == 0 && strcmp(stileX, "0") == 0))
|
||||
{
|
||||
tileX = tilex;
|
||||
}
|
||||
if ((tiley > 0 && tiley < 64) || (tiley == 0 && strcmp(stileY, "0") == 0))
|
||||
{
|
||||
tileY = tiley;
|
||||
}
|
||||
|
||||
if (tileX < 0 || tileY < 0)
|
||||
{
|
||||
printf("invalid tile coords.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--skipLiquid") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(param, "true") == 0)
|
||||
{
|
||||
skipLiquid = true;
|
||||
}
|
||||
else if (strcmp(param, "false") == 0)
|
||||
{
|
||||
skipLiquid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--skipLiquid', using default\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--skipContinents") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(param, "true") == 0)
|
||||
{
|
||||
skipContinents = true;
|
||||
}
|
||||
else if (strcmp(param, "false") == 0)
|
||||
{
|
||||
skipContinents = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--skipContinents', using default\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--skipJunkMaps") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(param, "true") == 0)
|
||||
{
|
||||
skipJunkMaps = true;
|
||||
}
|
||||
else if (strcmp(param, "false") == 0)
|
||||
{
|
||||
skipJunkMaps = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--skipJunkMaps', using default\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--skipBattlegrounds") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(param, "true") == 0)
|
||||
{
|
||||
skipBattlegrounds = true;
|
||||
}
|
||||
else if (strcmp(param, "false") == 0)
|
||||
{
|
||||
skipBattlegrounds = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--skipBattlegrounds', using default\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--debugOutput") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(param, "true") == 0)
|
||||
{
|
||||
debugOutput = true;
|
||||
}
|
||||
else if (strcmp(param, "false") == 0)
|
||||
{
|
||||
debugOutput = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--debugOutput', using default true\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--silent") == 0)
|
||||
{
|
||||
silent = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "--bigBaseUnit") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(param, "true") == 0)
|
||||
{
|
||||
bigBaseUnit = true;
|
||||
}
|
||||
else if (strcmp(param, "false") == 0)
|
||||
{
|
||||
bigBaseUnit = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid option for '--bigBaseUnit', using default false\n");
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "--offMeshInput") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
offMeshInputPath = param;
|
||||
}
|
||||
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
|
||||
{
|
||||
printUsage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int map = atoi(argv[i]);
|
||||
if (map > 0 || (map == 0 && (strcmp(argv[i], "0") == 0)))
|
||||
{
|
||||
mapnum = map;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid map id\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int finish(const char* message, int returnValue)
|
||||
{
|
||||
printf("%s", message);
|
||||
(void)getchar();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char map_magic[16];
|
||||
int thisBuild = getBuildNumber();
|
||||
int iCoreNumber = getCoreNumberFromBuild(thisBuild);
|
||||
showBanner("Movement Map Generator", iCoreNumber);
|
||||
setMapMagicVersion(iCoreNumber, map_magic);
|
||||
showWebsiteBanner();
|
||||
|
||||
int mapnum = -1;
|
||||
float maxAngle = 60.0f;
|
||||
int tileX = -1, tileY = -1;
|
||||
bool skipLiquid = false,
|
||||
skipContinents = false,
|
||||
skipJunkMaps = true,
|
||||
skipBattlegrounds = false,
|
||||
debugOutput = false,
|
||||
silent = false,
|
||||
bigBaseUnit = false;
|
||||
int num_threads = 0;
|
||||
char* offMeshInputPath = NULL;
|
||||
|
||||
bool validParam = handleArgs(argc, argv, mapnum,
|
||||
tileX, tileY, maxAngle,
|
||||
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
|
||||
debugOutput, silent, bigBaseUnit, num_threads, offMeshInputPath);
|
||||
|
||||
if (!validParam)
|
||||
{
|
||||
return silent ? -1 : finish(" You have specified invalid parameters (use -h for more help)", -1);
|
||||
}
|
||||
|
||||
if (mapnum == -1 && debugOutput)
|
||||
{
|
||||
if (silent)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
printf(" You have specifed debug output, but didn't specify a map to generate.\n");
|
||||
printf(" This will generate debug output for ALL maps.\n");
|
||||
printf(" Are you sure you want to continue? (y/n) ");
|
||||
if (getchar() != 'y')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkDirectories(debugOutput))
|
||||
{
|
||||
return silent ? -3 : finish(" Press any key to close...", -3);
|
||||
}
|
||||
|
||||
MapBuilder builder(map_magic, maxAngle, skipLiquid, skipContinents, skipJunkMaps,
|
||||
skipBattlegrounds, debugOutput, bigBaseUnit, offMeshInputPath);
|
||||
|
||||
ACE_Time_Value elapsed;
|
||||
ACE_High_Res_Timer timer;
|
||||
|
||||
timer.start();
|
||||
if (tileX > -1 && tileY > -1 && mapnum >= 0)
|
||||
{
|
||||
builder.buildSingleTile(mapnum, tileX, tileY);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_threads && builder.activate(num_threads)== -1)
|
||||
{
|
||||
if (!silent)
|
||||
{
|
||||
printf(" Thread initialization was not ok. The build is single threaded\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.activated())
|
||||
{
|
||||
printf(" Using %d thread(s) for building\n", num_threads);
|
||||
}
|
||||
|
||||
if (mapnum >= 0)
|
||||
{
|
||||
builder.buildMap(uint32(mapnum), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.buildAllMaps();
|
||||
}
|
||||
}
|
||||
timer.stop();
|
||||
timer.elapsed_time(elapsed);
|
||||
printf(" \n Total build time: %ld seconds\n\n", elapsed.sec());
|
||||
|
||||
return silent ? 1 : finish(" Movemap build is complete! Press enter to exit\n", 1);
|
||||
}
|
||||
11
src/tools/Extractor_projects/README.md
Normal file
11
src/tools/Extractor_projects/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
## Unified Extractor Projects
|
||||
|
||||
The submodule contains the unified Extractors for MaNGOS.
|
||||
|
||||
This initially Supports:-
|
||||
|
||||
* MaNGOS Zero
|
||||
|
||||
* MaNGOS One
|
||||
|
||||
* MaNGOS Two
|
||||
1412
src/tools/Extractor_projects/map-extractor/System.cpp
Normal file
1412
src/tools/Extractor_projects/map-extractor/System.cpp
Normal file
File diff suppressed because it is too large
Load diff
25
src/tools/Extractor_projects/map-extractor/map-extractor.rc
Normal file
25
src/tools/Extractor_projects/map-extractor/map-extractor.rc
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
IDI_APPICON ICON DISCARDABLE "../tools.ico"
|
||||
605
src/tools/Extractor_projects/shared/ExtractorCommon.cpp
Normal file
605
src/tools/Extractor_projects/shared/ExtractorCommon.cpp
Normal file
|
|
@ -0,0 +1,605 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "ExtractorCommon.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
/* This isn't the nicest way to do things..
|
||||
* TODO: Fix this with snprintf instead and check that it still works
|
||||
*/
|
||||
#define sprintf_s sprintf
|
||||
#endif
|
||||
|
||||
#if defined( __GNUC__ )
|
||||
#define _open open
|
||||
#define _close close
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
#else
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef O_LARGEFILE
|
||||
#define OPEN_FLAGS (O_RDONLY | O_BINARY | O_LARGEFILE)
|
||||
#else
|
||||
#define OPEN_FLAGS (O_RDONLY | O_BINARY)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function searches for and opens the WoW exe file, using all known variations on its spelling
|
||||
*
|
||||
* @RETURN pFile the pointer to the file, so that it can be worked on
|
||||
*/
|
||||
FILE* openWoWExe()
|
||||
{
|
||||
FILE *pFile;
|
||||
const char* ExeFileName[] = { "WoW.exe", "Wow.exe", "wow.exe" ,"World of Warcraft.exe", "World of Warcraft.app/Contents/MacOS/World of Warcraft"};
|
||||
int iExeSpelling = 5; ///> WoW.exe (Classic, CATA), Wow.exe (TBC, MoP, WoD), wow.exe (WOTLK) and a variant
|
||||
|
||||
/// loop through all possible file names
|
||||
for (int iFileCount = 0; iFileCount < iExeSpelling; iFileCount++)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (fopen_s(&pFile, ExeFileName[iFileCount], "rb") == 0)
|
||||
return pFile; ///< successfully located the WoW executable
|
||||
#else
|
||||
if ((pFile = fopen(ExeFileName[iFileCount], "rb")))
|
||||
return pFile; ///< successfully located the WoW executable
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0; ///< failed to locate WoW executable
|
||||
}
|
||||
|
||||
/**
|
||||
* This function loads up a binary file (WoW executable), then searches for and returns
|
||||
* the build number of the file. The build number is searched for in hex form.
|
||||
*
|
||||
* @PARAM sFilename is the filename of the WoW executable to be loaded
|
||||
* @RETURN iBuild the build number of the WoW executable, or 0 if failed
|
||||
*/
|
||||
int getBuildNumber()
|
||||
{
|
||||
int iBuild = -1; ///< build version # of the WoW executable (returned value)
|
||||
|
||||
/// buffers used for working on the file's bytes
|
||||
unsigned char byteSearchBuffer[1]; ///< used for reading in a single character, ready to be
|
||||
///< tested for the required text we are searching for: 1, 5, 6, or 8
|
||||
unsigned char jumpBytesBuffer[128]; ///< used for skipping past the bytes from the file's start
|
||||
///< to the base # area, before we start searching for the base #, for faster processing
|
||||
unsigned char preWOTLKbuildNumber[3]; ///< will hold the last 3 digits of the build number
|
||||
unsigned char postTBCbuildNumber[4]; ///< will hold the last 4 digits of the build number
|
||||
|
||||
// These do not include the first digit
|
||||
// as the first digit is used to locate the possible location of the build number
|
||||
// then the following bytes are grabbed, 3 for pre WOTLK, 4 for WOTLK and later.
|
||||
// Those grabbed bytes are then compared with the below variables in order to idenity the exe's build
|
||||
unsigned char vanillaBuild1[3] = { 0x38, 0x37, 0x35 }; // (5)875
|
||||
unsigned char vanillaBuild2[3] = { 0x30, 0x30, 0x35 }; // (6)005
|
||||
unsigned char vanillaBuild3[3] = { 0x31, 0x34, 0x31 }; // (6)141
|
||||
unsigned char tbcBuild[3] = { 0x36, 0x30, 0x36 }; // (8)606
|
||||
unsigned char wotlkBuild[4] = { 0x32, 0x33, 0x34, 0x30 }; // (1)2340
|
||||
unsigned char cataBuild[4] = { 0x35, 0x35, 0x39, 0x35 }; // (1)5595
|
||||
unsigned char mopBuild[4] = { 0x38, 0x34, 0x31, 0x34 }; // (1)8414
|
||||
|
||||
FILE *pFile;
|
||||
if (!(pFile = openWoWExe()))
|
||||
{
|
||||
printf("\nFatal Error: failed to locate the WoW executable!\n\n");
|
||||
printf("\nExiting program!!\n");
|
||||
exit(0); ///> failed to locate exe file
|
||||
}
|
||||
|
||||
/// jump over as much of the file as possible, before we start searching for the base #
|
||||
for (int i = 0; i < 3300; i++)
|
||||
{
|
||||
fread(jumpBytesBuffer, sizeof(jumpBytesBuffer), 1, pFile);
|
||||
}
|
||||
|
||||
/// Search for the build #
|
||||
while (fread(byteSearchBuffer, 1, 1, pFile))
|
||||
{
|
||||
/// we are looking for 1, 5, 6, or 8
|
||||
/// these values are the first digit of the build versions we are interested in
|
||||
|
||||
// Vanilla and TBC
|
||||
if (byteSearchBuffer[0] == 0x35 || byteSearchBuffer[0] == 0x36 || byteSearchBuffer[0] == 0x38)
|
||||
{
|
||||
/// grab the next 4 bytes
|
||||
fread(preWOTLKbuildNumber, sizeof(preWOTLKbuildNumber), 1, pFile);
|
||||
|
||||
if (!memcmp(preWOTLKbuildNumber, vanillaBuild1, sizeof(preWOTLKbuildNumber))) /// build is Vanilla?
|
||||
{
|
||||
return 5875;
|
||||
}
|
||||
else if (!memcmp(preWOTLKbuildNumber, vanillaBuild2, sizeof(preWOTLKbuildNumber))) /// build is Vanilla?
|
||||
{
|
||||
return 6005;
|
||||
}
|
||||
else if (!memcmp(preWOTLKbuildNumber, vanillaBuild3, sizeof(preWOTLKbuildNumber))) /// build is Vanilla?
|
||||
{
|
||||
return 6141;
|
||||
}
|
||||
else if (!memcmp(preWOTLKbuildNumber, tbcBuild, sizeof(preWOTLKbuildNumber))) /// build is TBC?
|
||||
{
|
||||
return 8606;
|
||||
}
|
||||
}
|
||||
|
||||
/// WOTLK, CATA, MoP
|
||||
if (byteSearchBuffer[0] == 0x31)
|
||||
{
|
||||
/// grab the next 4 bytes
|
||||
fread(postTBCbuildNumber, sizeof(postTBCbuildNumber), 1, pFile);
|
||||
|
||||
if (!memcmp(postTBCbuildNumber, wotlkBuild, sizeof(postTBCbuildNumber))) /// build is WOTLK?
|
||||
{
|
||||
return 12340;
|
||||
}
|
||||
else if (!memcmp(postTBCbuildNumber, cataBuild, sizeof(postTBCbuildNumber))) /// build is CATA?
|
||||
{
|
||||
return 15595;
|
||||
}
|
||||
else if (!memcmp(postTBCbuildNumber, mopBuild, sizeof(postTBCbuildNumber))) /// build is MoP?
|
||||
{
|
||||
return 18414;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nFatal Error: failed to identify build version!\n\n");
|
||||
printf("\nSupported build versions:\n");
|
||||
printf("\nVanilla: 5875, 6005, 6141\n");
|
||||
printf("TBC: 8606\n");
|
||||
printf("WOTLK: 12340\n");
|
||||
printf("CATA: 15595\n");
|
||||
printf("MOP: 18414\n");
|
||||
printf("\n\nExiting program!!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function looks up the Core Version based in the found build Number
|
||||
*
|
||||
* @RETURN iCoreNumber the build number of the WoW executable, or -1 if failed
|
||||
*/
|
||||
int getCoreNumber()
|
||||
{
|
||||
return getCoreNumberFromBuild(getBuildNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* This function looks up the Core Version based in the found build Number
|
||||
*
|
||||
* @PARAM iBuildNumber is the build number of the WoW executable
|
||||
* @RETURN iCoreNumber the build number of the WoW executable, or -1 if failed
|
||||
*/
|
||||
int getCoreNumberFromBuild(int iBuildNumber)
|
||||
{
|
||||
switch (iBuildNumber)
|
||||
{
|
||||
case 5875: //CLASSIC
|
||||
case 6005: //CLASSIC
|
||||
case 6141: //CLASSIC
|
||||
return CLIENT_CLASSIC;
|
||||
break;
|
||||
case 8606: //TBC
|
||||
return CLIENT_TBC;
|
||||
break;
|
||||
case 12340: //WOTLK
|
||||
return CLIENT_WOTLK;
|
||||
break;
|
||||
case 15595: //CATA
|
||||
return CLIENT_CATA;
|
||||
break;
|
||||
case 18414: //MOP
|
||||
return CLIENT_MOP;
|
||||
break;
|
||||
case 21355: //WOD
|
||||
return CLIENT_WOD;
|
||||
break;
|
||||
case 20740: //LEGION ALPHA
|
||||
return CLIENT_LEGION;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function displays the standard mangos banner to the console
|
||||
*
|
||||
* @PARAM sTitle is the Title text (directly under the MaNGOS logo)
|
||||
* @PARAM iCoreNumber is the Core Number
|
||||
*/
|
||||
void showBanner(const std::string& sTitle, int iCoreNumber)
|
||||
{
|
||||
printf(
|
||||
" __ __ _ _ ___ ___ ___ \n"
|
||||
" | \\/ |__ _| \\| |/ __|/ _ \\/ __| \n"
|
||||
" | |\\/| / _` | .` | (_ | (_) \\__ \\ \n"
|
||||
" |_| |_\\__,_|_|\\_|\\___|\\___/|___/ \n"
|
||||
" %s for ", sTitle.c_str());
|
||||
|
||||
switch (iCoreNumber)
|
||||
{
|
||||
case CLIENT_CLASSIC:
|
||||
printf("MaNGOSZero\n");
|
||||
break;
|
||||
case CLIENT_TBC:
|
||||
printf("MaNGOSOne\n");
|
||||
break;
|
||||
case CLIENT_WOTLK:
|
||||
printf("MaNGOSTwo\n");
|
||||
break;
|
||||
case CLIENT_CATA:
|
||||
printf("MaNGOSThree\n");
|
||||
break;
|
||||
case CLIENT_MOP:
|
||||
printf("MaNGOSFour\n");
|
||||
break;
|
||||
case CLIENT_WOD:
|
||||
printf("MaNGOSFive\n");
|
||||
break;
|
||||
case CLIENT_LEGION:
|
||||
printf("MaNGOSSix\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown Version\n");
|
||||
break;
|
||||
}
|
||||
printf(" ________________________________________________\n");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function displays the standard mangos help banner to the console
|
||||
*/
|
||||
void showWebsiteBanner()
|
||||
{
|
||||
printf(
|
||||
" ________________________________________________\n\n"
|
||||
" For help and support please visit: \n"
|
||||
" Website / Forum / Wiki: https://getmangos.eu \n"
|
||||
" ________________________________________________\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function returns the .map file 'magic' number based on the core number
|
||||
*
|
||||
* @PARAM iCoreNumber is the Core Number
|
||||
*/
|
||||
void setMapMagicVersion(int iCoreNumber, char* magic)
|
||||
{
|
||||
switch (iCoreNumber)
|
||||
{
|
||||
case CLIENT_CLASSIC:
|
||||
std::strcpy(magic,"z1.5");
|
||||
break;
|
||||
case CLIENT_TBC:
|
||||
std::strcpy(magic,"s1.5");
|
||||
break;
|
||||
case CLIENT_WOTLK:
|
||||
std::strcpy(magic,"v1.5");
|
||||
break;
|
||||
case CLIENT_CATA:
|
||||
std::strcpy(magic,"c1.5");
|
||||
break;
|
||||
case CLIENT_MOP:
|
||||
std::strcpy(magic,"p1.5");
|
||||
break;
|
||||
case CLIENT_WOD:
|
||||
std::strcpy(magic,"w1.5");
|
||||
break;
|
||||
case CLIENT_LEGION:
|
||||
std::strcpy(magic,"l1.5");
|
||||
break;
|
||||
default:
|
||||
std::strcpy(magic,"UNKN");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the .vmap file 'magic' number based on the core number
|
||||
*
|
||||
* @PARAM iCoreNumber is the Core Number
|
||||
*/
|
||||
void setVMapMagicVersion(int iCoreNumber, char* magic)
|
||||
{
|
||||
switch (iCoreNumber)
|
||||
{
|
||||
case CLIENT_CLASSIC:
|
||||
std::strcpy(magic,"VMAPz07");
|
||||
break;
|
||||
case CLIENT_TBC:
|
||||
std::strcpy(magic,"VMAPs07");
|
||||
break;
|
||||
case CLIENT_WOTLK:
|
||||
std::strcpy(magic,"VMAPt07");
|
||||
break;
|
||||
case CLIENT_CATA:
|
||||
std::strcpy(magic,"VMAPc07");
|
||||
break;
|
||||
case CLIENT_MOP:
|
||||
std::strcpy(magic,"VMAPp07");
|
||||
break;
|
||||
case CLIENT_WOD:
|
||||
std::strcpy(magic,"VMAPw07");
|
||||
break;
|
||||
case CLIENT_LEGION:
|
||||
std::strcpy(magic,"VMAPl07");
|
||||
break;
|
||||
default:
|
||||
std::strcpy(magic,"VMAPUNK");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the .mmap file 'magic' number based on the core number
|
||||
*
|
||||
* @PARAM iCoreNumber is the Core Number
|
||||
*/
|
||||
void setMMapMagicVersion(int iCoreNumber, char* magic)
|
||||
{
|
||||
switch (iCoreNumber)
|
||||
{
|
||||
case CLIENT_CLASSIC:
|
||||
std::strcpy(magic, "z06");
|
||||
break;
|
||||
case CLIENT_TBC:
|
||||
std::strcpy(magic, "s06");
|
||||
break;
|
||||
case CLIENT_WOTLK:
|
||||
std::strcpy(magic, "t06");
|
||||
break;
|
||||
case CLIENT_CATA:
|
||||
std::strcpy(magic, "c06");
|
||||
break;
|
||||
case CLIENT_MOP:
|
||||
std::strcpy(magic, "p06");
|
||||
break;
|
||||
case CLIENT_WOD:
|
||||
std::strcpy(magic, "w06");
|
||||
break;
|
||||
case CLIENT_LEGION:
|
||||
std::strcpy(magic, "l06");
|
||||
break;
|
||||
default:
|
||||
std::strcpy(magic, "UNK");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//#define MMAP_VERSION 4
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @Create Folders based on the path provided
|
||||
*
|
||||
* @param sPath
|
||||
*/
|
||||
void CreateDir(const std::string& sPath)
|
||||
{
|
||||
#ifdef WIN32
|
||||
_mkdir(sPath.c_str());
|
||||
#else
|
||||
mkdir(sPath.c_str(), 0777);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @Checks whether the Filename in the client exists
|
||||
*
|
||||
* @param sFileName
|
||||
* @return bool
|
||||
*/
|
||||
bool ClientFileExists(const char* sFileName)
|
||||
{
|
||||
int fp = _open(sFileName, OPEN_FLAGS);
|
||||
if (fp != -1)
|
||||
{
|
||||
_close(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool isTransportMap(int mapID)
|
||||
{
|
||||
switch (mapID)
|
||||
{
|
||||
// transport maps
|
||||
case 582: // Transport: Rut'theran to Auberdine
|
||||
case 584: // Transport: Menethil to Theramore
|
||||
case 586: // Transport: Exodar to Auberdine
|
||||
case 587: // Transport: Feathermoon Ferry - (TBC / WOTLK / CATA / MOP)
|
||||
case 588: // Transport: Menethil to Auberdine - (TBC / WOTLK / CATA / MOP)
|
||||
case 589: // Transport: Orgrimmar to Grom'Gol - (TBC / WOTLK / CATA / MOP)
|
||||
case 590: // Transport: Grom'Gol to Undercity - (TBC / WOTLK / CATA / MOP)
|
||||
case 591: // Transport: Undercity to Orgrimmar - (TBC / WOTLK / CATA / MOP)
|
||||
case 592: // Transport: Borean Tundra Test - (WOTLK / CATA / MOP)
|
||||
case 593: // Transport: Booty Bay to Ratchet - (TBC / WOTLK / CATA / MOP)
|
||||
case 594: // Transport: Howling Fjord Sister Mercy (Quest) - (WOTLK / CATA / MOP)
|
||||
case 596: // Transport: Naglfar - (WOTLK / CATA / MOP)
|
||||
case 610: // Transport: Tirisfal to Vengeance Landing - (WOTLK / CATA / MOP)
|
||||
case 612: // Transport: Menethil to Valgarde - (WOTLK / CATA / MOP)
|
||||
case 613: // Transport: Orgrimmar to Warsong Hold - (WOTLK / CATA / MOP)
|
||||
case 614: // Transport: Stormwind to Valiance Keep - (WOTLK / CATA / MOP)
|
||||
case 620: // Transport: Moa'ki to Unu'pe - (WOTLK / CATA / MOP)
|
||||
case 621: // Transport: Moa'ki to Kamagua - (WOTLK / CATA / MOP)
|
||||
case 622: // Transport: Orgrim's Hammer - (WOTLK / CATA / MOP)
|
||||
case 623: // Transport: The Skybreaker - (WOTLK / CATA / MOP)
|
||||
case 641: // Transport: Alliance Airship BG - (WOTLK / CATA / MOP)
|
||||
case 642: // Transport: HordeAirshipBG - (WOTLK / CATA / MOP)
|
||||
case 647: // Transport: Orgrimmar to Thunder Bluff - (WOTLK / CATA / MOP)
|
||||
case 662: // Transport: Alliance Vashj'ir Ship - (WOTLK / CATA / MOP)
|
||||
case 672: // Transport: The Skybreaker (Icecrown Citadel Raid) - (WOTLK / CATA / MOP)
|
||||
case 673: // Transport: Orgrim's Hammer (Icecrown Citadel Raid) - (WOTLK / CATA / MOP)
|
||||
case 674: // Transport: Ship to Vashj'ir - (WOTLK / CATA / MOP)
|
||||
case 712: // Transport: The Skybreaker (IC Dungeon) - (WOTLK / CATA / MOP)
|
||||
case 713: // Transport: Orgrim's Hammer (IC Dungeon) - (WOTLK / CATA / MOP)
|
||||
case 718: // Transport: The Mighty Wind (Icecrown Citadel Raid) - (WOTLK / CATA / MOP)
|
||||
case 738: // Ship to Vashj'ir (Orgrimmar -> Vashj'ir) - (CATA / MOP)
|
||||
case 739: // Vashj'ir Sub - Horde - (CATA / MOP)
|
||||
case 740: // Vashj'ir Sub - Alliance - (CATA / MOP)
|
||||
case 741: // Twilight Highlands Horde Transport - (CATA / MOP)
|
||||
case 742: // Vashj'ir Sub - Horde - Circling Abyssal Maw - (CATA / MOP)
|
||||
case 743: // Vashj'ir Sub - Alliance circling Abyssal Maw - (CATA / MOP)
|
||||
case 746: // Uldum Phase Oasis - (CATA / MOP)
|
||||
case 747: // Transport: Deepholm Gunship - (CATA / MOP)
|
||||
case 748: // Transport: Onyxia/Nefarian Elevator - (CATA / MOP)
|
||||
case 749: // Transport: Gilneas Moving Gunship - (CATA / MOP)
|
||||
case 750: // Transport: Gilneas Static Gunship - (CATA / MOP)
|
||||
case 762: // Twilight Highlands Zeppelin 1 - (CATA / MOP)
|
||||
case 763: // Twilight Highlands Zeppelin 2 - (CATA / MOP)
|
||||
case 765: // Krazzworks Attack Zeppelin - (CATA / MOP)
|
||||
case 766: // Transport: Gilneas Moving Gunship 02 - (CATA / MOP)
|
||||
case 767: // Transport: Gilneas Moving Gunship 03 - (CATA / MOP)
|
||||
case 1113: // Transport: DarkmoonCarousel - (MOP)
|
||||
case 1132: // Transport218599 - The Skybag (Brawl'gar Arena) - (MOP)
|
||||
case 1133: // Transport218600 - Zandalari Ship (Mogu Island) - (MOP)
|
||||
case 1172: // Transport: Siege of Orgrimmar (Alliance) - (MOP)
|
||||
case 1173: // Transport: Siege of Orgrimmar (Horde) - (MOP)
|
||||
case 1192: // Transport: Iron_Horde_Gorgrond_Train - (WOD)
|
||||
case 1231: // Transport: Wavemurder Barge - (WOD)
|
||||
return true;
|
||||
default: // no transport maps
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool shouldSkipMap(int mapID,bool m_skipContinents, bool m_skipJunkMaps, bool m_skipBattlegrounds)
|
||||
{
|
||||
if (m_skipContinents)
|
||||
switch (mapID)
|
||||
{
|
||||
case 0: // Eastern Kingdoms - (CLASSIC / TBC / WOTLK / CATA / MOP)
|
||||
case 1: // Kalimdor - (CLASSIC - TBC / WOTLK / CATA / MOP)
|
||||
case 530: // Outland - (TBC / WOTLK / CATA / MOP)
|
||||
case 571: // Northrend - (WOTLK / CATA / MOP)
|
||||
case 870: // Pandaria - (MOP)
|
||||
case 1116: // Draenor - (WOD)
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_skipJunkMaps)
|
||||
switch (mapID)
|
||||
{
|
||||
case 13: // test.wdt
|
||||
case 25: // ScottTest.wdt
|
||||
case 29: // Test.wdt
|
||||
case 35: // StornWind Crypt (Unused Instance)
|
||||
case 37: // Ashara.wdt (Unused Raid Area)
|
||||
case 42: // Colin.wdt
|
||||
case 44: // Monastry.wdt (Unused Old SM)
|
||||
case 169: // EmeraldDream.wdt (unused, and very large)
|
||||
case 451: // development.wdt
|
||||
case 573: // ExteriorTest.wdt - (WOTLK / CATA / MOP)
|
||||
case 597: // CraigTest.wdt - (WOTLK / CATA / MOP)
|
||||
case 605: // development_nonweighted.wdt - (WOTLK / CATA / MOP)
|
||||
case 606: // QA_DVD.wdt - (WOTLK / CATA / MOP)
|
||||
case 627: // unused.wdt - (CATA / MOP)
|
||||
case 930: // (UNUSED) Scenario: Alcaz Island - (MOP)
|
||||
case 995: // The Depths [UNUSED] - (MOP)
|
||||
case 1010: // MistsCTF3
|
||||
case 1014: // (UNUSED) Peak of Serenity Scenario - (MOP)
|
||||
case 1028: // (UNUSED) Scenario: Mogu Ruins - (MOP)
|
||||
case 1029: // (UNUSED) Scenario: Mogu Crypt - (MOP)
|
||||
case 1049: // (UNUSED) Scenario: Black Ox Temple - (MOP)
|
||||
case 1060: // Level Design Land - Dev Only - (MOP)
|
||||
case 1181: // PattyMack Test Garrison Bldg Map - (WOD)
|
||||
case 1250: // Alliance - Garrison - Herb Garden 1 (UNUSED) - (WOD)
|
||||
case 1251: // Alliance - Garrison - Inn 1 DONT USE - (WOD)
|
||||
case 1264: // Propland - Dev Only - (WOD)
|
||||
case 1270: // Development Land 3 - (WOD)
|
||||
case 1310: // Expansion 5 QA Model Map - (WOD)
|
||||
case 1407: // GorgrondFinaleScenarioMap(zzzOld) - (WOD)
|
||||
case 1427: // PattyMack Test Garrison Bld Map2 - (WOD)
|
||||
|
||||
return true;
|
||||
default:
|
||||
if (isTransportMap(mapID))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_skipBattlegrounds)
|
||||
switch (mapID)
|
||||
{
|
||||
case 30: // AV
|
||||
case 37: // AC
|
||||
case 489: // WSG
|
||||
case 529: // AB
|
||||
case 566: // EotS - (TBC / WOTLK / CATA / MOP)
|
||||
case 607: // SotA - (WOTLK / CATA / MOP)
|
||||
case 628: // IoC - (WOTLK / CATA / MOP)
|
||||
case 726: // TP - (CATA / MOP)
|
||||
case 727: // SM - (CATA / MOP)
|
||||
case 728: // BfG - (CATA / MOP)
|
||||
case 761: // BfG2 - (CATA / MOP)
|
||||
case 968: // EotS2 - (CATA / MOP)
|
||||
case 998: // VOP - (MOP)
|
||||
case 1010: // CTF3 - (MOP)
|
||||
case 1101: // DOTA - (MOP)
|
||||
case 1105: // GR - (MOP)
|
||||
case 1166: // Small Battleground - (WOD)
|
||||
case 1431: // SparringArenaLevel3Stadium 'The Coliseum' - (WOD)
|
||||
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
57
src/tools/Extractor_projects/shared/ExtractorCommon.h
Normal file
57
src/tools/Extractor_projects/shared/ExtractorCommon.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
FILE* openWoWExe();
|
||||
int getBuildNumber();
|
||||
int getCoreNumber();
|
||||
int getCoreNumberFromBuild(int iBuildNumber);
|
||||
void showBanner(const std::string& title, int iCoreNumber);
|
||||
void showWebsiteBanner();
|
||||
void setMapMagicVersion(int iCoreNumber, char* magic);
|
||||
void setVMapMagicVersion(int iCoreNumber, char* magic);
|
||||
void setMMapMagicVersion(int iCoreNumber, char* magic);
|
||||
void CreateDir(const std::string& sPath);
|
||||
bool ClientFileExists(const char* sFileName);
|
||||
bool isTransportMap(int mapID);
|
||||
bool shouldSkipMap(int mapID, bool m_skipContinents, bool m_skipJunkMaps, bool m_skipBattlegrounds);
|
||||
|
||||
|
||||
static const char *langs[12] = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
|
||||
|
||||
/// Enumerated Core Numbers
|
||||
enum CoreNumber
|
||||
{
|
||||
CLIENT_CLASSIC = 0,
|
||||
CLIENT_TBC = 1,
|
||||
CLIENT_WOTLK = 2,
|
||||
CLIENT_CATA = 3,
|
||||
CLIENT_MOP = 4,
|
||||
CLIENT_WOD = 5,
|
||||
CLIENT_LEGION = 6
|
||||
};
|
||||
165
src/tools/Extractor_projects/shared/dbcfile.cpp
Normal file
165
src/tools/Extractor_projects/shared/dbcfile.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "dbcfile.h"
|
||||
#undef min
|
||||
#undef max
|
||||
#include <ml/mpq.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
DBCFile::DBCFile(const std::string& filename):
|
||||
filename(filename),
|
||||
data(0)
|
||||
{
|
||||
|
||||
}
|
||||
bool DBCFile::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
|
||||
// Need some error checking, otherwise an unhandled exception error occurs
|
||||
// if people screw with the data path.
|
||||
if (f.isEof() == true)
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Could not open DBCFile %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char header[4];
|
||||
unsigned int na, nb, es, ss;
|
||||
|
||||
if (f.read(header, 4) != 4) // Number of records
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Could not read header in DBCFile %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header[0] != 'W' || header[1] != 'D' || header[2] != 'B' || header[3] != 'C')
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("The header in DBCFile %s did not match.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.read(&na, 4) != 4) // Number of records
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Could not read number of records from DBCFile %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.read(&nb, 4) != 4) // Number of fields
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Could not read number of fields from DBCFile %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.read(&es, 4) != 4) // Size of a record
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Could not read record size from DBCFile %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.read(&ss, 4) != 4) // String size
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Could not read string block size from DBCFile %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
recordSize = es;
|
||||
recordCount = na;
|
||||
fieldCount = nb;
|
||||
stringSize = ss;
|
||||
if (fieldCount * 4 != recordSize)
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Field count and record size in DBCFile %s do not match.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
data = new unsigned char[recordSize * recordCount + stringSize];
|
||||
stringTable = data + recordSize * recordCount;
|
||||
|
||||
size_t data_size = recordSize * recordCount + stringSize;
|
||||
if (f.read(data, data_size) != data_size)
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("DBCFile %s did not contain expected amount of data for records.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
DBCFile::~DBCFile()
|
||||
{
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
DBCFile::Record DBCFile::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id * recordSize);
|
||||
}
|
||||
|
||||
size_t DBCFile::getMaxId()
|
||||
{
|
||||
assert(data);
|
||||
|
||||
size_t maxId = 0;
|
||||
for (size_t i = 0; i < getRecordCount(); ++i)
|
||||
{
|
||||
if (maxId < getRecord(i).getUInt(0))
|
||||
{
|
||||
maxId = getRecord(i).getUInt(0);
|
||||
}
|
||||
}
|
||||
return maxId;
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::begin()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, data);
|
||||
}
|
||||
DBCFile::Iterator DBCFile::end()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, stringTable);
|
||||
}
|
||||
303
src/tools/Extractor_projects/shared/dbcfile.h
Normal file
303
src/tools/Extractor_projects/shared/dbcfile.h
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef DBCFILE_H
|
||||
#define DBCFILE_H
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param filename
|
||||
*/
|
||||
DBCFile(const std::string& filename);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~DBCFile();
|
||||
|
||||
/**
|
||||
* @brief Open database. It must be openened before it can be used.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool open();
|
||||
|
||||
/**
|
||||
* @brief Database exceptions
|
||||
*
|
||||
*/
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
Exception(const std::string& message): message(message)
|
||||
{ }
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
virtual ~Exception()
|
||||
{ }
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return const std::string
|
||||
*/
|
||||
const std::string& getMessage() {return message;}
|
||||
private:
|
||||
std::string message; /**< TODO */
|
||||
};
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class NotFound: public Exception
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
NotFound(): Exception("Key was not found")
|
||||
{ }
|
||||
};
|
||||
class Iterator;
|
||||
/**
|
||||
* @brief Iteration over database
|
||||
*
|
||||
*/
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param r
|
||||
* @return Record &operator
|
||||
*/
|
||||
Record& operator= (const Record& r)
|
||||
{
|
||||
file = r.file;
|
||||
offset = r.offset;
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param field
|
||||
* @return float
|
||||
*/
|
||||
float getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset + (field * 4));
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param field
|
||||
* @return unsigned int
|
||||
*/
|
||||
unsigned int getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset + (field * 4));
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param field
|
||||
* @return int
|
||||
*/
|
||||
int getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset + (field * 4));
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ofs
|
||||
* @return unsigned char
|
||||
*/
|
||||
unsigned char getByte(size_t ofs) const
|
||||
{
|
||||
assert(ofs < file.recordSize);
|
||||
return *reinterpret_cast<unsigned char*>(offset + ofs);
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param field
|
||||
* @return const char
|
||||
*/
|
||||
const char* getString(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field);
|
||||
assert(stringOffset < file.stringSize);
|
||||
return reinterpret_cast<char*>(file.stringTable + stringOffset);
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param offset
|
||||
*/
|
||||
Record(DBCFile& file, unsigned char* offset): file(file), offset(offset) {}
|
||||
DBCFile& file; /**< TODO */
|
||||
unsigned char* offset; /**< TODO */
|
||||
|
||||
friend class DBCFile;
|
||||
friend class DBCFile::Iterator;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Iterator that iterates over records
|
||||
*
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file
|
||||
* @param offset
|
||||
*/
|
||||
Iterator(DBCFile& file, unsigned char* offset):
|
||||
record(file, offset) {}
|
||||
/**
|
||||
* @brief Advance (prefix only)
|
||||
*
|
||||
* @return Iterator &operator
|
||||
*/
|
||||
Iterator& operator++()
|
||||
{
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* @brief Return address of current instance
|
||||
*
|
||||
* @return const Record &operator
|
||||
*/
|
||||
Record const& operator*() const { return record; }
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return const Record *operator ->
|
||||
*/
|
||||
const Record* operator->() const
|
||||
{
|
||||
return &record;
|
||||
}
|
||||
/**
|
||||
* @brief Comparison
|
||||
*
|
||||
* @param b
|
||||
* @return bool operator
|
||||
*/
|
||||
bool operator==(const Iterator& b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param b
|
||||
* @return bool operator
|
||||
*/
|
||||
bool operator!=(const Iterator& b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get record by id
|
||||
*
|
||||
* @param id
|
||||
* @return Record
|
||||
*/
|
||||
Record getRecord(size_t id);
|
||||
/**
|
||||
* @brief Get begin iterator over records
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
Iterator begin();
|
||||
/**
|
||||
* @brief Get begin iterator over records
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
Iterator end();
|
||||
/**
|
||||
* @brief Trivial
|
||||
*
|
||||
* @return size_t
|
||||
*/
|
||||
size_t getRecordCount() const { return recordCount;}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return size_t
|
||||
*/
|
||||
size_t getFieldCount() const { return fieldCount; }
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return size_t
|
||||
*/
|
||||
size_t getMaxId();
|
||||
private:
|
||||
std::string filename; /**< TODO */
|
||||
size_t recordSize; /**< TODO */
|
||||
size_t recordCount; /**< TODO */
|
||||
size_t fieldCount; /**< TODO */
|
||||
size_t stringSize; /**< TODO */
|
||||
unsigned char* data; /**< TODO */
|
||||
unsigned char* stringTable; /**< TODO */
|
||||
};
|
||||
|
||||
#endif
|
||||
BIN
src/tools/Extractor_projects/tools.ico
Normal file
BIN
src/tools/Extractor_projects/tools.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
40
src/tools/Extractor_projects/vmap-extractor/README.md
Normal file
40
src/tools/Extractor_projects/vmap-extractor/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
vmap extractor
|
||||
--------------
|
||||
The *vmap extractor* will extract model information from the game client.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
You will need a working installation of the [World of Warcraft][1] client patched
|
||||
to version 1.12.x.
|
||||
|
||||
Instructions - Linux
|
||||
--------------------
|
||||
Use the created executable to extract model information. Change the data path if
|
||||
needed.
|
||||
|
||||
$ vmap-extractor -d /mnt/windows/games/world of warcraft/
|
||||
|
||||
Resulting files will be in `./Buildings`.
|
||||
|
||||
Instructions - Windows
|
||||
----------------------
|
||||
Use the created executable (from command prompt) to extract model information.
|
||||
It should find the data path for your client installation through the Windows
|
||||
registry, but the data path can be specified with the -d option.
|
||||
|
||||
Resulting files will be in `.\Buildings`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
The *vmap extractor* can be used with a few parameters to customize input, output
|
||||
and generated output.
|
||||
|
||||
* `-d PATH`, `--data PATH`: set the path for reading the client's MPQ archives to the given
|
||||
path.
|
||||
* `-s`, `--small`: small size (data size optimization), ~500MB less vmap data. This is the
|
||||
default setting.
|
||||
* `-l`, `--large`: large size, ~500MB more vmap data. Stores additional details in vmap data.
|
||||
* `-h`, `--help`: display the usage message, and an example call.
|
||||
|
||||
|
||||
[1]: http://blizzard.com/games/wow/ "World of Warcraft"
|
||||
161
src/tools/Extractor_projects/vmap-extractor/adtfile.cpp
Normal file
161
src/tools/Extractor_projects/vmap-extractor/adtfile.cpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include "vmapexport.h"
|
||||
#include "adtfile.h"
|
||||
|
||||
ADTFile::ADTFile(char* filename): ADT(filename)
|
||||
{
|
||||
AdtFilename.assign(filename);
|
||||
}
|
||||
|
||||
bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, StringSet& failedPaths,int iCoreNumber, const void *szRawVMAPMagic)
|
||||
{
|
||||
if (ADT.isEof())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 size;
|
||||
|
||||
std::string xMap;
|
||||
std::string yMap;
|
||||
|
||||
AdtFilename.erase(AdtFilename.find(".adt"), 4);
|
||||
std::string TempMapNumber;
|
||||
|
||||
TempMapNumber = AdtFilename.substr(AdtFilename.length() - 6, 6);
|
||||
xMap = TempMapNumber.substr(TempMapNumber.find("_") + 1, (TempMapNumber.find_last_of("_") - 1) - (TempMapNumber.find("_")));
|
||||
yMap = TempMapNumber.substr(TempMapNumber.find_last_of("_") + 1, (TempMapNumber.length()) - (TempMapNumber.find_last_of("_")));
|
||||
AdtFilename.erase((AdtFilename.length() - xMap.length() - yMap.length() - 2), (xMap.length() + yMap.length() + 2));
|
||||
|
||||
std::string AdtMapNumber = xMap + ' ' + yMap + ' ' + GetUniformName(AdtFilename);
|
||||
|
||||
std::string dirname = std::string(szWorkDirWmo) + "/dir_bin";
|
||||
FILE* dirfile;
|
||||
dirfile = fopen(dirname.c_str(), "ab");
|
||||
if (!dirfile)
|
||||
{
|
||||
printf("Can't open dirfile!'%s'\n", dirname.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!ADT.isEof())
|
||||
{
|
||||
char fourcc[5];
|
||||
ADT.read(&fourcc, 4);
|
||||
ADT.read(&size, 4);
|
||||
flipcc(fourcc);
|
||||
fourcc[4] = 0;
|
||||
|
||||
size_t nextpos = ADT.getPos() + size;
|
||||
|
||||
if (!strcmp(fourcc, "MCIN"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc, "MTEX"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc, "MMDX"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
char* buf = new char[size];
|
||||
ADT.read(buf, size);
|
||||
char* p = buf;
|
||||
int t = 0;
|
||||
ModelInstansName = new std::string[size];
|
||||
while (p < buf + size)
|
||||
{
|
||||
std::string path(p); // Store copy after name fixed
|
||||
std::string uName;
|
||||
ExtractSingleModel(path, uName, failedPaths, iCoreNumber, szRawVMAPMagic);
|
||||
ModelInstansName[t++] = uName;
|
||||
p = p + strlen(p) + 1;
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc, "MWMO"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
char* buf = new char[size];
|
||||
ADT.read(buf, size);
|
||||
char* p = buf;
|
||||
int q = 0;
|
||||
WmoInstansName = new std::string[size];
|
||||
while (p < buf + size)
|
||||
{
|
||||
std::string path(p);
|
||||
WmoInstansName[q++] = GetUniformName(path);
|
||||
p = p + strlen(p) + 1;
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
//======================
|
||||
else if (!strcmp(fourcc, "MDDF"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
nMDX = (int)size / 36;
|
||||
for (int i = 0; i < nMDX; ++i)
|
||||
{
|
||||
uint32 id;
|
||||
ADT.read(&id, 4);
|
||||
ModelInstance inst(ADT, ModelInstansName[id], map_num, tileX, tileY, dirfile, iCoreNumber);
|
||||
}
|
||||
delete[] ModelInstansName;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc, "MODF"))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
nWMO = (int)size / 64;
|
||||
for (int i = 0; i < nWMO; ++i)
|
||||
{
|
||||
uint32 id;
|
||||
ADT.read(&id, 4);
|
||||
WMOInstance inst(ADT, WmoInstansName[id], map_num, tileX, tileY, dirfile);
|
||||
}
|
||||
delete[] WmoInstansName;
|
||||
}
|
||||
}
|
||||
//======================
|
||||
ADT.seek(nextpos);
|
||||
}
|
||||
ADT.close();
|
||||
fclose(dirfile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ADTFile::~ADTFile()
|
||||
{
|
||||
ADT.close();
|
||||
}
|
||||
179
src/tools/Extractor_projects/vmap-extractor/adtfile.h
Normal file
179
src/tools/Extractor_projects/vmap-extractor/adtfile.h
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
|
||||
#include <ml/mpq.h>
|
||||
#include "wmo.h"
|
||||
#include "vmapexport.h"
|
||||
#include "model.h"
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
#define UNITSIZE (CHUNKSIZE / 8.0f)
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float x; /**< TODO */
|
||||
float y; /**< TODO */
|
||||
float z; /**< TODO */
|
||||
} svec;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct vec
|
||||
{
|
||||
double x; /**< TODO */
|
||||
double y; /**< TODO */
|
||||
double z; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct triangle
|
||||
{
|
||||
vec v[3]; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float v9[16 * 8 + 1][16 * 8 + 1]; /**< TODO */
|
||||
float v8[16 * 8][16 * 8]; /**< TODO */
|
||||
} Cell;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
double v9[9][9]; /**< TODO */
|
||||
double v8[8][8]; /**< TODO */
|
||||
uint16 area_id; /**< TODO */
|
||||
//Liquid *lq;
|
||||
float waterlevel[9][9]; /**< TODO */
|
||||
uint8 flag; /**< TODO */
|
||||
} chunk;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
chunk ch[16][16]; /**< TODO */
|
||||
} mcell;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct MapChunkHeader
|
||||
{
|
||||
uint32 flags; /**< TODO */
|
||||
uint32 ix; /**< TODO */
|
||||
uint32 iy; /**< TODO */
|
||||
uint32 nLayers; /**< TODO */
|
||||
uint32 nDoodadRefs; /**< TODO */
|
||||
uint32 ofsHeight; /**< TODO */
|
||||
uint32 ofsNormal; /**< TODO */
|
||||
uint32 ofsLayer; /**< TODO */
|
||||
uint32 ofsRefs; /**< TODO */
|
||||
uint32 ofsAlpha; /**< TODO */
|
||||
uint32 sizeAlpha; /**< TODO */
|
||||
uint32 ofsShadow; /**< TODO */
|
||||
uint32 sizeShadow; /**< TODO */
|
||||
uint32 areaid; /**< TODO */
|
||||
uint32 nMapObjRefs; /**< TODO */
|
||||
uint32 holes; /**< TODO */
|
||||
uint16 s1; /**< TODO */
|
||||
uint16 s2; /**< TODO */
|
||||
uint32 d1; /**< TODO */
|
||||
uint32 d2; /**< TODO */
|
||||
uint32 d3; /**< TODO */
|
||||
uint32 predTex; /**< TODO */
|
||||
uint32 nEffectDoodad; /**< TODO */
|
||||
uint32 ofsSndEmitters; /**< TODO */
|
||||
uint32 nSndEmitters; /**< TODO */
|
||||
uint32 ofsLiquid; /**< TODO */
|
||||
uint32 sizeLiquid; /**< TODO */
|
||||
float zpos; /**< TODO */
|
||||
float xpos; /**< TODO */
|
||||
float ypos; /**< TODO */
|
||||
uint32 textureId; /**< TODO */
|
||||
uint32 props; /**< TODO */
|
||||
uint32 effectId; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class ADTFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param filename
|
||||
*/
|
||||
ADTFile(char* filename);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~ADTFile();
|
||||
int nWMO; /**< TODO */
|
||||
int nMDX; /**< TODO */
|
||||
string* WmoInstansName; /**< TODO */
|
||||
string* ModelInstansName; /**< TODO */
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param map_num
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param failedPaths
|
||||
* @return bool
|
||||
*/
|
||||
bool init(uint32 map_num, uint32 tileX, uint32 tileY, StringSet& failedPaths,int iCoreNumber, const void *szRawVMAPMagic);
|
||||
private:
|
||||
MPQFile ADT; /**< TODO */
|
||||
string AdtFilename; /**< TODO */
|
||||
};
|
||||
|
||||
#endif
|
||||
40
src/tools/Extractor_projects/vmap-extractor/assembler.cpp
Normal file
40
src/tools/Extractor_projects/vmap-extractor/assembler.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "TileAssembler.h"
|
||||
#include <string>
|
||||
|
||||
bool AssembleVMAP(std::string src, std::string dest, const char* szMagic)
|
||||
{
|
||||
bool success = true;
|
||||
VMAP::TileAssembler* ta = new VMAP::TileAssembler(src, dest);
|
||||
|
||||
if (!ta->convertWorld2(szMagic))
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
delete ta;
|
||||
return success;
|
||||
}
|
||||
348
src/tools/Extractor_projects/vmap-extractor/model.cpp
Normal file
348
src/tools/Extractor_projects/vmap-extractor/model.cpp
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
#include <ml/mpq.h>
|
||||
#include "model.h"
|
||||
#include "wmo.h"
|
||||
#include "dbcfile.h"
|
||||
#include "vmapexport.h"
|
||||
#include <ExtractorCommon.h>
|
||||
|
||||
Model::Model(std::string& filename) : filename(filename), vertices(0), indices(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool Model::open(StringSet& failedPaths, int iCoreNumber)
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
|
||||
ok = !f.isEof();
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
f.close();
|
||||
failedPaths.insert(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
_unload();
|
||||
|
||||
bool bBoundingTriangles = false;
|
||||
uint32 uofsBoundingVertices = 0;
|
||||
uint32 uofsBoundingTriangles = 0;
|
||||
uint32 unBoundingVertices = 0;
|
||||
uint32 unBoundingTriangles = 0;
|
||||
|
||||
|
||||
if (iCoreNumber == CLIENT_CLASSIC || iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
memcpy(&headerClassicTBC, f.getBuffer(), sizeof(ModelHeaderClassicTBC));
|
||||
if (headerClassicTBC.nBoundingTriangles > 0)
|
||||
{
|
||||
bBoundingTriangles = true;
|
||||
uofsBoundingVertices = headerClassicTBC.ofsBoundingVertices;
|
||||
uofsBoundingTriangles = headerClassicTBC.ofsBoundingTriangles;
|
||||
unBoundingVertices = headerClassicTBC.nBoundingVertices;
|
||||
unBoundingTriangles = headerClassicTBC.nBoundingTriangles;
|
||||
}
|
||||
}
|
||||
if (iCoreNumber == CLIENT_WOTLK || iCoreNumber == CLIENT_CATA)
|
||||
{
|
||||
memcpy(&headerOthers, f.getBuffer(), sizeof(ModelHeaderOthers));
|
||||
if (headerOthers.nBoundingTriangles > 0)
|
||||
{
|
||||
bBoundingTriangles = true;
|
||||
uofsBoundingVertices = headerOthers.ofsBoundingVertices;
|
||||
uofsBoundingTriangles = headerOthers.ofsBoundingTriangles;
|
||||
unBoundingVertices = headerOthers.nBoundingVertices;
|
||||
unBoundingTriangles = headerOthers.nBoundingTriangles;
|
||||
}
|
||||
}
|
||||
if (bBoundingTriangles)
|
||||
{
|
||||
boundingVertices = (ModelBoundingVertex*)(f.getBuffer() + uofsBoundingVertices);
|
||||
vertices = new Vec3D[unBoundingVertices];
|
||||
|
||||
for (size_t i = 0; i < unBoundingVertices; i++)
|
||||
{
|
||||
vertices[i] = boundingVertices[i].pos;
|
||||
}
|
||||
|
||||
uint16* triangles = (uint16*)(f.getBuffer() + uofsBoundingTriangles);
|
||||
|
||||
nIndices = unBoundingTriangles; // refers to the number of int16's, not the number of triangles
|
||||
indices = new uint16[nIndices];
|
||||
memcpy(indices, triangles, nIndices * 2);
|
||||
|
||||
f.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("not included %s\n", filename.c_str());
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Model::ConvertToVMAPModel(std::string& outfilename,int iCoreNumber, const void *szRawVMAPMagic)
|
||||
{
|
||||
int N[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
FILE* output = fopen(outfilename.c_str(), "wb");
|
||||
if (!output)
|
||||
{
|
||||
printf("Can't create the output file '%s'\n", outfilename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
fwrite(szRawVMAPMagic, 8, 1, output);
|
||||
uint32 nVertices = 0;
|
||||
if (iCoreNumber == CLIENT_CLASSIC || iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
nVertices = headerClassicTBC.nBoundingVertices;
|
||||
}
|
||||
if (iCoreNumber == CLIENT_WOTLK || iCoreNumber == CLIENT_CATA)
|
||||
{
|
||||
nVertices = headerOthers.nBoundingVertices;
|
||||
}
|
||||
|
||||
fwrite(&nVertices, sizeof(int), 1, output);
|
||||
uint32 nofgroups = 1;
|
||||
fwrite(&nofgroups, sizeof(uint32), 1, output);
|
||||
fwrite(N, 4 * 3, 1, output); // rootwmoid, flags, groupid
|
||||
fwrite(N, sizeof(float), 3 * 2, output); //bbox, only needed for WMO currently
|
||||
fwrite(N, 4, 1, output); // liquidflags
|
||||
fwrite("GRP ", 4, 1, output);
|
||||
uint32 branches = 1;
|
||||
int wsize;
|
||||
wsize = sizeof(branches) + sizeof(uint32) * branches;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&branches, sizeof(branches), 1, output);
|
||||
uint32 nIndexes = (uint32) nIndices;
|
||||
fwrite(&nIndexes, sizeof(uint32), 1, output);
|
||||
fwrite("INDX", 4, 1, output);
|
||||
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&nIndexes, sizeof(uint32), 1, output);
|
||||
if (nIndexes > 0)
|
||||
{
|
||||
for (uint32 i = 0; i < nIndices; ++i)
|
||||
{
|
||||
// index[0] -> x, index[1] -> y, index[2] -> z, index[3] -> x ...
|
||||
if ((i % 3) - 1 == 0)
|
||||
{
|
||||
uint16 tmp = indices[i];
|
||||
indices[i] = indices[i+1];
|
||||
indices[i+1] = tmp;
|
||||
}
|
||||
}
|
||||
fwrite(indices, sizeof(unsigned short), nIndexes, output);
|
||||
}
|
||||
fwrite("VERT", 4, 1, output);
|
||||
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&nVertices, sizeof(int), 1, output);
|
||||
if (nVertices > 0)
|
||||
{
|
||||
fwrite(vertices, sizeof(float) * 3, nVertices, output);
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ModelInstance::ModelInstance(MPQFile& f, string& ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile, int coreNumber)
|
||||
{
|
||||
float ff[3];
|
||||
f.read(&id, 4);
|
||||
f.read(ff, 12);
|
||||
pos = fixCoords(Vec3D(ff[0], ff[1], ff[2]));
|
||||
f.read(ff, 12);
|
||||
rot = Vec3D(ff[0], ff[1], ff[2]);
|
||||
if (coreNumber == CLIENT_TBC || coreNumber == CLIENT_WOTLK)
|
||||
{
|
||||
uint16 fFlags; // dummy var
|
||||
f.read(&scaleOthers, 2);
|
||||
f.read(&fFlags, 2); // unknown but flag 1 is used for biodome in Outland, currently this value is not used
|
||||
sc = scaleOthers / 1024.0f; // scale factor - divide by 1024. why not just use a float?
|
||||
}
|
||||
if (coreNumber == CLIENT_CLASSIC)
|
||||
{
|
||||
f.read(&scaleZeroOnly,4); // The above three lines introduced a regression bug in Mangos Zero, is Fine for other cores.
|
||||
sc = scaleZeroOnly / 1024.0f; // scale factor - divide by 1024. why not just use a float?
|
||||
}
|
||||
|
||||
char tempname[512];
|
||||
sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName.c_str());
|
||||
FILE* input;
|
||||
input = fopen(tempname, "r+b");
|
||||
|
||||
if (!input)
|
||||
{
|
||||
//printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(input, 8, SEEK_SET); // get the correct no of vertices
|
||||
int nVertices;
|
||||
size_t file_read = fread(&nVertices, sizeof(int), 1, input);
|
||||
fclose(input);
|
||||
|
||||
if (nVertices == 0 || file_read <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint16 adtId = 0;// not used for models
|
||||
uint32 flags = MOD_M2;
|
||||
if (tileX == 65 && tileY == 65)
|
||||
{
|
||||
flags |= MOD_WORLDSPAWN;
|
||||
}
|
||||
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&flags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&id, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&pos, sizeof(float), 3, pDirfile);
|
||||
fwrite(&rot, sizeof(float), 3, pDirfile);
|
||||
fwrite(&sc, sizeof(float), 1, pDirfile);
|
||||
uint32 nlen = ModelInstName.length();
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(ModelInstName.c_str(), sizeof(char), nlen, pDirfile);
|
||||
|
||||
}
|
||||
|
||||
bool ExtractSingleModel(std::string& origPath, std::string& fixedName, StringSet& failedPaths, int iCoreNumber, const void *szRawVMAPMagic)
|
||||
{
|
||||
string ext = GetExtension(origPath);
|
||||
|
||||
// < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file
|
||||
if ((ext == "mdx") || (ext=="mdl"))
|
||||
{
|
||||
// replace .md[l,x] -> .m2
|
||||
origPath.erase(origPath.length() - 2, 2);
|
||||
origPath.append("2");
|
||||
}
|
||||
// >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file
|
||||
// nothing do
|
||||
|
||||
fixedName = GetUniformName(origPath);
|
||||
std::string output(szWorkDirWmo); // Stores output filename
|
||||
output += "/";
|
||||
output += fixedName;
|
||||
|
||||
if (FileExists(output.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Model mdl(origPath); // Possible changed fname
|
||||
if (!mdl.open(failedPaths, iCoreNumber))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mdl.ConvertToVMAPModel(output, iCoreNumber, szRawVMAPMagic);
|
||||
}
|
||||
|
||||
void ExtractGameobjectModels(int iCoreNumber, const void *szRawVMAPMagic)
|
||||
{
|
||||
printf("\n");
|
||||
printf("Extracting GameObject models...\n");
|
||||
DBCFile dbc("DBFilesClient\\GameObjectDisplayInfo.dbc");
|
||||
if (!dbc.open())
|
||||
{
|
||||
printf("Fatal error: Invalid GameObjectDisplayInfo.dbc file format!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::string basepath = szWorkDirWmo;
|
||||
basepath += "/";
|
||||
std::string path;
|
||||
StringSet failedPaths;
|
||||
|
||||
FILE* model_list = fopen((basepath + "temp_gameobject_models").c_str(), "wb");
|
||||
|
||||
for (DBCFile::Iterator it = dbc.begin(); it != dbc.end(); ++it)
|
||||
{
|
||||
path = it->getString(1);
|
||||
|
||||
if (path.length() < 4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string name;
|
||||
|
||||
string ch_ext = GetExtension(path);
|
||||
if (ch_ext.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (ch_ext == "wmo")
|
||||
{
|
||||
name = GetUniformName(path);
|
||||
result = ExtractSingleWmo(path, iCoreNumber, szRawVMAPMagic);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ExtractSingleModel(path, name, failedPaths, iCoreNumber, szRawVMAPMagic);
|
||||
}
|
||||
|
||||
if (result && FileExists((basepath + name).c_str()))
|
||||
{
|
||||
uint32 displayId = it->getUInt(0);
|
||||
uint32 path_length = name.length();
|
||||
fwrite(&displayId, sizeof(uint32), 1, model_list);
|
||||
fwrite(&path_length, sizeof(uint32), 1, model_list);
|
||||
fwrite(name.c_str(), sizeof(char), path_length, model_list);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(model_list);
|
||||
|
||||
if (!failedPaths.empty())
|
||||
{
|
||||
printf("\n Warning: Some models could not be extracted, see below\n");
|
||||
for (StringSet::const_iterator itr = failedPaths.begin(); itr != failedPaths.end(); ++itr)
|
||||
{
|
||||
printf(" Could not find file of model %s\n", itr->c_str());
|
||||
}
|
||||
printf("\n A few of these warnings are expected to happen, so be not alarmed!\n");
|
||||
}
|
||||
|
||||
printf("\n Asset Extraction Complete !\n");
|
||||
}
|
||||
144
src/tools/Extractor_projects/vmap-extractor/model.h
Normal file
144
src/tools/Extractor_projects/vmap-extractor/model.h
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include <vector>
|
||||
#include <ml/loadlib.h>
|
||||
#include "vec3d.h"
|
||||
#include "modelheaders.h"
|
||||
#include "wmo.h"
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
ModelHeaderClassicTBC headerClassicTBC; /**< TODO */
|
||||
ModelHeaderOthers headerOthers; /**< TODO */
|
||||
ModelBoundingVertex* boundingVertices; /**< TODO */
|
||||
Vec3D* vertices; /**< TODO */
|
||||
uint16* indices; /**< TODO */
|
||||
size_t nIndices; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param failedPaths
|
||||
* @return bool
|
||||
*/
|
||||
bool open(std::set<std::string>& failedPaths, int iCoreNumber);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param outfilename
|
||||
* @return bool
|
||||
*/
|
||||
bool ConvertToVMAPModel(std::string& outfilename, int iCoreNumber, const void *szRawVMAPMagic);
|
||||
|
||||
bool ok; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param filename
|
||||
*/
|
||||
Model(std::string& filename);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~Model() {_unload();}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void _unload()
|
||||
{
|
||||
delete[] vertices;
|
||||
delete[] indices;
|
||||
vertices = NULL;
|
||||
indices = NULL;
|
||||
}
|
||||
std::string filename; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class ModelInstance
|
||||
{
|
||||
public:
|
||||
Model* model; /**< TODO */
|
||||
|
||||
uint32 id; /**< TODO */
|
||||
Vec3D pos, rot; /**< TODO */
|
||||
unsigned int d1;
|
||||
float w, sc;
|
||||
unsigned int scaleZeroOnly;
|
||||
//unsigned int scale; // This line introduced a regression bug in Mangos Zero, is Fine for other cores.
|
||||
uint16 scaleOthers;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
ModelInstance() {}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param f
|
||||
* @param ModelInstName
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param pDirfile
|
||||
*/
|
||||
ModelInstance(MPQFile& f, std::string& ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile, int iCoreNumber);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param origPath original path of the model, cleaned with fixnamen and fixname2
|
||||
* @param fixedName will store the translated name (if changed)
|
||||
* @param failedPaths Set to collect errors
|
||||
* @return bool
|
||||
*/
|
||||
bool ExtractSingleModel(std::string& origPath, std::string& fixedName, std::set<std::string>& failedPaths, int iCoreNumber, const void *szRawVMAPMagic);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
void ExtractGameobjectModels(int iCoreNumber, const void *szRawVMAPMagic);
|
||||
|
||||
#endif
|
||||
187
src/tools/Extractor_projects/vmap-extractor/modelheaders.h
Normal file
187
src/tools/Extractor_projects/vmap-extractor/modelheaders.h
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef MODELHEADERS_H
|
||||
#define MODELHEADERS_H
|
||||
|
||||
/* typedef unsigned char uint8;
|
||||
typedef char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32; */
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct ModelHeaderClassicTBC
|
||||
{
|
||||
char id[4]; /**< TODO */
|
||||
uint8 version[4]; /**< TODO */
|
||||
uint32 nameLength; /**< TODO */
|
||||
uint32 nameOfs; /**< TODO */
|
||||
uint32 type; /**< TODO */
|
||||
uint32 nGlobalSequences; /**< TODO */
|
||||
uint32 ofsGlobalSequences; /**< TODO */
|
||||
uint32 nAnimations; /**< TODO */
|
||||
uint32 ofsAnimations; /**< TODO */
|
||||
uint32 nAnimationLookup; /**< TODO */
|
||||
uint32 ofsAnimationLookup; /**< TODO */
|
||||
uint32 nD; /**< TODO */
|
||||
uint32 ofsD; /**< TODO */
|
||||
uint32 nBones; /**< TODO */
|
||||
uint32 ofsBones; /**< TODO */
|
||||
uint32 nKeyBoneLookup; /**< TODO */
|
||||
uint32 ofsKeyBoneLookup; /**< TODO */
|
||||
uint32 nVertices; /**< TODO */
|
||||
uint32 ofsVertices; /**< TODO */
|
||||
uint32 nViews; /**< TODO */
|
||||
uint32 ofsViews; /**< TODO */
|
||||
uint32 nColors; /**< TODO */
|
||||
uint32 ofsColors; /**< TODO */
|
||||
uint32 nTextures; /**< TODO */
|
||||
uint32 ofsTextures; /**< TODO */
|
||||
uint32 nTransparency; /**< TODO */
|
||||
uint32 ofsTransparency; /**< TODO */
|
||||
uint32 nI; /**< TODO */
|
||||
uint32 ofsI; /**< TODO */
|
||||
uint32 nTextureanimations; /**< TODO */
|
||||
uint32 ofsTextureanimations; /**< TODO */
|
||||
uint32 nTexReplace; /**< TODO */
|
||||
uint32 ofsTexReplace; /**< TODO */
|
||||
uint32 nRenderFlags; /**< TODO */
|
||||
uint32 ofsRenderFlags; /**< TODO */
|
||||
uint32 nBoneLookupTable; /**< TODO */
|
||||
uint32 ofsBoneLookupTable; /**< TODO */
|
||||
uint32 nTexLookup; /**< TODO */
|
||||
uint32 ofsTexLookup; /**< TODO */
|
||||
uint32 nTexUnits; /**< TODO */
|
||||
uint32 ofsTexUnits; /**< TODO */
|
||||
uint32 nTransLookup; /**< TODO */
|
||||
uint32 ofsTransLookup; /**< TODO */
|
||||
uint32 nTexAnimLookup; /**< TODO */
|
||||
uint32 ofsTexAnimLookup; /**< TODO */
|
||||
float floats[14]; /**< TODO */
|
||||
uint32 nBoundingTriangles; /**< TODO */
|
||||
uint32 ofsBoundingTriangles; /**< TODO */
|
||||
uint32 nBoundingVertices; /**< TODO */
|
||||
uint32 ofsBoundingVertices; /**< TODO */
|
||||
uint32 nBoundingNormals; /**< TODO */
|
||||
uint32 ofsBoundingNormals; /**< TODO */
|
||||
uint32 nAttachments; /**< TODO */
|
||||
uint32 ofsAttachments; /**< TODO */
|
||||
uint32 nAttachLookup; /**< TODO */
|
||||
uint32 ofsAttachLookup; /**< TODO */
|
||||
uint32 nAttachments_2; /**< TODO */
|
||||
uint32 ofsAttachments_2; /**< TODO */
|
||||
uint32 nLights; /**< TODO */
|
||||
uint32 ofsLights; /**< TODO */
|
||||
uint32 nCameras; /**< TODO */
|
||||
uint32 ofsCameras; /**< TODO */
|
||||
uint32 nCameraLookup; /**< TODO */
|
||||
uint32 ofsCameraLookup; /**< TODO */
|
||||
uint32 nRibbonEmitters; /**< TODO */
|
||||
uint32 ofsRibbonEmitters; /**< TODO */
|
||||
uint32 nParticleEmitters; /**< TODO */
|
||||
uint32 ofsParticleEmitters; /**< TODO */
|
||||
|
||||
};
|
||||
|
||||
struct ModelHeaderOthers
|
||||
{
|
||||
char id[4]; /**< TODO */
|
||||
uint8 version[4]; /**< TODO */
|
||||
uint32 nameLength; /**< TODO */
|
||||
uint32 nameOfs; /**< TODO */
|
||||
uint32 type; /**< TODO */
|
||||
uint32 nGlobalSequences; /**< TODO */
|
||||
uint32 ofsGlobalSequences; /**< TODO */
|
||||
uint32 nAnimations; /**< TODO */
|
||||
uint32 ofsAnimations; /**< TODO */
|
||||
uint32 nAnimationLookup; /**< TODO */
|
||||
uint32 ofsAnimationLookup; /**< TODO */
|
||||
uint32 nBones; /**< TODO */
|
||||
uint32 ofsBones; /**< TODO */
|
||||
uint32 nKeyBoneLookup; /**< TODO */
|
||||
uint32 ofsKeyBoneLookup; /**< TODO */
|
||||
uint32 nVertices; /**< TODO */
|
||||
uint32 ofsVertices; /**< TODO */
|
||||
uint32 nViews; /**< TODO */
|
||||
uint32 nColors; /**< TODO */
|
||||
uint32 ofsColors; /**< TODO */
|
||||
uint32 nTextures; /**< TODO */
|
||||
uint32 ofsTextures; /**< TODO */
|
||||
uint32 nTransparency; /**< TODO */
|
||||
uint32 ofsTransparency; /**< TODO */
|
||||
uint32 nTextureanimations; /**< TODO */
|
||||
uint32 ofsTextureanimations; /**< TODO */
|
||||
uint32 nTexReplace; /**< TODO */
|
||||
uint32 ofsTexReplace; /**< TODO */
|
||||
uint32 nRenderFlags; /**< TODO */
|
||||
uint32 ofsRenderFlags; /**< TODO */
|
||||
uint32 nBoneLookupTable; /**< TODO */
|
||||
uint32 ofsBoneLookupTable; /**< TODO */
|
||||
uint32 nTexLookup; /**< TODO */
|
||||
uint32 ofsTexLookup; /**< TODO */
|
||||
uint32 nTexUnits; /**< TODO */
|
||||
uint32 ofsTexUnits; /**< TODO */
|
||||
uint32 nTransLookup; /**< TODO */
|
||||
uint32 ofsTransLookup; /**< TODO */
|
||||
uint32 nTexAnimLookup; /**< TODO */
|
||||
uint32 ofsTexAnimLookup; /**< TODO */
|
||||
float floats[14]; /**< TODO */
|
||||
uint32 nBoundingTriangles; /**< TODO */
|
||||
uint32 ofsBoundingTriangles; /**< TODO */
|
||||
uint32 nBoundingVertices; /**< TODO */
|
||||
uint32 ofsBoundingVertices; /**< TODO */
|
||||
uint32 nBoundingNormals; /**< TODO */
|
||||
uint32 ofsBoundingNormals; /**< TODO */
|
||||
uint32 nAttachments; /**< TODO */
|
||||
uint32 ofsAttachments; /**< TODO */
|
||||
uint32 nAttachLookup; /**< TODO */
|
||||
uint32 ofsAttachLookup; /**< TODO */
|
||||
uint32 nAttachments_2; /**< TODO */
|
||||
uint32 ofsAttachments_2; /**< TODO */
|
||||
uint32 nLights; /**< TODO */
|
||||
uint32 ofsLights; /**< TODO */
|
||||
uint32 nCameras; /**< TODO */
|
||||
uint32 ofsCameras; /**< TODO */
|
||||
uint32 nCameraLookup; /**< TODO */
|
||||
uint32 ofsCameraLookup; /**< TODO */
|
||||
uint32 nRibbonEmitters; /**< TODO */
|
||||
uint32 ofsRibbonEmitters; /**< TODO */
|
||||
uint32 nParticleEmitters; /**< TODO */
|
||||
uint32 ofsParticleEmitters; /**< TODO */
|
||||
};
|
||||
|
||||
struct ModelBoundingVertex
|
||||
{
|
||||
Vec3D pos; /**< TODO */
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
287
src/tools/Extractor_projects/vmap-extractor/vec3d.h
Normal file
287
src/tools/Extractor_projects/vmap-extractor/vec3d.h
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef VEC3D_H
|
||||
#define VEC3D_H
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class Vec3D
|
||||
{
|
||||
public:
|
||||
float x, y, z; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param x0
|
||||
* @param y0
|
||||
* @param z0
|
||||
*/
|
||||
Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
*/
|
||||
Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D &operator
|
||||
*/
|
||||
Vec3D& operator= (const Vec3D& v)
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D operator
|
||||
*/
|
||||
Vec3D operator+ (const Vec3D& v) const
|
||||
{
|
||||
Vec3D r(x + v.x, y + v.y, z + v.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D operator
|
||||
*/
|
||||
Vec3D operator- (const Vec3D& v) const
|
||||
{
|
||||
Vec3D r(x - v.x, y - v.y, z - v.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return float operator
|
||||
*/
|
||||
float operator* (const Vec3D& v) const
|
||||
{
|
||||
return x * v.x + y * v.y + z * v.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param d
|
||||
* @return Vec3D operator
|
||||
*/
|
||||
Vec3D operator* (float d) const
|
||||
{
|
||||
Vec3D r(x * d, y * d, z * d);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param d
|
||||
* @param v
|
||||
* @return Vec3D operator
|
||||
*/
|
||||
friend Vec3D operator* (float d, const Vec3D& v)
|
||||
{
|
||||
return v * d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D operator
|
||||
*/
|
||||
Vec3D operator% (const Vec3D& v) const
|
||||
{
|
||||
Vec3D r(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D &operator
|
||||
*/
|
||||
Vec3D& operator+= (const Vec3D& v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D &operator
|
||||
*/
|
||||
Vec3D& operator-= (const Vec3D& v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param d
|
||||
* @return Vec3D &operator
|
||||
*/
|
||||
Vec3D& operator*= (float d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
z *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float lengthSquared() const
|
||||
{
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float length() const
|
||||
{
|
||||
return sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return Vec3D
|
||||
*/
|
||||
Vec3D& normalize()
|
||||
{
|
||||
this->operator*= (1.0f / length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return Vec3D operator
|
||||
*/
|
||||
Vec3D operator~() const
|
||||
{
|
||||
Vec3D r(*this);
|
||||
r.normalize();
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param in
|
||||
* @param v
|
||||
* @return std::istream &operator >>
|
||||
*/
|
||||
friend std::istream& operator>>(std::istream& in, Vec3D& v)
|
||||
{
|
||||
in >> v.x >> v.y >> v.z;
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param out
|
||||
* @param v
|
||||
* @return std::ostream &operator
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& out, const Vec3D& v)
|
||||
{
|
||||
out << v.x << " " << v.y << " " << v.z;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return operator float
|
||||
*/
|
||||
operator float* ()
|
||||
{
|
||||
return (float*)this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param x0
|
||||
* @param y0
|
||||
* @param x
|
||||
* @param y
|
||||
* @param angle
|
||||
*/
|
||||
inline void rotate(float x0, float y0, float* x, float* y, float angle)
|
||||
{
|
||||
float xa = *x - x0, ya = *y - y0;
|
||||
*x = xa * cosf(angle) - ya * sinf(angle) + x0;
|
||||
*y = xa * sinf(angle) + ya * cosf(angle) + y0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief for whatever reason a certain company just can't stick to one coordinate system...
|
||||
*
|
||||
* @param v
|
||||
* @return Vec3D
|
||||
*/
|
||||
inline Vec3D fixCoords(const Vec3D& v) { return Vec3D(v.z, v.x, v.y); }
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
IDI_APPICON ICON DISCARDABLE "../tools.ico"
|
||||
592
src/tools/Extractor_projects/vmap-extractor/vmapexport.cpp
Normal file
592
src/tools/Extractor_projects/vmap-extractor/vmapexport.cpp
Normal file
|
|
@ -0,0 +1,592 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined WIN32
|
||||
#include <Windows.h>
|
||||
#include <sys/stat.h>
|
||||
#include <direct.h>
|
||||
#define mkdir _mkdir
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
//#pragma warning(disable : 4505)
|
||||
//#pragma comment(lib, "Winmm.lib")
|
||||
|
||||
#include <map>
|
||||
|
||||
//From Extractor
|
||||
#include "adtfile.h"
|
||||
#include "wdtfile.h"
|
||||
#include "dbcfile.h"
|
||||
#include "wmo.h"
|
||||
#include <ml/mpq.h>
|
||||
#include "vmapexport.h"
|
||||
#include "Auth/md5.h"
|
||||
|
||||
#include "ExtractorCommon.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define MPQ_BLOCK_SIZE 0x1000
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool AssembleVMAP(std::string src, std::string dest, const char* szMagic);
|
||||
extern ArchiveSet gOpenArchives;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[64];
|
||||
unsigned int id;
|
||||
} map_id;
|
||||
|
||||
map_id* map_ids;
|
||||
uint16* LiqType = 0;
|
||||
uint32 map_count;
|
||||
char output_path[128] = ".";
|
||||
char input_path[1024] = ".";
|
||||
bool hasInputPathParam = false;
|
||||
bool preciseVectorData = true;
|
||||
|
||||
// Constants
|
||||
|
||||
//static const char * szWorkDirMaps = ".\\Maps";
|
||||
char const szWorkDirWmo[] = "./Buildings";
|
||||
char szRawVMAPMagic[] = "VMAP000";
|
||||
|
||||
// Local testing functions
|
||||
|
||||
bool FileExists(const char* file)
|
||||
{
|
||||
if (FILE* n = std::fopen(file, "rb"))
|
||||
{
|
||||
fclose(n);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void compute_md5(const char* value, char* result)
|
||||
{
|
||||
md5_byte_t digest[16];
|
||||
md5_state_t ctx;
|
||||
|
||||
md5_init(&ctx);
|
||||
md5_append(&ctx, (const unsigned char*)value, strlen(value));
|
||||
md5_finish(&ctx, digest);
|
||||
|
||||
for(int i=0;i<16;i++)
|
||||
{
|
||||
sprintf(result+2*i,"%02x",digest[i]);
|
||||
}
|
||||
result[32]='\0';
|
||||
}
|
||||
|
||||
std::string GetUniformName(std::string& path)
|
||||
{
|
||||
std::transform(path.begin(),path.end(),path.begin(),::tolower);
|
||||
|
||||
string tempPath;
|
||||
string file;
|
||||
char digest[33];
|
||||
|
||||
std::size_t found = path.find_last_of("/\\");
|
||||
if (found != string::npos)
|
||||
{
|
||||
file = path.substr(found+1);
|
||||
tempPath = path.substr(0,found);
|
||||
}
|
||||
else
|
||||
{
|
||||
file = tempPath = path;
|
||||
}
|
||||
|
||||
if(!tempPath.empty())
|
||||
compute_md5(tempPath.c_str(),digest);
|
||||
else
|
||||
compute_md5("\\",digest);
|
||||
|
||||
string result;
|
||||
result = result.assign(digest) + "-" + file;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetExtension(std::string& path)
|
||||
{
|
||||
string ext;
|
||||
size_t foundExt = path.find_last_of(".");
|
||||
if (foundExt != std::string::npos)
|
||||
{
|
||||
ext=path.substr(foundExt+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ext.clear();
|
||||
}
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||
return ext;
|
||||
}
|
||||
|
||||
// copied from contrib/extractor/System.cpp
|
||||
void ReadLiquidTypeTableDBC()
|
||||
{
|
||||
printf(" Reading liquid types from LiquidType.dbc...");
|
||||
DBCFile dbc("DBFilesClient\\LiquidType.dbc");
|
||||
if (!dbc.open())
|
||||
{
|
||||
printf("Fatal error: Could not read LiquidType.dbc!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size_t LiqType_count = dbc.getRecordCount();
|
||||
size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0);
|
||||
LiqType = new uint16[LiqType_maxid + 1];
|
||||
memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16));
|
||||
|
||||
for (uint32 x = 0; x < LiqType_count; ++x)
|
||||
{
|
||||
LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
|
||||
}
|
||||
|
||||
printf(" Success! (%u Liquid Types loaded)\n", (unsigned int)LiqType_count);
|
||||
}
|
||||
|
||||
void ParseMapFiles(int iCoreNumber)
|
||||
{
|
||||
char fn[512];
|
||||
//char id_filename[64];
|
||||
char id[10];
|
||||
StringSet failedPaths;
|
||||
printf("\n");
|
||||
for (unsigned int i = 0; i < map_count; ++i)
|
||||
{
|
||||
sprintf(id, "%03u", map_ids[i].id);
|
||||
sprintf(fn, "World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name);
|
||||
WDTFile WDT(fn, map_ids[i].name);
|
||||
if (WDT.init(id, map_ids[i].id))
|
||||
{
|
||||
printf(" Processing Map %u (%s)\n[", map_ids[i].id, map_ids[i].name);
|
||||
for (int x = 0; x < 64; ++x)
|
||||
{
|
||||
for (int y = 0; y < 64; ++y)
|
||||
{
|
||||
if (ADTFile* ADT = WDT.GetMap(x, y))
|
||||
{
|
||||
//sprintf(id_filename,"%02u %02u %03u",x,y,map_ids[i].id);//!!!!!!!!!
|
||||
ADT->init(map_ids[i].id, x, y, failedPaths, iCoreNumber, szRawVMAPMagic);
|
||||
delete ADT;
|
||||
}
|
||||
}
|
||||
printf("#");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!failedPaths.empty())
|
||||
{
|
||||
printf(" Warning: Some models could not be extracted, see below\n");
|
||||
for (StringSet::const_iterator itr = failedPaths.begin(); itr != failedPaths.end(); ++itr)
|
||||
{
|
||||
printf("Could not find file of model %s\n", itr->c_str());
|
||||
}
|
||||
printf(" A few not found models can be expected and are not alarming.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void getGamePath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
strcpy(input_path, "Data\\");
|
||||
#else
|
||||
strcpy(input_path, "Data/");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool scan_patches(char* scanmatch, std::vector<std::string>& pArchiveNames)
|
||||
{
|
||||
int i;
|
||||
char path[512];
|
||||
|
||||
for (i = 1; i <= 99; i++)
|
||||
{
|
||||
if (i != 1)
|
||||
{
|
||||
sprintf(path, "%s-%d.MPQ", scanmatch, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(path, "%s.MPQ", scanmatch);
|
||||
}
|
||||
#ifdef __linux__
|
||||
if (FILE* h = fopen64(path, "rb"))
|
||||
#else
|
||||
if (FILE* h = fopen(path, "rb"))
|
||||
#endif
|
||||
{
|
||||
fclose(h);
|
||||
//matches.push_back(path);
|
||||
pArchiveNames.push_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool fillArchiveNameVector(std::vector<std::string>& pArchiveNames, int iCoreNumber)
|
||||
{
|
||||
if (iCoreNumber == CLIENT_TBC || iCoreNumber ==2)
|
||||
{
|
||||
if (!hasInputPathParam)
|
||||
{
|
||||
getGamePath();
|
||||
}
|
||||
}
|
||||
printf("\n Game path: %s\n", input_path);
|
||||
|
||||
char path[512];
|
||||
// open expansion and common files
|
||||
if (iCoreNumber == CLIENT_CLASSIC)
|
||||
{
|
||||
printf(" Opening data files from data directory.\n");
|
||||
sprintf(path, "%s/Data/terrain.MPQ", input_path);
|
||||
pArchiveNames.push_back(path);
|
||||
sprintf(path, "%s/Data/model.MPQ", input_path);
|
||||
pArchiveNames.push_back(path);
|
||||
sprintf(path, "%s/Data/texture.MPQ", input_path);
|
||||
pArchiveNames.push_back(path);
|
||||
sprintf(path, "%s/Data/wmo.MPQ", input_path);
|
||||
pArchiveNames.push_back(path);
|
||||
sprintf(path, "%s/Data/misc.MPQ", input_path);
|
||||
pArchiveNames.push_back(path);
|
||||
|
||||
sprintf(path, "%s/Data/patch", input_path);
|
||||
if (!scan_patches(path, pArchiveNames))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (iCoreNumber == CLIENT_TBC || iCoreNumber == CLIENT_WOTLK)
|
||||
{
|
||||
string in_path(input_path);
|
||||
std::vector<std::string> locales, searchLocales;
|
||||
|
||||
searchLocales.push_back("enGB");
|
||||
searchLocales.push_back("enUS");
|
||||
searchLocales.push_back("deDE");
|
||||
searchLocales.push_back("esES");
|
||||
searchLocales.push_back("frFR");
|
||||
searchLocales.push_back("koKR");
|
||||
searchLocales.push_back("zhCN");
|
||||
searchLocales.push_back("zhTW");
|
||||
searchLocales.push_back("enCN");
|
||||
searchLocales.push_back("enTW");
|
||||
searchLocales.push_back("esMX");
|
||||
searchLocales.push_back("ruRU");
|
||||
|
||||
for (std::vector<std::string>::iterator i = searchLocales.begin(); i != searchLocales.end(); ++i)
|
||||
{
|
||||
std::string localePath = in_path + *i;
|
||||
// check if locale exists:
|
||||
struct stat status;
|
||||
if (stat(localePath.c_str(), &status))
|
||||
continue;
|
||||
if ((status.st_mode & S_IFDIR) == 0)
|
||||
continue;
|
||||
printf(" Found locale '%s'\n", i->c_str());
|
||||
locales.push_back(*i);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// open locale expansion and common files
|
||||
printf(" Adding data files from locale directories.\n");
|
||||
for (std::vector<std::string>::iterator i = locales.begin(); i != locales.end(); ++i)
|
||||
{
|
||||
pArchiveNames.push_back(in_path + *i + "/locale-" + *i + ".MPQ");
|
||||
pArchiveNames.push_back(in_path + *i + "/expansion-locale-" + *i + ".MPQ");
|
||||
if (iCoreNumber == CLIENT_WOTLK)
|
||||
{
|
||||
pArchiveNames.push_back(in_path + *i + "/lichking-locale-" + *i + ".MPQ");
|
||||
}
|
||||
}
|
||||
printf(" Opening data files from data directory.\n");
|
||||
pArchiveNames.push_back(input_path + string("common.MPQ"));
|
||||
if (iCoreNumber == CLIENT_WOTLK)
|
||||
{
|
||||
pArchiveNames.push_back(input_path + string("common-2.MPQ"));
|
||||
}
|
||||
pArchiveNames.push_back(input_path + string("expansion.MPQ"));
|
||||
if (iCoreNumber == CLIENT_WOTLK)
|
||||
{
|
||||
pArchiveNames.push_back(input_path + string("lichking.MPQ"));
|
||||
}
|
||||
|
||||
// now, scan for the patch levels in the core dir
|
||||
printf(" Scanning patch levels from data directory.\n");
|
||||
sprintf(path, "%spatch", input_path);
|
||||
if (!scan_patches(path, pArchiveNames))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
||||
// now, scan for the patch levels in locale dirs
|
||||
printf(" Scanning patch levels from locale directories.\n");
|
||||
bool foundOne = false;
|
||||
for (std::vector<std::string>::iterator i = locales.begin(); i != locales.end(); ++i)
|
||||
{
|
||||
printf(" Locale: %s\n", i->c_str());
|
||||
sprintf(path, "%s%s/patch-%s", input_path, i->c_str(), i->c_str());
|
||||
if (scan_patches(path, pArchiveNames))
|
||||
foundOne = true;
|
||||
}
|
||||
printf("\n");
|
||||
if (!foundOne)
|
||||
{
|
||||
printf("no locale found\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Usage(char* prg)
|
||||
{
|
||||
printf(" Usage: %s [OPTION]\n\n", prg);
|
||||
printf(" Extract client database files and generate map files.\n");
|
||||
printf(" -h, --help show the usage\n");
|
||||
printf(" -d, --data <path> search path for game client archives\n");
|
||||
printf(" -s, --small extract smaller vmaps by optimizing data. Reduces\n");
|
||||
printf(" size by ~ 500MB\n");
|
||||
printf("\n");
|
||||
printf(" Example:\n");
|
||||
printf(" - use data path and create larger vmaps:\n");
|
||||
printf(" %s -l -d \"c:\\games\\world of warcraft\"\n", prg);
|
||||
}
|
||||
|
||||
bool processArgv(int argc, char** argv)
|
||||
{
|
||||
bool result = true;
|
||||
char* param = NULL;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 )
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--small") == 0 )
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--data") == 0 )
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
result = true;
|
||||
strcpy(input_path, param);
|
||||
if (input_path[strlen(input_path) - 1] != '\\' || input_path[strlen(input_path) - 1] != '/')
|
||||
{
|
||||
strcat(input_path, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Usage(argv[0]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// Main
|
||||
//
|
||||
// The program must be run with two command line arguments
|
||||
//
|
||||
// Arg1 - The source MPQ name (for testing reading and file find)
|
||||
// Arg2 - Listfile name
|
||||
//
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int thisBuild = getBuildNumber();
|
||||
int iCoreNumber = getCoreNumberFromBuild(thisBuild);
|
||||
std::string outDir = std::string(output_path) + "/vmaps";
|
||||
|
||||
showBanner("Vertical Map Asset Extractor", iCoreNumber);
|
||||
setVMapMagicVersion(iCoreNumber, szRawVMAPMagic);
|
||||
showWebsiteBanner();
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Use command line arguments, when some
|
||||
if (!processArgv(argc, argv))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// some simple check if working dir is dirty
|
||||
else
|
||||
{
|
||||
std::string sdir = std::string(szWorkDirWmo) + "/dir";
|
||||
std::string sdir_bin = std::string(szWorkDirWmo) + "/dir_bin";
|
||||
struct stat status;
|
||||
bool dirty = false;
|
||||
|
||||
if (!stat(sdir.c_str(), &status) || !stat(sdir_bin.c_str(), &status))
|
||||
{
|
||||
printf(" Your %s directory seems to exist, please delete it!\n", szWorkDirWmo);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (!stat(outDir.c_str(), &status))
|
||||
{
|
||||
printf(" Your %s directory seems to exist, please delete it!\n", outDir.c_str());
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
printf(" <press return to exit>");
|
||||
char garbage[2];
|
||||
int ret = scanf("%c", garbage);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf(" Beginning work ....\n");
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// Create the working and ouput directories
|
||||
CreateDir(std::string(szWorkDirWmo));
|
||||
CreateDir(outDir);
|
||||
|
||||
// prepare archive name list
|
||||
std::vector<std::string> archiveNames;
|
||||
fillArchiveNameVector(archiveNames, iCoreNumber);
|
||||
for (size_t i = 0; i < archiveNames.size(); ++i)
|
||||
{
|
||||
MPQArchive* archive = new MPQArchive(archiveNames[i].c_str());
|
||||
if (!gOpenArchives.size() || gOpenArchives.front() != archive)
|
||||
{
|
||||
delete archive;
|
||||
}
|
||||
}
|
||||
|
||||
if (gOpenArchives.empty())
|
||||
{
|
||||
printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n", input_path);
|
||||
return 1;
|
||||
}
|
||||
if (iCoreNumber == CLIENT_CLASSIC)
|
||||
{
|
||||
ReadLiquidTypeTableDBC();
|
||||
}
|
||||
|
||||
// extract data
|
||||
if (success)
|
||||
{
|
||||
success = ExtractWmo(iCoreNumber, szRawVMAPMagic);
|
||||
}
|
||||
|
||||
// Open map.dbc
|
||||
if (success)
|
||||
{
|
||||
DBCFile* dbc = new DBCFile("DBFilesClient\\Map.dbc");
|
||||
if (!dbc->open())
|
||||
{
|
||||
delete dbc;
|
||||
printf("FATAL ERROR: Map.dbc not found in data file.\n");
|
||||
return 1;
|
||||
}
|
||||
map_count = dbc->getRecordCount();
|
||||
map_ids = new map_id[map_count];
|
||||
for (unsigned int x = 0; x < map_count; ++x)
|
||||
{
|
||||
map_ids[x].id = dbc->getRecord(x).getUInt(0);
|
||||
strcpy(map_ids[x].name, dbc->getRecord(x).getString(1));
|
||||
printf(" Map %d - %s\n", map_ids[x].id, map_ids[x].name);
|
||||
}
|
||||
|
||||
|
||||
delete dbc;
|
||||
ParseMapFiles(iCoreNumber);
|
||||
delete [] map_ids;
|
||||
//nError = ERROR_SUCCESS;
|
||||
// Extract models, listed in DameObjectDisplayInfo.dbc
|
||||
ExtractGameobjectModels(iCoreNumber, szRawVMAPMagic);
|
||||
}
|
||||
|
||||
delete [] LiqType;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
printf("ERROR: Extract for %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n", szRawVMAPMagic, preciseVectorData);
|
||||
getchar();
|
||||
return 1;
|
||||
}
|
||||
|
||||
success = AssembleVMAP(std::string(szWorkDirWmo), outDir, szRawVMAPMagic);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
printf("ERROR: VMAP building for %s NOT completed", szRawVMAPMagic);
|
||||
getchar();
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf(" VMAP building complete. No errors.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
75
src/tools/Extractor_projects/vmap-extractor/vmapexport.h
Normal file
75
src/tools/Extractor_projects/vmap-extractor/vmapexport.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef VMAPEXPORT_H
|
||||
#define VMAPEXPORT_H
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
typedef std::set<std::string> StringSet;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
enum ModelFlags
|
||||
{
|
||||
MOD_M2 = 1,
|
||||
MOD_WORLDSPAWN = 1 << 1,
|
||||
MOD_HAS_BOUND = 1 << 2
|
||||
};
|
||||
|
||||
extern char const szWorkDirWmo[]; /**< TODO */
|
||||
//extern const char* szRawVMAPMagic; /**< vmap magic string for extracted raw vmap data */
|
||||
|
||||
/**
|
||||
* @brief Test if the specified file exists in the building directory
|
||||
*
|
||||
* @param file
|
||||
* @return bool
|
||||
*/
|
||||
bool FileExists(const char* file);
|
||||
|
||||
/**
|
||||
* @brief Get "uniform" name for a path (a uniform name has the format <md5hash>-<filename>.<ext>)
|
||||
*
|
||||
* @param path
|
||||
* @return string
|
||||
*/
|
||||
std::string GetUniformName(std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Get extension for a file
|
||||
*
|
||||
* @param file
|
||||
* @return extension, if found, or empty string if not
|
||||
*/
|
||||
std::string GetExtension(std::string& file);
|
||||
|
||||
#endif
|
||||
129
src/tools/Extractor_projects/vmap-extractor/wdtfile.cpp
Normal file
129
src/tools/Extractor_projects/vmap-extractor/wdtfile.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include "vmapexport.h"
|
||||
#include "wdtfile.h"
|
||||
|
||||
WDTFile::WDTFile(char* file_name, char* file_name1): WDT(file_name)
|
||||
{
|
||||
filename.assign(file_name1);
|
||||
}
|
||||
|
||||
bool WDTFile::init(char* map_id, unsigned int mapID)
|
||||
{
|
||||
if (WDT.isEof())
|
||||
{
|
||||
//printf("Can't find WDT file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char fourcc[5];
|
||||
uint32 size;
|
||||
|
||||
std::string dirname = std::string(szWorkDirWmo) + "/dir_bin";
|
||||
FILE* dirfile;
|
||||
dirfile = fopen(dirname.c_str(), "ab");
|
||||
if (!dirfile)
|
||||
{
|
||||
printf("Can't open dirfile!'%s'\n", dirname.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!WDT.isEof())
|
||||
{
|
||||
WDT.read(fourcc, 4);
|
||||
WDT.read(&size, 4);
|
||||
|
||||
flipcc(fourcc);
|
||||
fourcc[4] = 0;
|
||||
|
||||
size_t nextpos = WDT.getPos() + size;
|
||||
|
||||
if (!strcmp(fourcc, "MAIN"))
|
||||
{
|
||||
}
|
||||
if (!strcmp(fourcc, "MWMO"))
|
||||
{
|
||||
// global map objects
|
||||
if (size)
|
||||
{
|
||||
char* buf = new char[size];
|
||||
WDT.read(buf, size);
|
||||
char* p = buf;
|
||||
int q = 0;
|
||||
gWmoInstansName = new string[size];
|
||||
while (p < buf + size)
|
||||
{
|
||||
string path(p);
|
||||
gWmoInstansName[q++] = GetUniformName(path);
|
||||
p = p + strlen(p) + 1;
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc, "MODF"))
|
||||
{
|
||||
// global wmo instance data
|
||||
if (size)
|
||||
{
|
||||
gnWMO = (int)size / 64;
|
||||
string gWMO_mapname;
|
||||
string fake_mapname;
|
||||
fake_mapname = "65 65 ";
|
||||
//gWMO_mapname = fake_mapname + filename;
|
||||
gWMO_mapname = fake_mapname + std::string(map_id);
|
||||
for (int i = 0; i < gnWMO; ++i)
|
||||
{
|
||||
int id;
|
||||
WDT.read(&id, 4);
|
||||
WMOInstance inst(WDT, gWmoInstansName[id], mapID, 65, 65, dirfile);
|
||||
}
|
||||
delete[] gWmoInstansName;
|
||||
}
|
||||
}
|
||||
WDT.seek((int)nextpos);
|
||||
}
|
||||
|
||||
fclose(dirfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
WDTFile::~WDTFile(void)
|
||||
{
|
||||
WDT.close();
|
||||
}
|
||||
|
||||
ADTFile* WDTFile::GetMap(int x, int z)
|
||||
{
|
||||
if (!(x >= 0 && z >= 0 && x < 64 && z < 64))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char name[512];
|
||||
|
||||
sprintf(name, "World\\Maps\\%s\\%s_%d_%d.adt", filename.c_str(), filename.c_str(), x, z);
|
||||
return new ADTFile(name);
|
||||
}
|
||||
79
src/tools/Extractor_projects/vmap-extractor/wdtfile.h
Normal file
79
src/tools/Extractor_projects/vmap-extractor/wdtfile.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef WDTFILE_H
|
||||
#define WDTFILE_H
|
||||
|
||||
#include <string>
|
||||
#include <ml/mpq.h>
|
||||
#include "wmo.h"
|
||||
#include "adtfile.h"
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class WDTFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param file_name
|
||||
* @param file_name1
|
||||
*/
|
||||
WDTFile(char* file_name, char* file_name1);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~WDTFile(void);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param map_id
|
||||
* @param mapID
|
||||
* @return bool
|
||||
*/
|
||||
bool init(char* map_id, unsigned int mapID);
|
||||
|
||||
std::string* gWmoInstansName; /**< TODO */
|
||||
int gnWMO, nMaps; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param x
|
||||
* @param z
|
||||
* @return ADTFile
|
||||
*/
|
||||
ADTFile* GetMap(int x, int z);
|
||||
|
||||
private:
|
||||
MPQFile WDT; /**< TODO */
|
||||
bool maps[64][64]; /**< TODO */
|
||||
std::string filename; /**< TODO */
|
||||
};
|
||||
|
||||
#endif
|
||||
745
src/tools/Extractor_projects/vmap-extractor/wmo.cpp
Normal file
745
src/tools/Extractor_projects/vmap-extractor/wmo.cpp
Normal file
|
|
@ -0,0 +1,745 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "wmo.h"
|
||||
#include "vec3d.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <ExtractorCommon.h>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
extern uint16* LiqType;
|
||||
extern bool preciseVectorData;
|
||||
extern ArchiveSet gOpenArchives;
|
||||
|
||||
WMORoot::WMORoot(std::string& filename) : filename(filename)
|
||||
{
|
||||
}
|
||||
|
||||
bool WMORoot::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
if (f.isEof())
|
||||
{
|
||||
printf(" No such file %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 size;
|
||||
char fourcc[5];
|
||||
|
||||
while (!f.isEof())
|
||||
{
|
||||
f.read(fourcc, 4);
|
||||
f.read(&size, 4);
|
||||
|
||||
flipcc(fourcc);
|
||||
fourcc[4] = 0;
|
||||
|
||||
size_t nextpos = f.getPos() + size;
|
||||
|
||||
if (!strcmp(fourcc, "MOHD")) //header
|
||||
{
|
||||
f.read(&nTextures, 4);
|
||||
f.read(&nGroups, 4);
|
||||
f.read(&nP, 4);
|
||||
f.read(&nLights, 4);
|
||||
f.read(&nModels, 4);
|
||||
f.read(&nDoodads, 4);
|
||||
f.read(&nDoodadSets, 4);
|
||||
f.read(&col, 4);
|
||||
f.read(&RootWMOID, 4);
|
||||
f.read(bbcorn1, 12);
|
||||
f.read(bbcorn2, 12);
|
||||
f.read(&liquidType, 4);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
else if (!strcmp(fourcc,"MOTX"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOMT"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOGN"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOGI"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOLT"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODN"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODS"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MODD"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOSB"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPV"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPT"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MOPR"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc,"MFOG"))
|
||||
{
|
||||
}
|
||||
*/
|
||||
f.seek((int)nextpos);
|
||||
}
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WMORoot::ConvertToVMAPRootWmo(FILE* pOutfile, const void *szRawVMAPMagic)
|
||||
{
|
||||
//printf("Convert RootWmo...\n");
|
||||
|
||||
fwrite(szRawVMAPMagic, 1, 8, pOutfile);
|
||||
unsigned int nVectors = 0;
|
||||
fwrite(&nVectors, sizeof(nVectors), 1, pOutfile); // will be filled later
|
||||
fwrite(&nGroups, 4, 1, pOutfile);
|
||||
fwrite(&RootWMOID, 4, 1, pOutfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
WMORoot::~WMORoot()
|
||||
{
|
||||
}
|
||||
|
||||
WMOGroup::WMOGroup(std::string& filename) : filename(filename),
|
||||
MOPY(0), MOVI(0), MoviEx(0), MOVT(0), MOBA(0), MobaEx(0), hlq(0), LiquEx(0), LiquBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool WMOGroup::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
if (f.isEof())
|
||||
{
|
||||
printf(" No such file.\n");
|
||||
return false;
|
||||
}
|
||||
uint32 size;
|
||||
char fourcc[5];
|
||||
while (!f.isEof())
|
||||
{
|
||||
f.read(fourcc, 4);
|
||||
f.read(&size, 4);
|
||||
flipcc(fourcc);
|
||||
if (!strcmp(fourcc, "MOGP")) //Fix sizeoff = Data size.
|
||||
{
|
||||
size = 68;
|
||||
}
|
||||
fourcc[4] = 0;
|
||||
size_t nextpos = f.getPos() + size;
|
||||
LiquEx_size = 0;
|
||||
liquflags = 0;
|
||||
|
||||
if (!strcmp(fourcc, "MOGP")) //header
|
||||
{
|
||||
f.read(&groupName, 4);
|
||||
f.read(&descGroupName, 4);
|
||||
f.read(&mogpFlags, 4);
|
||||
f.read(bbcorn1, 12);
|
||||
f.read(bbcorn2, 12);
|
||||
f.read(&moprIdx, 2);
|
||||
f.read(&moprNItems, 2);
|
||||
f.read(&nBatchA, 2);
|
||||
f.read(&nBatchB, 2);
|
||||
f.read(&nBatchC, 4);
|
||||
f.read(&fogIdx, 4);
|
||||
f.read(&liquidType, 4);
|
||||
f.read(&groupWMOID, 4);
|
||||
|
||||
}
|
||||
else if (!strcmp(fourcc, "MOPY"))
|
||||
{
|
||||
MOPY = new char[size];
|
||||
mopy_size = size;
|
||||
nTriangles = (int)size / 2;
|
||||
f.read(MOPY, size);
|
||||
}
|
||||
else if (!strcmp(fourcc, "MOVI"))
|
||||
{
|
||||
MOVI = new uint16[size / 2];
|
||||
f.read(MOVI, size);
|
||||
}
|
||||
else if (!strcmp(fourcc, "MOVT"))
|
||||
{
|
||||
MOVT = new float[size / 4];
|
||||
f.read(MOVT, size);
|
||||
nVertices = (int)size / 12;
|
||||
}
|
||||
else if (!strcmp(fourcc, "MONR"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc, "MOTV"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(fourcc, "MOBA"))
|
||||
{
|
||||
MOBA = new uint16[size / 2];
|
||||
moba_size = size / 2;
|
||||
f.read(MOBA, size);
|
||||
}
|
||||
else if (!strcmp(fourcc, "MLIQ"))
|
||||
{
|
||||
liquflags |= 1;
|
||||
hlq = new WMOLiquidHeader;
|
||||
f.read(hlq, 0x1E);
|
||||
LiquEx_size = sizeof(WMOLiquidVert) * hlq->xverts * hlq->yverts;
|
||||
LiquEx = new WMOLiquidVert[hlq->xverts * hlq->yverts];
|
||||
f.read(LiquEx, LiquEx_size);
|
||||
int nLiquBytes = hlq->xtiles * hlq->ytiles;
|
||||
LiquBytes = new char[nLiquBytes];
|
||||
f.read(LiquBytes, nLiquBytes);
|
||||
|
||||
/* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app);
|
||||
llog << filename;
|
||||
llog << "\nbbox: " << bbcorn1[0] << ", " << bbcorn1[1] << ", " << bbcorn1[2] << " | " << bbcorn2[0] << ", " << bbcorn2[1] << ", " << bbcorn2[2];
|
||||
llog << "\nlpos: " << hlq->pos_x << ", " << hlq->pos_y << ", " << hlq->pos_z;
|
||||
llog << "\nx-/yvert: " << hlq->xverts << "/" << hlq->yverts << " size: " << size << " expected size: " << 30 + hlq->xverts*hlq->yverts*8 + hlq->xtiles*hlq->ytiles << std::endl;
|
||||
llog.close(); */
|
||||
}
|
||||
f.seek((int)nextpos);
|
||||
}
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
int WMOGroup::ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool pPreciseVectorData, int iCoreNumber)
|
||||
{
|
||||
fwrite(&mogpFlags, sizeof(uint32), 1, output);
|
||||
fwrite(&groupWMOID, sizeof(uint32), 1, output);
|
||||
// group bound
|
||||
fwrite(bbcorn1, sizeof(float), 3, output);
|
||||
fwrite(bbcorn2, sizeof(float), 3, output);
|
||||
fwrite(&liquflags, sizeof(uint32), 1, output);
|
||||
int nColTriangles = 0;
|
||||
if (pPreciseVectorData)
|
||||
{
|
||||
char GRP[] = "GRP ";
|
||||
fwrite(GRP, 1, 4, output);
|
||||
|
||||
int k = 0;
|
||||
int moba_batch = moba_size / 12;
|
||||
MobaEx = new int[moba_batch * 4];
|
||||
for (int i = 8; i < moba_size; i += 12)
|
||||
{
|
||||
MobaEx[k++] = MOBA[i];
|
||||
}
|
||||
int moba_size_grp = moba_batch * 4 + 4;
|
||||
fwrite(&moba_size_grp, 4, 1, output);
|
||||
fwrite(&moba_batch, 4, 1, output);
|
||||
fwrite(MobaEx, 4, k, output);
|
||||
delete [] MobaEx;
|
||||
|
||||
uint32 nIdexes = nTriangles * 3;
|
||||
|
||||
if (fwrite("INDX", 4, 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nbraches ID");
|
||||
exit(0);
|
||||
}
|
||||
int wsize = sizeof(uint32) + sizeof(unsigned short) * nIdexes;
|
||||
if (fwrite(&wsize, sizeof(int), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file wsize");
|
||||
exit(0);
|
||||
}
|
||||
if (fwrite(&nIdexes, sizeof(uint32), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nIndexes");
|
||||
exit(0);
|
||||
}
|
||||
if (nIdexes > 0)
|
||||
{
|
||||
if (fwrite(MOVI, sizeof(unsigned short), nIdexes, output) != nIdexes)
|
||||
{
|
||||
printf("Error while writing file indexarray");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (fwrite("VERT", 4, 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nbraches ID");
|
||||
exit(0);
|
||||
}
|
||||
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
|
||||
if (fwrite(&wsize, sizeof(int), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file wsize");
|
||||
exit(0);
|
||||
}
|
||||
if (fwrite(&nVertices, sizeof(int), 1, output) != 1)
|
||||
{
|
||||
printf("Error while writing file nVertices");
|
||||
exit(0);
|
||||
}
|
||||
if (nVertices > 0)
|
||||
{
|
||||
if (fwrite(MOVT, sizeof(float) * 3, nVertices, output) != nVertices)
|
||||
{
|
||||
printf("Error while writing file vectors");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
nColTriangles = nTriangles;
|
||||
}
|
||||
else
|
||||
{
|
||||
char GRP[] = "GRP ";
|
||||
fwrite(GRP, 1, 4, output);
|
||||
int k = 0;
|
||||
int moba_batch = moba_size / 12;
|
||||
MobaEx = new int[moba_batch * 4];
|
||||
for (int i = 8; i < moba_size; i += 12)
|
||||
{
|
||||
MobaEx[k++] = MOBA[i];
|
||||
}
|
||||
|
||||
int moba_size_grp = moba_batch * 4 + 4;
|
||||
fwrite(&moba_size_grp, 4, 1, output);
|
||||
fwrite(&moba_batch, 4, 1, output);
|
||||
fwrite(MobaEx, 4, k, output);
|
||||
delete [] MobaEx;
|
||||
|
||||
//-------INDX------------------------------------
|
||||
//-------MOPY--------
|
||||
MoviEx = new uint16[nTriangles * 3]; // "worst case" size...
|
||||
int* IndexRenum = new int[nVertices];
|
||||
memset(IndexRenum, 0xFF, nVertices * sizeof(int));
|
||||
for (int i = 0; i < nTriangles; ++i)
|
||||
{
|
||||
// Skip no collision triangles
|
||||
if (MOPY[2 * i]&WMO_MATERIAL_NO_COLLISION ||
|
||||
!(MOPY[2 * i] & (WMO_MATERIAL_HINT | WMO_MATERIAL_COLLIDE_HIT)))
|
||||
{ continue; }
|
||||
// Use this triangle
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
IndexRenum[MOVI[3 * i + j]] = 1;
|
||||
MoviEx[3 * nColTriangles + j] = MOVI[3 * i + j];
|
||||
}
|
||||
++nColTriangles;
|
||||
}
|
||||
|
||||
// assign new vertex index numbers
|
||||
int nColVertices = 0;
|
||||
for (uint32 i = 0; i < nVertices; ++i)
|
||||
{
|
||||
if (IndexRenum[i] == 1)
|
||||
{
|
||||
IndexRenum[i] = nColVertices;
|
||||
++nColVertices;
|
||||
}
|
||||
}
|
||||
|
||||
// translate triangle indices to new numbers
|
||||
for (int i = 0; i < 3 * nColTriangles; ++i)
|
||||
{
|
||||
assert(MoviEx[i] < nVertices);
|
||||
MoviEx[i] = IndexRenum[MoviEx[i]];
|
||||
}
|
||||
|
||||
// write triangle indices
|
||||
int INDX[] = {0x58444E49, nColTriangles * 6 + 4, nColTriangles * 3};
|
||||
fwrite(INDX, 4, 3, output);
|
||||
fwrite(MoviEx, 2, nColTriangles * 3, output);
|
||||
|
||||
// write vertices
|
||||
int VERT[] = {0x54524556, nColVertices * 3 * sizeof(float) + 4, nColVertices}; // "VERT"
|
||||
int check = 3 * nColVertices;
|
||||
fwrite(VERT, 4, 3, output);
|
||||
for (uint32 i = 0; i < nVertices; ++i)
|
||||
if (IndexRenum[i] >= 0)
|
||||
{
|
||||
check -= fwrite(MOVT + 3 * i, sizeof(float), 3, output);
|
||||
}
|
||||
|
||||
assert(check == 0);
|
||||
|
||||
delete [] MoviEx;
|
||||
delete [] IndexRenum;
|
||||
}
|
||||
|
||||
//------LIQU------------------------
|
||||
if (LiquEx_size != 0)
|
||||
{
|
||||
int LIQU_h[] = {0x5551494C, sizeof(WMOLiquidHeader) + LiquEx_size + hlq->xtiles* hlq->ytiles}; // "LIQU"
|
||||
fwrite(LIQU_h, 4, 2, output);
|
||||
|
||||
// according to WoW.Dev Wiki:
|
||||
uint32 liquidEntry;
|
||||
if (rootWMO->liquidType & 4)
|
||||
{
|
||||
liquidEntry = liquidType;
|
||||
}
|
||||
else if (liquidType == 15)
|
||||
{
|
||||
liquidEntry = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
liquidEntry = liquidType + 1;
|
||||
}
|
||||
|
||||
if (!liquidEntry)
|
||||
{
|
||||
int v1; // edx@1
|
||||
int v2; // eax@1
|
||||
|
||||
v1 = hlq->xtiles * hlq->ytiles;
|
||||
v2 = 0;
|
||||
if (v1 > 0)
|
||||
{
|
||||
while ((LiquBytes[v2] & 0xF) == 15)
|
||||
{
|
||||
++v2;
|
||||
if (v2 >= v1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (v2 < v1 && (LiquBytes[v2] & 0xF) != 15)
|
||||
{
|
||||
liquidEntry = (LiquBytes[v2] & 0xF) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (liquidEntry && liquidEntry < 21)
|
||||
{
|
||||
switch (((uint8)liquidEntry - 1) & 3)
|
||||
{
|
||||
case 0:
|
||||
if (iCoreNumber == CLIENT_WOTLK || iCoreNumber == CLIENT_CATA)
|
||||
{
|
||||
liquidEntry = ((mogpFlags & 0x80000) != 0) + 13;
|
||||
}
|
||||
if (iCoreNumber == CLIENT_CLASSIC || iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
liquidEntry = ((mogpFlags & 0x80000) != 0) + 1;
|
||||
if (iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
if (liquidEntry == 1) // water type
|
||||
{
|
||||
if (filename.find("coilfang_raid") != string::npos)
|
||||
{
|
||||
// set water type to special coilfang raid water
|
||||
liquidEntry = 41;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (iCoreNumber == CLIENT_CLASSIC || iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
liquidEntry = 2; // ocean
|
||||
}
|
||||
if (iCoreNumber == CLIENT_WOTLK || iCoreNumber == CLIENT_CATA)
|
||||
{
|
||||
liquidEntry = 14;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (iCoreNumber == CLIENT_CLASSIC || iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
liquidEntry = 3; // magma
|
||||
}
|
||||
if (iCoreNumber == CLIENT_WOTLK || iCoreNumber == CLIENT_CATA)
|
||||
{
|
||||
liquidEntry = 19;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (iCoreNumber == CLIENT_CLASSIC || iCoreNumber == CLIENT_TBC)
|
||||
{
|
||||
if ((filename.find("stratholme_raid") != string::npos) || (filename.find("Stratholme_raid") != string::npos))
|
||||
{
|
||||
liquidEntry = 21; // Naxxramas slime
|
||||
}
|
||||
else
|
||||
{
|
||||
liquidEntry = 4;
|
||||
} // Normal slime
|
||||
}
|
||||
if (iCoreNumber == CLIENT_WOTLK || iCoreNumber == CLIENT_CATA)
|
||||
{
|
||||
liquidEntry = 20;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hlq->type = liquidEntry;
|
||||
|
||||
/* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app);
|
||||
llog << filename;
|
||||
llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->liquidType << " group:" << liquidType << ")\n";
|
||||
llog.close(); */
|
||||
|
||||
fwrite(hlq, sizeof(WMOLiquidHeader), 1, output);
|
||||
// only need height values, the other values are unknown anyway
|
||||
for (uint32 i = 0; i < LiquEx_size / sizeof(WMOLiquidVert); ++i)
|
||||
{
|
||||
fwrite(&LiquEx[i].height, sizeof(float), 1, output);
|
||||
}
|
||||
// todo: compress to bit field
|
||||
fwrite(LiquBytes, 1, hlq->xtiles * hlq->ytiles, output);
|
||||
}
|
||||
|
||||
return nColTriangles;
|
||||
}
|
||||
|
||||
WMOGroup::~WMOGroup()
|
||||
{
|
||||
delete [] MOPY;
|
||||
delete [] MOVI;
|
||||
delete [] MOVT;
|
||||
delete [] MOBA;
|
||||
delete hlq;
|
||||
delete [] LiquEx;
|
||||
delete [] LiquBytes;
|
||||
}
|
||||
|
||||
//WmoInstName is in the form MD5/name.wmo
|
||||
WMOInstance::WMOInstance(MPQFile& f, std::string& WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
|
||||
{
|
||||
pos = Vec3D(0, 0, 0);
|
||||
|
||||
float ff[3];
|
||||
f.read(&id, 4);
|
||||
f.read(ff, 12);
|
||||
pos = Vec3D(ff[0], ff[1], ff[2]);
|
||||
f.read(ff, 12);
|
||||
rot = Vec3D(ff[0], ff[1], ff[2]);
|
||||
f.read(ff, 12);
|
||||
pos2 = Vec3D(ff[0], ff[1], ff[2]);
|
||||
f.read(ff, 12);
|
||||
pos3 = Vec3D(ff[0], ff[1], ff[2]);
|
||||
f.read(&d2, 4);
|
||||
|
||||
uint16 trash, adtId;
|
||||
f.read(&adtId, 2);
|
||||
f.read(&trash, 2);
|
||||
|
||||
//-----------add_in _dir_file----------------
|
||||
|
||||
char tempname[512];
|
||||
sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName.c_str());
|
||||
FILE* input;
|
||||
input = fopen(tempname, "r+b");
|
||||
|
||||
if (!input)
|
||||
{
|
||||
printf("WMOInstance::WMOInstance: couldn't open %s\n", tempname);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(input, 8, SEEK_SET); // get the correct no of vertices
|
||||
int nVertices;
|
||||
size_t file_read = fread(&nVertices, sizeof(int), 1, input);
|
||||
fclose(input);
|
||||
|
||||
if (nVertices == 0 || file_read <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float x, z;
|
||||
x = pos.x;
|
||||
z = pos.z;
|
||||
if (x == 0 && z == 0)
|
||||
{
|
||||
pos.x = 533.33333f * 32;
|
||||
pos.z = 533.33333f * 32;
|
||||
}
|
||||
pos = fixCoords(pos);
|
||||
pos2 = fixCoords(pos2);
|
||||
pos3 = fixCoords(pos3);
|
||||
|
||||
float scale = 1.0f;
|
||||
uint32 flags = MOD_HAS_BOUND;
|
||||
if (tileX == 65 && tileY == 65)
|
||||
{
|
||||
flags |= MOD_WORLDSPAWN;
|
||||
}
|
||||
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
|
||||
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&flags, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
|
||||
fwrite(&id, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(&pos, sizeof(float), 3, pDirfile);
|
||||
fwrite(&rot, sizeof(float), 3, pDirfile);
|
||||
fwrite(&scale, sizeof(float), 1, pDirfile);
|
||||
fwrite(&pos2, sizeof(float), 3, pDirfile);
|
||||
fwrite(&pos3, sizeof(float), 3, pDirfile);
|
||||
uint32 nlen = WmoInstName.length();
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(WmoInstName.c_str(), sizeof(char), nlen, pDirfile);
|
||||
|
||||
}
|
||||
|
||||
bool ExtractSingleWmo(std::string& fname, int iCoreNumber, const void *szRawVMAPMagic)
|
||||
{
|
||||
// Copy files from archive
|
||||
char szLocalFile[1024];
|
||||
string plain_name = GetUniformName(fname);
|
||||
|
||||
sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name.c_str());
|
||||
|
||||
if (FileExists(szLocalFile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int p = 0;
|
||||
//Select root wmo files
|
||||
const char* rchr = strrchr(plain_name.c_str(), '_');
|
||||
if (rchr != NULL)
|
||||
{
|
||||
char cpy[4];
|
||||
strncpy((char*)cpy, rchr, 4);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int m = cpy[i];
|
||||
if (isdigit(m))
|
||||
{
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p == 3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool file_ok = true;
|
||||
printf(" Extracting %s\n", fname.c_str());
|
||||
|
||||
WMORoot froot(fname);
|
||||
if (!froot.open())
|
||||
{
|
||||
printf("Couldn't open RootWmo!!!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE* output = fopen(szLocalFile, "wb");
|
||||
if (!output)
|
||||
{
|
||||
printf("Couldn't open %s for writing!\n", szLocalFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
froot.ConvertToVMAPRootWmo(output,szRawVMAPMagic);
|
||||
int Wmo_nVertices = 0;
|
||||
if (froot.nGroups != 0)
|
||||
{
|
||||
for (uint32 i = 0; i < froot.nGroups; ++i)
|
||||
{
|
||||
char temp[1024];
|
||||
strcpy(temp, fname.c_str());
|
||||
temp[fname.length() - 4] = 0;
|
||||
char groupFileName[1024];
|
||||
sprintf(groupFileName, "%s_%03d.wmo", temp, i);
|
||||
|
||||
string s(groupFileName);
|
||||
|
||||
WMOGroup fgroup(s);
|
||||
if (!fgroup.open())
|
||||
{
|
||||
printf("Could not open all Group file for: %s\n", plain_name.c_str());
|
||||
file_ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData, iCoreNumber);
|
||||
}
|
||||
}
|
||||
|
||||
fseek(output, 8, SEEK_SET); // store the correct no of vertices
|
||||
fwrite(&Wmo_nVertices, sizeof(int), 1, output);
|
||||
fclose(output);
|
||||
|
||||
// Delete the extracted file in the case of an error
|
||||
if (!file_ok)
|
||||
{
|
||||
remove(szLocalFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractWmo(int iCoreNumber, const void *szRawVMAPMagic)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
for (ArchiveSet::const_iterator ar_itr = gOpenArchives.begin(); ar_itr != gOpenArchives.end() && success; ++ar_itr)
|
||||
{
|
||||
vector<std::string> filelist;
|
||||
|
||||
(*ar_itr)->GetFileListTo(filelist);
|
||||
for (vector<std::string>::iterator fname = filelist.begin(); fname != filelist.end() && success; ++fname)
|
||||
{
|
||||
if (fname->find(".wmo") != string::npos)
|
||||
{
|
||||
ExtractSingleWmo(*fname, iCoreNumber, szRawVMAPMagic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
printf("\n Extraction of WMO's complete, No fatal errors\n");
|
||||
}
|
||||
{ printf("\n Reading Maps\n"); }
|
||||
{ printf(" _______________________________________________________\n"); }
|
||||
|
||||
return success;
|
||||
}
|
||||
227
src/tools/Extractor_projects/vmap-extractor/wmo.h
Normal file
227
src/tools/Extractor_projects/vmap-extractor/wmo.h
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/**
|
||||
* MaNGOS is a full featured server for World of Warcraft, supporting
|
||||
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
|
||||
*
|
||||
* Copyright (C) 2005-2020 MaNGOS <https://getmangos.eu>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
|
||||
* and lore are copyrighted by Blizzard Entertainment, Inc.
|
||||
*/
|
||||
|
||||
#ifndef WMO_H
|
||||
#define WMO_H
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "vec3d.h"
|
||||
#include <ml/mpq.h>
|
||||
#include <ml/loadlib.h>
|
||||
|
||||
// MOPY flags
|
||||
#define WMO_MATERIAL_NOCAMCOLLIDE 0x01
|
||||
#define WMO_MATERIAL_DETAIL 0x02
|
||||
#define WMO_MATERIAL_NO_COLLISION 0x04
|
||||
#define WMO_MATERIAL_HINT 0x08
|
||||
#define WMO_MATERIAL_RENDER 0x10
|
||||
#define WMO_MATERIAL_COLLIDE_HIT 0x20
|
||||
#define WMO_MATERIAL_WALL_SURFACE 0x40
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class WMORoot
|
||||
{
|
||||
public:
|
||||
uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType; /**< TODO */
|
||||
unsigned int col; /**< TODO */
|
||||
float bbcorn1[3]; /**< TODO */
|
||||
float bbcorn2[3]; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param filename
|
||||
*/
|
||||
WMORoot(std::string& filename);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~WMORoot();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool open();
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param output
|
||||
* @return bool
|
||||
*/
|
||||
bool ConvertToVMAPRootWmo(FILE* output, const void *szRawVMAPMagic);
|
||||
private:
|
||||
std::string filename; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct WMOLiquidHeader
|
||||
{
|
||||
int xverts, yverts, xtiles, ytiles; /**< TODO */
|
||||
float pos_x; /**< TODO */
|
||||
float pos_y; /**< TODO */
|
||||
float pos_z; /**< TODO */
|
||||
short type; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
struct WMOLiquidVert
|
||||
{
|
||||
uint16 unk1; /**< TODO */
|
||||
uint16 unk2; /**< TODO */
|
||||
float height; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class WMOGroup
|
||||
{
|
||||
public:
|
||||
// MOGP
|
||||
int groupName, descGroupName, mogpFlags; /**< TODO */
|
||||
float bbcorn1[3]; /**< TODO */
|
||||
float bbcorn2[3]; /**< TODO */
|
||||
uint16 moprIdx; /**< TODO */
|
||||
uint16 moprNItems; /**< TODO */
|
||||
uint16 nBatchA; /**< TODO */
|
||||
uint16 nBatchB; /**< TODO */
|
||||
uint32 nBatchC, fogIdx, liquidType, groupWMOID; /**< TODO */
|
||||
|
||||
int mopy_size, moba_size; /**< TODO */
|
||||
int LiquEx_size; /**< TODO */
|
||||
unsigned int nVertices; /**< number when loaded */
|
||||
int nTriangles; /**< number when loaded */
|
||||
char* MOPY; /**< TODO */
|
||||
uint16* MOVI; /**< TODO */
|
||||
uint16* MoviEx; /**< TODO */
|
||||
float* MOVT; /**< TODO */
|
||||
uint16* MOBA; /**< TODO */
|
||||
int* MobaEx; /**< TODO */
|
||||
WMOLiquidHeader* hlq; /**< TODO */
|
||||
WMOLiquidVert* LiquEx; /**< TODO */
|
||||
char* LiquBytes; /**< TODO */
|
||||
uint32 liquflags; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param filename
|
||||
*/
|
||||
WMOGroup(std::string& filename);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
~WMOGroup();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
bool open();
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param output
|
||||
* @param rootWMO
|
||||
* @param pPreciseVectorData
|
||||
* @return int
|
||||
*/
|
||||
int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool pPreciseVectorData, int iCoreNumber);
|
||||
|
||||
private:
|
||||
std::string filename; /**< TODO */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
class WMOInstance
|
||||
{
|
||||
static std::set<int> ids; /**< TODO */
|
||||
public:
|
||||
std::string MapName; /**< TODO */
|
||||
int currx; /**< TODO */
|
||||
int curry; /**< TODO */
|
||||
WMOGroup* wmo; /**< TODO */
|
||||
Vec3D pos; /**< TODO */
|
||||
Vec3D pos2, pos3, rot; /**< TODO */
|
||||
uint32 indx, id, d2, d3; /**< TODO */
|
||||
int doodadset; /**< TODO */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param f
|
||||
* @param WmoInstName
|
||||
* @param mapID
|
||||
* @param tileX
|
||||
* @param tileY
|
||||
* @param pDirfile
|
||||
*/
|
||||
WMOInstance(MPQFile& f, std::string& WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
static void reset();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param fname
|
||||
* @return bool
|
||||
*/
|
||||
bool ExtractSingleWmo(std::string& fname, int iCoreNumber, const void *szRawVMAPMagic);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param
|
||||
* @return bool
|
||||
*/
|
||||
bool ExtractWmo(int iCoreNumber, const void *szRawVMAPMagic);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue