mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 01:08:35 +00:00
Directory Structure [step 1]: moving files
working on #672 NOTE: This commit can't be compiled!!
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
add_subdirectory(map_extractor)
|
||||
add_subdirectory(vmap4_assembler)
|
||||
add_subdirectory(vmap4_extractor)
|
||||
add_subdirectory(mmaps_generator)
|
||||
if (WITH_MESHEXTRACTOR)
|
||||
add_subdirectory(mesh_extractor)
|
||||
endif()
|
||||
@@ -1,44 +0,0 @@
|
||||
# Copyright (C)
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
file(GLOB_RECURSE sources *.cpp *.h)
|
||||
|
||||
set(include_Dirs
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/loadlib
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
set(include_Dirs
|
||||
${include_Dirs}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq/win
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${include_Dirs})
|
||||
|
||||
add_executable(mapextractor
|
||||
${sources}
|
||||
)
|
||||
|
||||
target_link_libraries(mapextractor
|
||||
mpq
|
||||
${BZIP2_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS mapextractor DESTINATION bin)
|
||||
elseif( WIN32 )
|
||||
install(TARGETS mapextractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "adt.h"
|
||||
|
||||
// Helper
|
||||
int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888};
|
||||
int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000};
|
||||
|
||||
u_map_fcc MHDRMagic = { {'R','D','H','M'} };
|
||||
u_map_fcc MCINMagic = { {'N','I','C','M'} };
|
||||
u_map_fcc MH2OMagic = { {'O','2','H','M'} };
|
||||
u_map_fcc MCNKMagic = { {'K','N','C','M'} };
|
||||
u_map_fcc MCVTMagic = { {'T','V','C','M'} };
|
||||
u_map_fcc MCLQMagic = { {'Q','L','C','M'} };
|
||||
|
||||
bool isHole(int holes, int i, int j)
|
||||
{
|
||||
int testi = i / 2;
|
||||
int testj = j / 4;
|
||||
if(testi > 3) testi = 3;
|
||||
if(testj > 3) testj = 3;
|
||||
return (holes & holetab_h[testi] & holetab_v[testj]) != 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Adt file loader class
|
||||
//
|
||||
ADT_file::ADT_file()
|
||||
{
|
||||
a_grid = 0;
|
||||
}
|
||||
|
||||
ADT_file::~ADT_file()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void ADT_file::free()
|
||||
{
|
||||
a_grid = 0;
|
||||
FileLoader::free();
|
||||
}
|
||||
|
||||
//
|
||||
// Adt file check function
|
||||
//
|
||||
bool ADT_file::prepareLoadedData()
|
||||
{
|
||||
// Check parent
|
||||
if (!FileLoader::prepareLoadedData())
|
||||
return false;
|
||||
|
||||
// Check and prepare MHDR
|
||||
a_grid = (adt_MHDR *)(GetData()+8+version->size);
|
||||
if (!a_grid->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MHDR::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MHDRMagic.fcc)
|
||||
return false;
|
||||
|
||||
if (size!=sizeof(adt_MHDR)-8)
|
||||
return false;
|
||||
|
||||
// Check and prepare MCIN
|
||||
if (offsMCIN && !getMCIN()->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
// Check and prepare MH2O
|
||||
if (offsMH2O && !getMH2O()->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCIN::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MCINMagic.fcc)
|
||||
return false;
|
||||
|
||||
// Check cells data
|
||||
for (int i=0; i<ADT_CELLS_PER_GRID;i++)
|
||||
for (int j=0; j<ADT_CELLS_PER_GRID;j++)
|
||||
if (cells[i][j].offsMCNK && !getMCNK(i,j)->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MH2O::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MH2OMagic.fcc)
|
||||
return false;
|
||||
|
||||
// Check liquid data
|
||||
// for (int i=0; i<ADT_CELLS_PER_GRID;i++)
|
||||
// for (int j=0; j<ADT_CELLS_PER_GRID;j++)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCNK::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MCNKMagic.fcc)
|
||||
return false;
|
||||
|
||||
// Check height map
|
||||
if (offsMCVT && !getMCVT()->prepareLoadedData())
|
||||
return false;
|
||||
// Check liquid data
|
||||
if (offsMCLQ && !getMCLQ()->prepareLoadedData())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCVT::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MCVTMagic.fcc)
|
||||
return false;
|
||||
|
||||
if (size != sizeof(adt_MCVT)-8)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool adt_MCLQ::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MCLQMagic.fcc)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
|
||||
#include "loadlib.h"
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
#define UNITSIZE (CHUNKSIZE / 8.0f)
|
||||
|
||||
enum LiquidType
|
||||
{
|
||||
LIQUID_TYPE_WATER = 0,
|
||||
LIQUID_TYPE_OCEAN = 1,
|
||||
LIQUID_TYPE_MAGMA = 2,
|
||||
LIQUID_TYPE_SLIME = 3
|
||||
};
|
||||
|
||||
//**************************************************************************************
|
||||
// ADT file class
|
||||
//**************************************************************************************
|
||||
#define ADT_CELLS_PER_GRID 16
|
||||
#define ADT_CELL_SIZE 8
|
||||
#define ADT_GRID_SIZE (ADT_CELLS_PER_GRID*ADT_CELL_SIZE)
|
||||
|
||||
//
|
||||
// Adt file height map chunk
|
||||
//
|
||||
class adt_MCVT
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
public:
|
||||
float height_map[(ADT_CELL_SIZE+1)*(ADT_CELL_SIZE+1)+ADT_CELL_SIZE*ADT_CELL_SIZE];
|
||||
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file liquid map chunk (old)
|
||||
//
|
||||
class adt_MCLQ
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
float height1;
|
||||
float height2;
|
||||
struct liquid_data{
|
||||
uint32 light;
|
||||
float height;
|
||||
} liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1];
|
||||
|
||||
// 1<<0 - ochen
|
||||
// 1<<1 - lava/slime
|
||||
// 1<<2 - water
|
||||
// 1<<6 - all water
|
||||
// 1<<7 - dark water
|
||||
// == 0x0F - not show liquid
|
||||
uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE];
|
||||
uint8 data[84];
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file cell chunk
|
||||
//
|
||||
class adt_MCNK
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
uint32 flags;
|
||||
uint32 ix;
|
||||
uint32 iy;
|
||||
uint32 nLayers;
|
||||
uint32 nDoodadRefs;
|
||||
uint32 offsMCVT; // height map
|
||||
uint32 offsMCNR; // Normal vectors for each vertex
|
||||
uint32 offsMCLY; // Texture layer definitions
|
||||
uint32 offsMCRF; // A list of indices into the parent file's MDDF chunk
|
||||
uint32 offsMCAL; // Alpha maps for additional texture layers
|
||||
uint32 sizeMCAL;
|
||||
uint32 offsMCSH; // Shadow map for static shadows on the terrain
|
||||
uint32 sizeMCSH;
|
||||
uint32 areaid;
|
||||
uint32 nMapObjRefs;
|
||||
uint32 holes;
|
||||
uint16 s[2];
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32 data3;
|
||||
uint32 predTex;
|
||||
uint32 nEffectDoodad;
|
||||
uint32 offsMCSE;
|
||||
uint32 nSndEmitters;
|
||||
uint32 offsMCLQ; // Liqid level (old)
|
||||
uint32 sizeMCLQ; //
|
||||
float zpos;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint32 offsMCCV; // offsColorValues in WotLK
|
||||
uint32 props;
|
||||
uint32 effectId;
|
||||
|
||||
bool prepareLoadedData();
|
||||
adt_MCVT *getMCVT()
|
||||
{
|
||||
if (offsMCVT)
|
||||
return (adt_MCVT *)((uint8 *)this + offsMCVT);
|
||||
return 0;
|
||||
}
|
||||
adt_MCLQ *getMCLQ()
|
||||
{
|
||||
if (offsMCLQ)
|
||||
return (adt_MCLQ *)((uint8 *)this + offsMCLQ);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file grid chunk
|
||||
//
|
||||
class adt_MCIN
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
struct adt_CELLS{
|
||||
uint32 offsMCNK;
|
||||
uint32 size;
|
||||
uint32 flags;
|
||||
uint32 asyncId;
|
||||
} cells[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
||||
|
||||
bool prepareLoadedData();
|
||||
// offset from begin file (used this-84)
|
||||
adt_MCNK *getMCNK(int x, int y)
|
||||
{
|
||||
if (cells[x][y].offsMCNK)
|
||||
return (adt_MCNK *)((uint8 *)this + cells[x][y].offsMCNK - 84);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#define ADT_LIQUID_HEADER_FULL_LIGHT 0x01
|
||||
#define ADT_LIQUID_HEADER_NO_HIGHT 0x02
|
||||
|
||||
struct adt_liquid_header{
|
||||
uint16 liquidType; // Index from LiquidType.dbc
|
||||
uint16 formatFlags;
|
||||
float heightLevel1;
|
||||
float heightLevel2;
|
||||
uint8 xOffset;
|
||||
uint8 yOffset;
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
uint32 offsData2a;
|
||||
uint32 offsData2b;
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file liquid data chunk (new)
|
||||
//
|
||||
class adt_MH2O
|
||||
{
|
||||
public:
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
|
||||
struct adt_LIQUID{
|
||||
uint32 offsData1;
|
||||
uint32 used;
|
||||
uint32 offsData2;
|
||||
} liquid[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
|
||||
|
||||
bool prepareLoadedData();
|
||||
|
||||
adt_liquid_header *getLiquidData(int x, int y)
|
||||
{
|
||||
if (liquid[x][y].used && liquid[x][y].offsData1)
|
||||
return (adt_liquid_header *)((uint8*)this + 8 + liquid[x][y].offsData1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float *getLiquidHeightMap(adt_liquid_header *h)
|
||||
{
|
||||
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
|
||||
return 0;
|
||||
if (h->offsData2b)
|
||||
return (float *)((uint8*)this + 8 + h->offsData2b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 *getLiquidLightMap(adt_liquid_header *h)
|
||||
{
|
||||
if (h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT)
|
||||
return 0;
|
||||
if (h->offsData2b)
|
||||
{
|
||||
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
|
||||
return (uint8 *)((uint8*)this + 8 + h->offsData2b);
|
||||
return (uint8 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 *getLiquidFullLightMap(adt_liquid_header *h)
|
||||
{
|
||||
if (!(h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT))
|
||||
return 0;
|
||||
if (h->offsData2b)
|
||||
{
|
||||
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
|
||||
return (uint32 *)((uint8*)this + 8 + h->offsData2b);
|
||||
return (uint32 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64 getLiquidShowMap(adt_liquid_header *h)
|
||||
{
|
||||
if (h->offsData2a)
|
||||
return *((uint64 *)((uint8*)this + 8 + h->offsData2a));
|
||||
else
|
||||
return 0xFFFFFFFFFFFFFFFFuLL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// Adt file header chunk
|
||||
//
|
||||
class adt_MHDR
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
|
||||
uint32 pad;
|
||||
uint32 offsMCIN; // MCIN
|
||||
uint32 offsTex; // MTEX
|
||||
uint32 offsModels; // MMDX
|
||||
uint32 offsModelsIds; // MMID
|
||||
uint32 offsMapObejcts; // MWMO
|
||||
uint32 offsMapObejctsIds; // MWID
|
||||
uint32 offsDoodsDef; // MDDF
|
||||
uint32 offsObjectsDef; // MODF
|
||||
uint32 offsMFBO; // MFBO
|
||||
uint32 offsMH2O; // MH2O
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32 data3;
|
||||
uint32 data4;
|
||||
uint32 data5;
|
||||
public:
|
||||
bool prepareLoadedData();
|
||||
adt_MCIN *getMCIN(){ return (adt_MCIN *)((uint8 *)&pad+offsMCIN);}
|
||||
adt_MH2O *getMH2O(){ return offsMH2O ? (adt_MH2O *)((uint8 *)&pad+offsMH2O) : 0;}
|
||||
|
||||
};
|
||||
|
||||
class ADT_file : public FileLoader{
|
||||
public:
|
||||
bool prepareLoadedData();
|
||||
ADT_file();
|
||||
~ADT_file();
|
||||
void free();
|
||||
|
||||
adt_MHDR *a_grid;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "dbcfile.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
|
||||
DBCFile::DBCFile(const std::string& filename):
|
||||
filename(filename), recordSize(0), recordCount(0), fieldCount(0), stringSize(0), data(NULL), stringTable(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool DBCFile::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
char header[4];
|
||||
unsigned int na,nb,es,ss;
|
||||
|
||||
if(f.read(header,4)!=4) // Number of records
|
||||
return false;
|
||||
|
||||
if(header[0]!='W' || header[1]!='D' || header[2]!='B' || header[3]!='C')
|
||||
return false;
|
||||
|
||||
if(f.read(&na,4)!=4) // Number of records
|
||||
return false;
|
||||
if(f.read(&nb,4)!=4) // Number of fields
|
||||
return false;
|
||||
if(f.read(&es,4)!=4) // Size of a record
|
||||
return false;
|
||||
if(f.read(&ss,4)!=4) // String size
|
||||
return false;
|
||||
|
||||
recordSize = es;
|
||||
recordCount = na;
|
||||
fieldCount = nb;
|
||||
stringSize = ss;
|
||||
if(fieldCount*4 != recordSize)
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef DBCFILE_H
|
||||
#define DBCFILE_H
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
DBCFile(const std::string &filename);
|
||||
~DBCFile();
|
||||
|
||||
// Open database. It must be openened before it can be used.
|
||||
bool open();
|
||||
|
||||
// Database exceptions
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &message): message(message)
|
||||
{ }
|
||||
virtual ~Exception()
|
||||
{ }
|
||||
const std::string &getMessage() {return message;}
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
class NotFound: public Exception
|
||||
{
|
||||
public:
|
||||
NotFound(): Exception("Key was not found")
|
||||
{ }
|
||||
};
|
||||
// Iteration over database
|
||||
class Iterator;
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
float getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset+field*4);
|
||||
}
|
||||
unsigned int getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset+field*4);
|
||||
}
|
||||
int getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset+field*4);
|
||||
}
|
||||
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:
|
||||
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
|
||||
DBCFile &file;
|
||||
unsigned char *offset;
|
||||
|
||||
friend class DBCFile;
|
||||
friend class DBCFile::Iterator;
|
||||
};
|
||||
/** Iterator that iterates over records
|
||||
*/
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(DBCFile &file, unsigned char *offset):
|
||||
record(file, offset) {}
|
||||
/// Advance (prefix only)
|
||||
Iterator & operator++() {
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/// Return address of current instance
|
||||
Record const & operator*() const { return record; }
|
||||
const Record* operator->() const {
|
||||
return &record;
|
||||
}
|
||||
/// Comparison
|
||||
bool operator==(const Iterator &b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
bool operator!=(const Iterator &b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record;
|
||||
};
|
||||
|
||||
// Get record by id
|
||||
Record getRecord(size_t id);
|
||||
/// Get begin iterator over records
|
||||
Iterator begin();
|
||||
/// Get begin iterator over records
|
||||
Iterator end();
|
||||
/// Trivial
|
||||
size_t getRecordCount() const { return recordCount;}
|
||||
size_t getFieldCount() const { return fieldCount; }
|
||||
size_t getMaxId();
|
||||
private:
|
||||
std::string filename;
|
||||
size_t recordSize;
|
||||
size_t recordCount;
|
||||
size_t fieldCount;
|
||||
size_t stringSize;
|
||||
unsigned char *data;
|
||||
unsigned char *stringTable;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "loadlib.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
#include <cstdio>
|
||||
|
||||
class MPQFile;
|
||||
|
||||
u_map_fcc MverMagic = { {'R','E','V','M'} };
|
||||
|
||||
FileLoader::FileLoader()
|
||||
{
|
||||
data = 0;
|
||||
data_size = 0;
|
||||
version = 0;
|
||||
}
|
||||
|
||||
FileLoader::~FileLoader()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
bool FileLoader::loadFile(char *filename, bool log)
|
||||
{
|
||||
free();
|
||||
MPQFile mf(filename);
|
||||
if(mf.isEof())
|
||||
{
|
||||
if (log)
|
||||
printf("No such file %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
data_size = mf.getSize();
|
||||
|
||||
data = new uint8 [data_size];
|
||||
mf.read(data, data_size);
|
||||
mf.close();
|
||||
if (prepareLoadedData())
|
||||
return true;
|
||||
|
||||
printf("Error loading %s", filename);
|
||||
mf.close();
|
||||
free();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileLoader::prepareLoadedData()
|
||||
{
|
||||
// Check version
|
||||
version = (file_MVER *) data;
|
||||
if (version->fcc != MverMagic.fcc)
|
||||
return false;
|
||||
if (version->ver != FILE_FORMAT_VERSION)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileLoader::free()
|
||||
{
|
||||
if (data) delete[] data;
|
||||
data = 0;
|
||||
data_size = 0;
|
||||
version = 0;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef LOAD_LIB_H
|
||||
#define LOAD_LIB_H
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef __int64 int64;
|
||||
typedef __int32 int32;
|
||||
typedef __int16 int16;
|
||||
typedef __int8 int8;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef unsigned __int16 uint16;
|
||||
typedef unsigned __int8 uint8;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#ifndef uint64_t
|
||||
#ifdef __linux__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#endif
|
||||
typedef int64_t int64;
|
||||
typedef int32_t int32;
|
||||
typedef int16_t int16;
|
||||
typedef int8_t int8;
|
||||
typedef uint64_t uint64;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint8_t uint8;
|
||||
#endif
|
||||
|
||||
#define FILE_FORMAT_VERSION 18
|
||||
|
||||
union u_map_fcc
|
||||
{
|
||||
char fcc_txt[4];
|
||||
uint32 fcc;
|
||||
};
|
||||
|
||||
//
|
||||
// File version chunk
|
||||
//
|
||||
struct file_MVER
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
uint32 ver;
|
||||
};
|
||||
|
||||
class FileLoader{
|
||||
uint8 *data;
|
||||
uint32 data_size;
|
||||
public:
|
||||
virtual bool prepareLoadedData();
|
||||
uint8 *GetData() {return data;}
|
||||
uint32 GetDataSize() {return data_size;}
|
||||
|
||||
file_MVER *version;
|
||||
FileLoader();
|
||||
~FileLoader();
|
||||
bool loadFile(char *filename, bool log = true);
|
||||
virtual void free();
|
||||
};
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "mpq_libmpq04.h"
|
||||
#include <deque>
|
||||
#include <cstdio>
|
||||
|
||||
ArchiveSet gOpenArchives;
|
||||
|
||||
MPQArchive::MPQArchive(const char* filename)
|
||||
{
|
||||
int result = libmpq__archive_open(&mpq_a, filename, -1);
|
||||
printf("Opening %s\n", filename);
|
||||
if(result) {
|
||||
switch(result) {
|
||||
case LIBMPQ_ERROR_OPEN :
|
||||
printf("Error opening archive '%s': Does file really exist?\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_FORMAT : /* bad file format */
|
||||
printf("Error opening archive '%s': Bad file format\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_SEEK : /* seeking in file failed */
|
||||
printf("Error opening archive '%s': Seeking in file failed\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_READ : /* Read error in archive */
|
||||
printf("Error opening archive '%s': Read error in archive\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */
|
||||
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
|
||||
break;
|
||||
default:
|
||||
printf("Error opening archive '%s': Unknown error\n", filename);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
gOpenArchives.push_front(this);
|
||||
}
|
||||
|
||||
void MPQArchive::close()
|
||||
{
|
||||
//gOpenArchives.erase(erase(&mpq_a);
|
||||
libmpq__archive_close(mpq_a);
|
||||
}
|
||||
|
||||
MPQFile::MPQFile(const char* filename):
|
||||
eof(false),
|
||||
buffer(0),
|
||||
pointer(0),
|
||||
size(0)
|
||||
{
|
||||
for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i)
|
||||
{
|
||||
mpq_archive *mpq_a = (*i)->mpq_a;
|
||||
|
||||
uint32_t filenum;
|
||||
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
|
||||
libmpq__off_t transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
|
||||
if (size<=1) {
|
||||
// printf("warning: file %s has size %d; cannot read.\n", filename, size);
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
return;
|
||||
}
|
||||
buffer = new char[size];
|
||||
|
||||
//libmpq_file_getdata
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
/*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/
|
||||
return;
|
||||
|
||||
}
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
size_t MPQFile::read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof) return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > size_t(size)) {
|
||||
bytes = size - pointer;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
memcpy(dest, &(buffer[pointer]), bytes);
|
||||
|
||||
pointer = rpos;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void MPQFile::seek(int offset)
|
||||
{
|
||||
pointer = offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::seekRelative(int offset)
|
||||
{
|
||||
pointer += offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::close()
|
||||
{
|
||||
if (buffer) delete[] buffer;
|
||||
buffer = 0;
|
||||
eof = true;
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MPQ_H
|
||||
#define MPQ_H
|
||||
|
||||
#include "loadlib/loadlib.h"
|
||||
#include "libmpq/mpq.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MPQArchive
|
||||
{
|
||||
|
||||
public:
|
||||
mpq_archive_s *mpq_a;
|
||||
|
||||
MPQArchive(const char* filename);
|
||||
~MPQArchive() { close(); }
|
||||
void close();
|
||||
|
||||
void GetFileListTo(vector<string>& filelist) {
|
||||
uint32_t filenum;
|
||||
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
|
||||
libmpq__off_t size, transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
char *buffer = new char[size+1];
|
||||
buffer[size] = '\0';
|
||||
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
|
||||
char seps[] = "\n";
|
||||
char *token;
|
||||
|
||||
token = strtok( buffer, seps );
|
||||
uint32 counter = 0;
|
||||
while ((token != NULL) && (counter < size)) {
|
||||
//cout << token << endl;
|
||||
token[strlen(token) - 1] = 0;
|
||||
string s = token;
|
||||
filelist.push_back(s);
|
||||
counter += strlen(token) + 2;
|
||||
token = strtok(NULL, seps);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
typedef std::deque<MPQArchive*> ArchiveSet;
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
//MPQHANDLE handle;
|
||||
bool eof;
|
||||
char *buffer;
|
||||
libmpq__off_t pointer,size;
|
||||
|
||||
// disable copying
|
||||
MPQFile(const MPQFile& /*f*/) {}
|
||||
void operator=(const MPQFile& /*f*/) {}
|
||||
|
||||
public:
|
||||
MPQFile(const char* filename); // filenames are not case sensitive
|
||||
~MPQFile() { close(); }
|
||||
size_t read(void* dest, size_t bytes);
|
||||
size_t getSize() { return size; }
|
||||
size_t getPos() { return pointer; }
|
||||
char* getBuffer() { return buffer; }
|
||||
char* getPointer() { return buffer + pointer; }
|
||||
bool isEof() { return eof; }
|
||||
void seek(int offset);
|
||||
void seekRelative(int offset);
|
||||
void close();
|
||||
};
|
||||
|
||||
inline void flipcc(char *fcc)
|
||||
{
|
||||
char t;
|
||||
t=fcc[0];
|
||||
fcc[0]=fcc[3];
|
||||
fcc[3]=t;
|
||||
t=fcc[1];
|
||||
fcc[1]=fcc[2];
|
||||
fcc[2]=t;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include "wdt.h"
|
||||
|
||||
u_map_fcc MWMOMagic = { {'O', 'M', 'W', 'M'} };
|
||||
u_map_fcc MPHDMagic = { {'D', 'H', 'P', 'M'} };
|
||||
u_map_fcc MAINMagic = { {'N', 'I', 'A', 'M'} };
|
||||
|
||||
bool wdt_MWMO::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MWMOMagic.fcc)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wdt_MPHD::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MPHDMagic.fcc)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wdt_MAIN::prepareLoadedData()
|
||||
{
|
||||
if (fcc != MAINMagic.fcc)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
WDT_file::WDT_file()
|
||||
{
|
||||
mphd = 0;
|
||||
main = 0;
|
||||
wmo = 0;
|
||||
}
|
||||
|
||||
WDT_file::~WDT_file()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void WDT_file::free()
|
||||
{
|
||||
mphd = 0;
|
||||
main = 0;
|
||||
wmo = 0;
|
||||
FileLoader::free();
|
||||
}
|
||||
|
||||
bool WDT_file::prepareLoadedData()
|
||||
{
|
||||
// Check parent
|
||||
if (!FileLoader::prepareLoadedData())
|
||||
return false;
|
||||
|
||||
mphd = (wdt_MPHD *)((uint8*)version+version->size+8);
|
||||
if (!mphd->prepareLoadedData())
|
||||
return false;
|
||||
main = (wdt_MAIN *)((uint8*)mphd + mphd->size+8);
|
||||
if (!main->prepareLoadedData())
|
||||
return false;
|
||||
wmo = (wdt_MWMO *)((uint8*)main+ main->size+8);
|
||||
if (!wmo->prepareLoadedData())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WDT_H
|
||||
#define WDT_H
|
||||
#include "loadlib.h"
|
||||
|
||||
//**************************************************************************************
|
||||
// WDT file class and structures
|
||||
//**************************************************************************************
|
||||
#define WDT_MAP_SIZE 64
|
||||
|
||||
class wdt_MWMO{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
class wdt_MPHD{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
|
||||
uint32 data1;
|
||||
uint32 data2;
|
||||
uint32 data3;
|
||||
uint32 data4;
|
||||
uint32 data5;
|
||||
uint32 data6;
|
||||
uint32 data7;
|
||||
uint32 data8;
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
class wdt_MAIN{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
public:
|
||||
uint32 size;
|
||||
|
||||
struct adtData{
|
||||
uint32 exist;
|
||||
uint32 data1;
|
||||
} adt_list[64][64];
|
||||
|
||||
bool prepareLoadedData();
|
||||
};
|
||||
|
||||
class WDT_file : public FileLoader{
|
||||
public:
|
||||
bool prepareLoadedData();
|
||||
|
||||
WDT_file();
|
||||
~WDT_file();
|
||||
void free();
|
||||
|
||||
wdt_MPHD *mphd;
|
||||
wdt_MAIN *main;
|
||||
wdt_MWMO *wmo;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "ADT.h"
|
||||
#include "DoodadHandler.h"
|
||||
#include "LiquidHandler.h"
|
||||
#include "WorldModelHandler.h"
|
||||
|
||||
ADT::ADT( std::string file, int x, int y ) : ObjectData(NULL), Data(NULL), HasObjectData(false),
|
||||
_DoodadHandler(NULL), _WorldModelHandler(NULL), _LiquidHandler(NULL), X(x), Y(y)
|
||||
{
|
||||
Data = new ChunkedData(file);
|
||||
ObjectData = new ChunkedData(file);
|
||||
if (ObjectData->Stream)
|
||||
HasObjectData = true;
|
||||
else
|
||||
ObjectData = NULL;
|
||||
}
|
||||
|
||||
ADT::~ADT()
|
||||
{
|
||||
delete ObjectData;
|
||||
delete Data;
|
||||
|
||||
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
|
||||
delete *itr;
|
||||
|
||||
MapChunks.clear();
|
||||
delete _DoodadHandler;
|
||||
delete _WorldModelHandler;
|
||||
delete _LiquidHandler;
|
||||
}
|
||||
|
||||
void ADT::Read()
|
||||
{
|
||||
Header.Read(Data->GetChunkByName("MHDR")->GetStream());
|
||||
MapChunks.reserve(16 * 16);
|
||||
|
||||
for (std::vector<Chunk*>::iterator itr = Data->Chunks.begin(); itr != Data->Chunks.end(); ++itr)
|
||||
if ((*itr)->Name == "MCNK")
|
||||
MapChunks.push_back(new MapChunk(this, *itr));
|
||||
|
||||
_LiquidHandler = new LiquidHandler(this);
|
||||
|
||||
// do this separate from map chunk initialization to access liquid data
|
||||
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
|
||||
(*itr)->GenerateTriangles();
|
||||
|
||||
_DoodadHandler = new DoodadHandler(this);
|
||||
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
|
||||
_DoodadHandler->ProcessMapChunk(*itr);
|
||||
|
||||
_WorldModelHandler = new WorldModelHandler(this);
|
||||
for (std::vector<MapChunk*>::iterator itr = MapChunks.begin(); itr != MapChunks.end(); ++itr)
|
||||
_WorldModelHandler->ProcessMapChunk(*itr);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
#include "ChunkedData.h"
|
||||
#include "MapChunk.h"
|
||||
|
||||
class DoodadHandler;
|
||||
class WorldModelHandler;
|
||||
class LiquidHandler;
|
||||
|
||||
class ADT
|
||||
{
|
||||
public:
|
||||
ADT(std::string file, int x, int y);
|
||||
~ADT();
|
||||
|
||||
void Read();
|
||||
|
||||
ChunkedData* ObjectData;
|
||||
ChunkedData* Data;
|
||||
std::vector<MapChunk*> MapChunks;
|
||||
MHDR Header;
|
||||
// Can we dispose of this?
|
||||
bool HasObjectData;
|
||||
|
||||
DoodadHandler* _DoodadHandler;
|
||||
WorldModelHandler* _WorldModelHandler;
|
||||
LiquidHandler* _LiquidHandler;
|
||||
|
||||
int X;
|
||||
int Y;
|
||||
};
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
# Copyright (C)
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
file(GLOB_RECURSE meshExtract_Sources *.cpp *.h)
|
||||
|
||||
set(include_Base
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||
${ACE_INCLUDE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
set(include_Base
|
||||
${include_Base}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq/win
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${include_Base})
|
||||
|
||||
add_executable(MeshExtractor ${meshExtract_Sources})
|
||||
|
||||
target_link_libraries(MeshExtractor
|
||||
g3dlib
|
||||
mpq
|
||||
Recast
|
||||
Detour
|
||||
${BZIP2_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${ACE_LIBRARY}
|
||||
)
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS MeshExtractor DESTINATION bin)
|
||||
elseif( WIN32 )
|
||||
install(TARGETS MeshExtractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "Define.h"
|
||||
#include <ace/Guard_T.h>
|
||||
#include <ace/Synch.h>
|
||||
#include "WorldModelRoot.h"
|
||||
#include "Model.h"
|
||||
|
||||
template<class K, class T>
|
||||
class GenericCache
|
||||
{
|
||||
public:
|
||||
GenericCache() {}
|
||||
|
||||
static const uint32 FlushLimit = 300; // We can't get too close to filling up all the memory, and we have to be wary of the maximum number of open streams.
|
||||
|
||||
void Insert(K key, T* val)
|
||||
{
|
||||
ACE_GUARD(ACE_Thread_Mutex, g, mutex);
|
||||
|
||||
if (_items.size() > FlushLimit)
|
||||
Clear();
|
||||
_items[key] = val;
|
||||
}
|
||||
|
||||
T* Get(K key)
|
||||
{
|
||||
ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
|
||||
typename std::map<K, T*>::iterator itr = _items.find(key);
|
||||
if (itr != _items.end())
|
||||
return itr->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (typename std::map<K, T*>::iterator itr = _items.begin(); itr != _items.end(); ++itr)
|
||||
delete itr->second;
|
||||
_items.clear();
|
||||
}
|
||||
private:
|
||||
std::map<K, T*> _items;
|
||||
ACE_Thread_Mutex mutex;
|
||||
};
|
||||
|
||||
class CacheClass
|
||||
{
|
||||
public:
|
||||
CacheClass() {}
|
||||
GenericCache<std::string, Model> ModelCache;
|
||||
GenericCache<std::string, WorldModelRoot> WorldModelCache;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
ModelCache.Clear();
|
||||
WorldModelCache.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
extern CacheClass* Cache;
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "Chunk.h"
|
||||
#include "Utils.h"
|
||||
|
||||
int32 Chunk::FindSubChunkOffset(std::string name)
|
||||
{
|
||||
// Reverse the name
|
||||
name = std::string(name.rbegin(), name.rend());
|
||||
if (name.size() != 4)
|
||||
return -1;
|
||||
|
||||
FILE* stream = GetStream();
|
||||
uint32 matched = 0;
|
||||
while (uint32(ftell(stream)) < Utils::Size(stream))
|
||||
{
|
||||
char b = 0;
|
||||
if (fread(&b, sizeof(char), 1, stream) != 1 || b != name[matched])
|
||||
matched = 0;
|
||||
else
|
||||
++matched;
|
||||
|
||||
if (matched == 4)
|
||||
return ftell(stream) - 4;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* Chunk::GetStream()
|
||||
{
|
||||
fseek(Stream, Offset, SEEK_SET);
|
||||
return Stream;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef CHUNK_H
|
||||
#define CHUNK_H
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
class ChunkedData;
|
||||
|
||||
class Chunk
|
||||
{
|
||||
public:
|
||||
Chunk(const char* name, uint32 length, uint32 offset, FILE* stream) : Name(name), Length(length), Offset(offset), Stream(stream) {}
|
||||
|
||||
int32 FindSubChunkOffset(std::string name);
|
||||
FILE* GetStream();
|
||||
std::string Name;
|
||||
uint32 Length;
|
||||
uint32 Offset;
|
||||
FILE* Stream;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "ChunkedData.h"
|
||||
#include "MPQManager.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
ChunkedData::ChunkedData( FILE* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) :
|
||||
Stream(stream)
|
||||
{
|
||||
if (!Stream)
|
||||
return;
|
||||
Load(maxLength, chunksHint);
|
||||
}
|
||||
|
||||
ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ )
|
||||
{
|
||||
Stream = MPQHandler->GetFile(file);
|
||||
if (!Stream)
|
||||
return;
|
||||
Load(0, chunksHint);
|
||||
}
|
||||
|
||||
void ChunkedData::Load( uint32 maxLength, uint32 chunksHint )
|
||||
{
|
||||
if (!maxLength)
|
||||
maxLength = Utils::Size(Stream);
|
||||
Chunks.reserve(chunksHint);
|
||||
uint32 baseOffset = ftell(Stream);
|
||||
uint32 calcOffset = 0;
|
||||
while ((calcOffset + baseOffset) < Utils::Size(Stream) && (calcOffset < maxLength))
|
||||
{
|
||||
char nameBytes[5];
|
||||
uint32 read = fread(&nameBytes, sizeof(char), 4, Stream);
|
||||
nameBytes[read] = '\0';
|
||||
std::string name = std::string(nameBytes);
|
||||
// Utils::Reverse(nameBytes);
|
||||
name = std::string(name.rbegin(), name.rend());
|
||||
uint32 length;
|
||||
if (fread(&length, sizeof(uint32), 1, Stream) != 1)
|
||||
continue;
|
||||
calcOffset += 8;
|
||||
Chunks.push_back(new Chunk(name.c_str(), length, calcOffset + baseOffset, Stream));
|
||||
calcOffset += length;
|
||||
// save an extra seek at the end
|
||||
if ((calcOffset + baseOffset) < Utils::Size(Stream) && calcOffset < maxLength)
|
||||
fseek(Stream, length, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
int ChunkedData::GetFirstIndex( const std::string& name )
|
||||
{
|
||||
for (uint32 i = 0; i < Chunks.size(); ++i)
|
||||
if (Chunks[i]->Name == name)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Chunk* ChunkedData::GetChunkByName( const std::string& name )
|
||||
{
|
||||
for (uint32 i = 0; i < Chunks.size(); ++i)
|
||||
if (Chunks[i]->Name == name)
|
||||
return Chunks[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ChunkedData::~ChunkedData()
|
||||
{
|
||||
for (std::vector<Chunk*>::iterator itr = Chunks.begin(); itr != Chunks.end(); ++itr)
|
||||
delete *itr;
|
||||
|
||||
Chunks.clear();
|
||||
if (Stream)
|
||||
fclose(Stream);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef CHNK_H
|
||||
#define CHNK_H
|
||||
|
||||
#include <vector>
|
||||
#include "Chunk.h"
|
||||
|
||||
class ChunkedData
|
||||
{
|
||||
public:
|
||||
ChunkedData(FILE* stream, uint32 maxLength, uint32 chunksHint = 300);
|
||||
ChunkedData(const std::string &file, uint32 chunksHint = 300);
|
||||
~ChunkedData();
|
||||
|
||||
int GetFirstIndex(const std::string& name);
|
||||
Chunk* GetChunkByName(const std::string& name);
|
||||
|
||||
void Load(uint32 maxLength, uint32 chunksHint);
|
||||
std::vector<Chunk*> Chunks;
|
||||
FILE* Stream;
|
||||
};
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef CONSTANTS_H
|
||||
#define CONSTANTS_H
|
||||
|
||||
class Constants
|
||||
{
|
||||
public:
|
||||
enum TriangleType
|
||||
{
|
||||
TRIANGLE_TYPE_UNKNOWN,
|
||||
TRIANGLE_TYPE_TERRAIN,
|
||||
TRIANGLE_TYPE_WATER,
|
||||
TRIANGLE_TYPE_DOODAD,
|
||||
TRIANGLE_TYPE_WMO
|
||||
};
|
||||
|
||||
enum PolyArea
|
||||
{
|
||||
POLY_AREA_TERRAIN = 1,
|
||||
POLY_AREA_WATER = 2,
|
||||
POLY_AREA_ROAD = 3,
|
||||
POLY_AREA_DANGER = 4,
|
||||
};
|
||||
|
||||
enum PolyFlag
|
||||
{
|
||||
POLY_FLAG_WALK = 1,
|
||||
POLY_FLAG_SWIM = 2,
|
||||
POLY_FLAG_FLIGHTMASTER = 4
|
||||
};
|
||||
|
||||
enum ExtractFlags
|
||||
{
|
||||
EXTRACT_FLAG_DBC = 0x01,
|
||||
EXTRACT_FLAG_MAPS = 0x02,
|
||||
EXTRACT_FLAG_VMAPS = 0x04,
|
||||
EXTRACT_FLAG_GOB_MODELS = 0x08,
|
||||
EXTRACT_FLAG_MMAPS = 0x10,
|
||||
EXTRACT_FLAG_TEST = 0x20,
|
||||
EXTRACT_FLAG_ALLOWED = EXTRACT_FLAG_DBC | EXTRACT_FLAG_MAPS | EXTRACT_FLAG_VMAPS | EXTRACT_FLAG_GOB_MODELS | EXTRACT_FLAG_MMAPS | EXTRACT_FLAG_TEST
|
||||
};
|
||||
|
||||
static const float TileSize;
|
||||
static const float MaxXY;
|
||||
static const float ChunkSize;
|
||||
static const float UnitSize;
|
||||
static const float Origin[];
|
||||
static const float PI;
|
||||
static const float MaxStandableHeight;
|
||||
static bool ToWoWCoords;
|
||||
static bool Debug;
|
||||
static const char* VMAPMagic;
|
||||
static const float BaseUnitDim;
|
||||
static const int VertexPerMap;
|
||||
static const int VertexPerTile;
|
||||
static const int TilesPerMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "ContinentBuilder.h"
|
||||
#include "TileBuilder.h"
|
||||
#include "WDT.h"
|
||||
#include "Utils.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "Cache.h"
|
||||
#include "ace/Task.h"
|
||||
#include "Recast.h"
|
||||
#include "DetourCommon.h"
|
||||
|
||||
class BuilderThread : public ACE_Task_Base
|
||||
{
|
||||
private:
|
||||
int X, Y, MapId;
|
||||
std::string Continent;
|
||||
dtNavMeshParams Params;
|
||||
ContinentBuilder* cBuilder;
|
||||
public:
|
||||
BuilderThread(ContinentBuilder* _cBuilder, dtNavMeshParams& params) : Params(params), cBuilder(_cBuilder), Free(true) {}
|
||||
|
||||
void SetData(int x, int y, int map, const std::string& cont)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
MapId = map;
|
||||
Continent = cont;
|
||||
}
|
||||
|
||||
int svc()
|
||||
{
|
||||
Free = false;
|
||||
printf("[%02i,%02i] Building tile\n", X, Y);
|
||||
TileBuilder builder(cBuilder, Continent, X, Y, MapId);
|
||||
char buff[100];
|
||||
sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X);
|
||||
FILE* f = fopen(buff, "r");
|
||||
if (f) // Check if file already exists.
|
||||
{
|
||||
printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y);
|
||||
fclose(f);
|
||||
Free = true;
|
||||
return 0;
|
||||
}
|
||||
uint8* nav = builder.BuildTiled(Params);
|
||||
if (nav)
|
||||
{
|
||||
f = fopen(buff, "wb");
|
||||
if (!f)
|
||||
{
|
||||
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
|
||||
return 0;
|
||||
}
|
||||
MmapTileHeader header;
|
||||
header.size = builder.DataSize;
|
||||
fwrite(&header, sizeof(MmapTileHeader), 1, f);
|
||||
fwrite(nav, sizeof(unsigned char), builder.DataSize, f);
|
||||
fclose(f);
|
||||
}
|
||||
dtFree(nav);
|
||||
printf("[%02i,%02i] Tile Built!\n", X, Y);
|
||||
Free = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Free;
|
||||
};
|
||||
|
||||
void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
|
||||
{
|
||||
// this is for elevation
|
||||
if (verts && vertCount)
|
||||
rcCalcBounds(verts, vertCount, bmin, bmax);
|
||||
else
|
||||
{
|
||||
bmin[1] = FLT_MIN;
|
||||
bmax[1] = FLT_MAX;
|
||||
}
|
||||
|
||||
// this is for width and depth
|
||||
bmax[0] = (32 - int(tileX)) * Constants::TileSize;
|
||||
bmax[2] = (32 - int(tileY)) * Constants::TileSize;
|
||||
bmin[0] = bmax[0] - Constants::TileSize;
|
||||
bmin[2] = bmax[2] - Constants::TileSize;
|
||||
}
|
||||
|
||||
void ContinentBuilder::CalculateTileBounds()
|
||||
{
|
||||
for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr)
|
||||
{
|
||||
tileXMax = std::max(itr->X, tileXMax);
|
||||
tileXMin = std::min(itr->X, tileXMin);
|
||||
|
||||
tileYMax = std::max(itr->Y, tileYMax);
|
||||
tileYMin = std::min(itr->Y, tileYMin);
|
||||
}
|
||||
getTileBounds(tileXMax, tileYMax, NULL, 0, bmin, bmax);
|
||||
}
|
||||
|
||||
void ContinentBuilder::Build()
|
||||
{
|
||||
char buff[50];
|
||||
sprintf(buff, "mmaps/%03u.mmap", MapId);
|
||||
FILE* mmap = fopen(buff, "wb");
|
||||
if (!mmap)
|
||||
{
|
||||
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
|
||||
return;
|
||||
}
|
||||
|
||||
CalculateTileBounds();
|
||||
|
||||
dtNavMeshParams params;
|
||||
|
||||
std::vector<BuilderThread*> Threads;
|
||||
|
||||
if (TileMap->IsGlobalModel)
|
||||
{
|
||||
printf("Map %s ( %u ) is a WMO. Building with 1 thread.\n", Continent.c_str(), MapId);
|
||||
|
||||
TileBuilder* builder = new TileBuilder(this, Continent, 0, 0, MapId);
|
||||
builder->AddGeometry(TileMap->Model, TileMap->ModelDefinition);
|
||||
uint8* nav = builder->BuildInstance(params);
|
||||
if (nav)
|
||||
{
|
||||
// Set some params for the navmesh
|
||||
dtMeshHeader* header = (dtMeshHeader*)nav;
|
||||
dtVcopy(params.orig, header->bmin);
|
||||
params.tileWidth = header->bmax[0] - header->bmin[0];
|
||||
params.tileHeight = header->bmax[2] - header->bmin[2];
|
||||
params.maxTiles = 1;
|
||||
params.maxPolys = header->polyCount;
|
||||
fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap);
|
||||
fclose(mmap);
|
||||
|
||||
char buff[100];
|
||||
sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, 0, 0);
|
||||
FILE* f = fopen(buff, "wb");
|
||||
if (!f)
|
||||
{
|
||||
printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff);
|
||||
return;
|
||||
}
|
||||
|
||||
MmapTileHeader mheader;
|
||||
mheader.size = builder->DataSize;
|
||||
fwrite(&mheader, sizeof(MmapTileHeader), 1, f);
|
||||
fwrite(nav, sizeof(unsigned char), builder->DataSize, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
dtFree(nav);
|
||||
delete builder;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.maxPolys = 32768;
|
||||
params.maxTiles = 4096;
|
||||
rcVcopy(params.orig, Constants::Origin);
|
||||
params.tileHeight = Constants::TileSize;
|
||||
params.tileWidth = Constants::TileSize;
|
||||
fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap);
|
||||
fclose(mmap);
|
||||
|
||||
for (uint32 i = 0; i < NumberOfThreads; ++i)
|
||||
Threads.push_back(new BuilderThread(this, params));
|
||||
printf("Map %s ( %u ) has %u tiles. Building them with %u threads\n", Continent.c_str(), MapId, uint32(TileMap->TileTable.size()), NumberOfThreads);
|
||||
for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr)
|
||||
{
|
||||
bool next = false;
|
||||
while (!next)
|
||||
{
|
||||
for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
|
||||
{
|
||||
if ((*_th)->Free)
|
||||
{
|
||||
(*_th)->SetData(itr->X, itr->Y, MapId, Continent);
|
||||
(*_th)->activate();
|
||||
next = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Wait for 20 seconds
|
||||
ACE_OS::sleep(ACE_Time_Value (0, 20000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache->Clear();
|
||||
|
||||
// Free memory
|
||||
for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th)
|
||||
{
|
||||
(*_th)->wait();
|
||||
delete *_th;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef CONT_BUILDER_H
|
||||
#define CONT_BUILDER_H
|
||||
#include <string>
|
||||
#include "WDT.h"
|
||||
#include "Define.h"
|
||||
|
||||
class ContinentBuilder
|
||||
{
|
||||
public:
|
||||
ContinentBuilder(std::string continent, uint32 mapId, WDT* wdt, uint32 tn) :
|
||||
Continent(continent), TileMap(wdt), MapId(mapId),
|
||||
NumberOfThreads(tn), tileXMin(64), tileYMin(64), tileXMax(0), tileYMax(0)
|
||||
{}
|
||||
|
||||
void Build();
|
||||
void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax);
|
||||
void CalculateTileBounds();
|
||||
float bmin[3];
|
||||
float bmax[3];
|
||||
private:
|
||||
std::string Continent;
|
||||
WDT* TileMap;
|
||||
uint32 MapId;
|
||||
uint32 NumberOfThreads;
|
||||
int tileXMin;
|
||||
int tileYMin;
|
||||
int tileXMax;
|
||||
int tileYMax;
|
||||
};
|
||||
#endif
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include "DBC.h"
|
||||
#include "Define.h"
|
||||
|
||||
DBC::DBC( FILE* stream ) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true)
|
||||
{
|
||||
char magic[5];
|
||||
uint32 count = 0;
|
||||
count += fread(&magic, sizeof(char), 4, stream);
|
||||
magic[4] = '\0';
|
||||
count += fread(&RecordCount, sizeof(uint32), 1, stream);
|
||||
Records.reserve(RecordCount);
|
||||
count += fread(&Fields, sizeof(uint32), 1, stream);
|
||||
count += fread(&RecordSize, sizeof(uint32), 1, stream);
|
||||
count += fread(&StringBlockSize, sizeof(uint32), 1, stream);
|
||||
if (count != 8)
|
||||
printf("DBC::DBC: Failed to read some data expected 8, read %u\n", count);
|
||||
|
||||
for (int i = 0; i < RecordCount; i++)
|
||||
{
|
||||
Record* rec = new Record(this);
|
||||
Records.push_back(rec);
|
||||
int size = 0;
|
||||
for (int f = 0; f < Fields; f++)
|
||||
{
|
||||
if (size + 4 > RecordSize)
|
||||
{
|
||||
IsFaulty = true;
|
||||
break;
|
||||
}
|
||||
uint32 tmp;
|
||||
if (fread(&tmp, sizeof(uint32), 1, stream) != 1)
|
||||
printf("DBC::DBC: Failed to read some data expected 1, read 0\n");
|
||||
rec->Values.push_back(tmp);
|
||||
size += 4;
|
||||
}
|
||||
}
|
||||
StringBlock = new uint8[StringBlockSize];
|
||||
count = fread(StringBlock, sizeof(uint8), StringBlockSize, stream);
|
||||
if (count != StringBlockSize)
|
||||
printf("DBC::DBC: Failed to read some data expected %u, read %u\n", StringBlockSize, count);
|
||||
}
|
||||
|
||||
std::string DBC::GetStringByOffset( int offset )
|
||||
{
|
||||
int len = 0;
|
||||
for (uint32 i = offset; i < StringBlockSize; i++)
|
||||
{
|
||||
if (!StringBlock[i])
|
||||
{
|
||||
len = (i - offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
char* d = new char[len+1];
|
||||
strcpy(d, (const char*)(StringBlock + offset));
|
||||
d[len] = '\0';
|
||||
std::string val = std::string(d);
|
||||
delete [] d;
|
||||
return val;
|
||||
}
|
||||
|
||||
Record* DBC::GetRecordById( int id )
|
||||
{
|
||||
// we assume Id is index 0
|
||||
for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr)
|
||||
if ((*itr)->Values[0] == id)
|
||||
return *itr;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef DBC_H
|
||||
#define DBC_H
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "Define.h"
|
||||
|
||||
class Record;
|
||||
|
||||
class DBC
|
||||
{
|
||||
public:
|
||||
DBC(FILE* stream);
|
||||
|
||||
std::string GetStringByOffset(int offset);
|
||||
|
||||
Record* GetRecordById(int id);
|
||||
|
||||
std::string Name;
|
||||
std::vector<Record*> Records;
|
||||
int RecordCount;
|
||||
int Fields;
|
||||
int RecordSize;
|
||||
uint8* StringBlock;
|
||||
uint32 StringBlockSize;
|
||||
bool IsFaulty;
|
||||
};
|
||||
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
Record(DBC* dbc) : Source(dbc) {}
|
||||
|
||||
DBC* Source;
|
||||
std::vector<int> Values;
|
||||
|
||||
int operator[](int index)
|
||||
{
|
||||
return Values[index];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetValue(int index)
|
||||
{
|
||||
return *(T*)(&Values[index]);
|
||||
}
|
||||
|
||||
std::string GetString(int index)
|
||||
{
|
||||
return Source->GetStringByOffset(Values[index]);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "DoodadHandler.h"
|
||||
#include "Chunk.h"
|
||||
#include "Cache.h"
|
||||
#include "Model.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
|
||||
DoodadHandler::DoodadHandler( ADT* adt ) :
|
||||
ObjectDataHandler(adt), _definitions(NULL), _paths(NULL)
|
||||
{
|
||||
Chunk* mddf = adt->ObjectData->GetChunkByName("MDDF");
|
||||
if (mddf)
|
||||
ReadDoodadDefinitions(mddf);
|
||||
|
||||
Chunk* mmid = adt->ObjectData->GetChunkByName("MMID");
|
||||
Chunk* mmdx = adt->ObjectData->GetChunkByName("MMDX");
|
||||
if (mmid && mmdx)
|
||||
ReadDoodadPaths(mmid, mmdx);
|
||||
}
|
||||
|
||||
void DoodadHandler::ProcessInternal( MapChunk* mcnk )
|
||||
{
|
||||
if (!IsSane())
|
||||
return;
|
||||
|
||||
uint32 refCount = mcnk->Header.DoodadRefs;
|
||||
FILE* stream = mcnk->Source->GetStream();
|
||||
fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
|
||||
for (uint32 i = 0; i < refCount; i++)
|
||||
{
|
||||
int32 index;
|
||||
int32 count;
|
||||
if ((count = fread(&index, sizeof(int32), 1, stream)) != 1)
|
||||
printf("DoodadHandler::ProcessInternal: Failed to read some data expected 1, read %d\n", count);
|
||||
if (index < 0 || uint32(index) >= _definitions->size())
|
||||
continue;
|
||||
DoodadDefinition doodad = (*_definitions)[index];
|
||||
if (_drawn.find(doodad.UniqueId) != _drawn.end())
|
||||
continue;
|
||||
_drawn.insert(doodad.UniqueId);
|
||||
if (doodad.MmidIndex >= _paths->size())
|
||||
continue;
|
||||
|
||||
std::string path = (*_paths)[doodad.MmidIndex];
|
||||
Model* model = Cache->ModelCache.Get(path);
|
||||
if (!model)
|
||||
{
|
||||
model = new Model(path);
|
||||
Cache->ModelCache.Insert(path, model);
|
||||
}
|
||||
if (!model->IsCollidable)
|
||||
continue;
|
||||
|
||||
Vertices.reserve(refCount * model->Vertices.size() * 0.2);
|
||||
Triangles.reserve(refCount * model->Triangles.size() * 0.2);
|
||||
|
||||
InsertModelGeometry(doodad, model);
|
||||
}
|
||||
// Restore the stream position
|
||||
fseek(stream, mcnk->Source->Offset, SEEK_SET);
|
||||
}
|
||||
|
||||
void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk )
|
||||
{
|
||||
int32 count = chunk->Length / 36;
|
||||
_definitions = new std::vector<DoodadDefinition>;
|
||||
_definitions->reserve(count);
|
||||
FILE* stream = chunk->GetStream();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
DoodadDefinition def;
|
||||
def.Read(stream);
|
||||
_definitions->push_back(def);
|
||||
}
|
||||
}
|
||||
|
||||
void DoodadHandler::ReadDoodadPaths( Chunk* id, Chunk* data )
|
||||
{
|
||||
int paths = id->Length / 4;
|
||||
_paths = new std::vector<std::string>();
|
||||
_paths->reserve(paths);
|
||||
for (int i = 0; i < paths; i++)
|
||||
{
|
||||
FILE* idStream = id->GetStream();
|
||||
fseek(idStream, i * 4, SEEK_CUR);
|
||||
uint32 offset;
|
||||
if (fread(&offset, sizeof(uint32), 1, idStream) != 1)
|
||||
printf("DoodadHandler::ReadDoodadPaths: Failed to read some data expected 1, read 0\n");
|
||||
FILE* dataStream = data->GetStream();
|
||||
fseek(dataStream, offset + data->Offset, SEEK_SET);
|
||||
_paths->push_back(Utils::ReadString(dataStream));
|
||||
}
|
||||
}
|
||||
|
||||
void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model* model)
|
||||
{
|
||||
uint32 vertOffset = Vertices.size();
|
||||
|
||||
for (std::vector<Vector3>::iterator itr = model->Vertices.begin(); itr != model->Vertices.end(); ++itr)
|
||||
Vertices.push_back(Utils::TransformDoodadVertex(def, *itr)); // Vertices have to be converted based on the information from the DoodadDefinition struct
|
||||
|
||||
for (std::vector<Triangle<uint16> >::iterator itr = model->Triangles.begin(); itr != model->Triangles.end(); ++itr)
|
||||
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_DOODAD, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
|
||||
}
|
||||
|
||||
DoodadHandler::~DoodadHandler()
|
||||
{
|
||||
delete _definitions;
|
||||
delete _paths;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef DOOADHNDL_H
|
||||
#define DOOADHNDL_H
|
||||
#include "ObjectDataHandler.h"
|
||||
#include "Utils.h"
|
||||
#include "Chunk.h"
|
||||
#include "Model.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class DoodadDefinition : public IDefinition
|
||||
{
|
||||
public:
|
||||
uint32 MmidIndex;
|
||||
uint32 UniqueId;
|
||||
uint16 DecimalScale;
|
||||
uint16 Flags;
|
||||
|
||||
virtual float Scale() const { return DecimalScale / 1024.0f; }
|
||||
|
||||
Vector3 FixCoords(Vector3& vec)
|
||||
{
|
||||
return Vector3(vec.z, vec.x, vec.y);
|
||||
}
|
||||
|
||||
void Read(FILE* stream)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
count += fread(&MmidIndex, sizeof(uint32), 1, stream);
|
||||
count += fread(&UniqueId, sizeof(uint32), 1, stream);
|
||||
Position = (Vector3::Read(stream));
|
||||
Rotation = Vector3::Read(stream);
|
||||
count += fread(&DecimalScale, sizeof(uint16), 1, stream);
|
||||
count += fread(&Flags, sizeof(uint16), 1, stream);
|
||||
if (count != 4)
|
||||
printf("DoodadDefinition::Read: Failed to read some data expected 4, read %d\n", count);
|
||||
}
|
||||
};
|
||||
|
||||
class DoodadHandler : public ObjectDataHandler
|
||||
{
|
||||
public:
|
||||
DoodadHandler(ADT* adt);
|
||||
~DoodadHandler();
|
||||
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Triangle<uint32> > Triangles;
|
||||
bool IsSane() { return _definitions && _paths; }
|
||||
|
||||
|
||||
protected:
|
||||
void ProcessInternal(MapChunk* chunk);
|
||||
|
||||
private:
|
||||
void ReadDoodadDefinitions(Chunk* chunk);
|
||||
void ReadDoodadPaths(Chunk* id, Chunk* data);
|
||||
void InsertModelGeometry(const DoodadDefinition& def, Model* model);
|
||||
std::set<uint32> _drawn;
|
||||
std::vector<DoodadDefinition>* _definitions;
|
||||
std::vector<std::string>* _paths;
|
||||
};
|
||||
#endif
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "Geometry.h"
|
||||
#include "Constants.h"
|
||||
#include "ADT.h"
|
||||
#include "WorldModelHandler.h"
|
||||
#include "DoodadHandler.h"
|
||||
#include <limits.h>
|
||||
|
||||
Geometry::Geometry() : Transform(false)
|
||||
{
|
||||
Vertices.reserve(10000);
|
||||
Triangles.reserve(10000);
|
||||
}
|
||||
|
||||
void Geometry::CalculateBoundingBox( float*& min, float*& max )
|
||||
{
|
||||
min = new float[3];
|
||||
max = new float[3];
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
max[i] = std::numeric_limits<float>::min();
|
||||
min[i] = std::numeric_limits<float>::max();
|
||||
}
|
||||
|
||||
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
|
||||
{
|
||||
if (itr->x > max[0])
|
||||
max[0] = itr->x;
|
||||
if (itr->x < min[0])
|
||||
min[0] = itr->x;
|
||||
|
||||
if (itr->y > max[1])
|
||||
max[1] = itr->y;
|
||||
if (itr->y < min[1])
|
||||
min[1] = itr->y;
|
||||
|
||||
if (itr->z > max[2])
|
||||
max[2] = itr->z;
|
||||
if (itr->z < min[2])
|
||||
min[2] = itr->z;
|
||||
}
|
||||
}
|
||||
|
||||
void Geometry::CalculateMinMaxHeight( float& min, float& max )
|
||||
{
|
||||
min = std::numeric_limits<float>::max();
|
||||
max = std::numeric_limits<float>::min();
|
||||
|
||||
for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr)
|
||||
{
|
||||
if (Transform)
|
||||
{
|
||||
if (itr->y < min)
|
||||
min = itr->y;
|
||||
if (itr->y > max)
|
||||
max = itr->y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (itr->z < min)
|
||||
min = itr->z;
|
||||
if (itr->z > max)
|
||||
max = itr->z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Geometry::AddData( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris )
|
||||
{
|
||||
uint32 vertOffset = Vertices.size();
|
||||
for (std::vector<Vector3>::iterator itr = verts.begin(); itr != verts.end(); ++itr)
|
||||
Vertices.push_back(Transform ? Utils::ToRecast(*itr) : *itr);
|
||||
|
||||
for (std::vector<Triangle<uint32> >::iterator itr = tris.begin(); itr != tris.end(); ++itr)
|
||||
Triangles.push_back(Triangle<uint32>(itr->Type, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset));
|
||||
}
|
||||
|
||||
void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas )
|
||||
{
|
||||
verts = new float[Vertices.size() * 3];
|
||||
for (uint32 i = 0; i < Vertices.size(); ++i)
|
||||
{
|
||||
Vector3& vert = Vertices[i];
|
||||
verts[(i * 3) + 0] = vert.x;
|
||||
verts[(i * 3) + 1] = vert.y;
|
||||
verts[(i * 3) + 2] = vert.z;
|
||||
}
|
||||
|
||||
tris = new int[Triangles.size() * 3];
|
||||
for (uint32 i = 0; i < Triangles.size(); ++i)
|
||||
{
|
||||
Triangle<uint32>& tri = Triangles[i];
|
||||
tris[(i * 3) + 0] = (int)tri.V0;
|
||||
tris[(i * 3) + 1] = (int)tri.V1;
|
||||
tris[(i * 3) + 2] = (int)tri.V2;
|
||||
}
|
||||
|
||||
areas = new uint8[Triangles.size()];
|
||||
for (uint32 i = 0; i < Triangles.size(); i++)
|
||||
{
|
||||
switch (Triangles[i].Type)
|
||||
{
|
||||
case Constants::TRIANGLE_TYPE_WATER:
|
||||
areas[i] = Constants::POLY_AREA_WATER;
|
||||
break;
|
||||
default:
|
||||
areas[i] = Constants::POLY_AREA_TERRAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Geometry::AddAdt( ADT* adt )
|
||||
{
|
||||
for (std::vector<MapChunk*>::iterator itr = adt->MapChunks.begin(); itr != adt->MapChunks.end(); ++itr)
|
||||
{
|
||||
std::vector<Triangle<uint32> > tmp;
|
||||
tmp.reserve((*itr)->Triangles.size());
|
||||
for (std::vector<Triangle<uint8> >::iterator itr2 = (*itr)->Triangles.begin(); itr2 != (*itr)->Triangles.end(); ++itr2)
|
||||
tmp.push_back(Triangle<uint32>(itr2->Type, itr2->V0, itr2->V1, itr2->V2));
|
||||
AddData((*itr)->Vertices, tmp);
|
||||
}
|
||||
|
||||
if (!adt->_DoodadHandler->Triangles.empty())
|
||||
AddData(adt->_DoodadHandler->Vertices, adt->_DoodadHandler->Triangles);
|
||||
|
||||
if (!adt->_WorldModelHandler->Triangles.empty())
|
||||
AddData(adt->_WorldModelHandler->Vertices, adt->_WorldModelHandler->Triangles);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef GEOMETRY_H
|
||||
#define GEOMETRY_H
|
||||
#include <vector>
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
class ADT;
|
||||
class Geometry
|
||||
{
|
||||
public:
|
||||
Geometry();
|
||||
|
||||
void CalculateBoundingBox(float*& min, float*& max);
|
||||
void CalculateMinMaxHeight(float& min, float& max);
|
||||
void AddData(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris);
|
||||
void AddAdt(ADT* adt);
|
||||
void GetRawData(float*& verts, int*& tris, uint8*& areas);
|
||||
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Triangle<uint32> > Triangles;
|
||||
bool Transform;
|
||||
};
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "LiquidHandler.h"
|
||||
#include "Utils.h"
|
||||
|
||||
LiquidHandler::LiquidHandler( ADT* adt ) : Source(adt)
|
||||
{
|
||||
HandleNewLiquid();
|
||||
}
|
||||
|
||||
void LiquidHandler::HandleNewLiquid()
|
||||
{
|
||||
Chunk* chunk = Source->Data->GetChunkByName("MH2O");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
Vertices.reserve(1000);
|
||||
Triangles.reserve(1000);
|
||||
|
||||
FILE* stream = chunk->GetStream();
|
||||
H2OHeader header[256];
|
||||
MCNKData.reserve(256);
|
||||
for (int i = 0; i < 256; i++)
|
||||
header[i] = H2OHeader::Read(stream);
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
H2OHeader h = header[i];
|
||||
if (h.LayerCount == 0)
|
||||
{
|
||||
// Need to fill in missing data with dummies.
|
||||
MCNKData.push_back(MCNKLiquidData(NULL, H2ORenderMask()));
|
||||
continue;
|
||||
}
|
||||
fseek(stream, chunk->Offset + h.OffsetInformation, SEEK_SET);
|
||||
H2OInformation information = H2OInformation::Read(stream);
|
||||
|
||||
float** heights = new float*[9];
|
||||
for (int j = 0; j < 9; ++j)
|
||||
{
|
||||
heights[j] = new float[9];
|
||||
memset(heights[j], 0, sizeof(float) * 9);
|
||||
}
|
||||
|
||||
H2ORenderMask renderMask;
|
||||
if (information.LiquidType != 2)
|
||||
{
|
||||
fseek(stream, chunk->Offset + h.OffsetRender, SEEK_SET);
|
||||
renderMask = H2ORenderMask::Read(stream);
|
||||
if ((Utils::IsAllZero(renderMask.Mask, 8) || (information.Width == 8 && information.Height == 8)) && information.OffsetMask2)
|
||||
{
|
||||
fseek(stream, chunk->Offset + information.OffsetMask2, SEEK_SET);
|
||||
uint32 size = ceil(information.Width * information.Height / 8.0f);
|
||||
uint8* altMask = new uint8[size];
|
||||
if (fread(altMask, sizeof(uint8), size, stream) == size)
|
||||
for (uint32 mi = 0; mi < size; mi++)
|
||||
renderMask.Mask[mi + information.OffsetY] |= altMask[mi];
|
||||
delete[] altMask;
|
||||
}
|
||||
fseek(stream, chunk->Offset + information.OffsetHeightmap, SEEK_SET);
|
||||
|
||||
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
|
||||
for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++)
|
||||
if (fread(&heights[x][y], sizeof(float), 1, stream) != 1)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill with ocean data
|
||||
for (uint32 i = 0; i < 8; ++i)
|
||||
renderMask.Mask[i] = 0xFF;
|
||||
|
||||
for (uint32 y = 0; y < 9; ++y)
|
||||
for (uint32 x = 0; x < 9; ++x)
|
||||
heights[x][y] = information.HeightLevel1;
|
||||
}
|
||||
|
||||
MCNKData.push_back(MCNKLiquidData(heights, renderMask));
|
||||
|
||||
for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++)
|
||||
{
|
||||
for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++)
|
||||
{
|
||||
if (!renderMask.ShouldRender(x, y))
|
||||
continue;
|
||||
|
||||
MapChunk* mapChunk = Source->MapChunks[i];
|
||||
Vector3 location = mapChunk->Header.Position;
|
||||
location.y = location.y - (x * Constants::UnitSize);
|
||||
location.x = location.x - (y * Constants::UnitSize);
|
||||
location.z = heights[x][y];
|
||||
|
||||
uint32 vertOffset = Vertices.size();
|
||||
Vertices.push_back(location);
|
||||
Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y, location.z));
|
||||
Vertices.push_back(Vector3(location.x, location.y - Constants::UnitSize, location.z));
|
||||
Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y - Constants::UnitSize, location.z));
|
||||
|
||||
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset+2, vertOffset + 1));
|
||||
Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef LIQUID_H
|
||||
#define LIQUID_H
|
||||
#include "ADT.h"
|
||||
#include "Utils.h"
|
||||
#include "Define.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class LiquidHandler
|
||||
{
|
||||
public:
|
||||
LiquidHandler(ADT* adt);
|
||||
|
||||
ADT* Source;
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Triangle<uint32> > Triangles;
|
||||
std::vector<MCNKLiquidData> MCNKData;
|
||||
private:
|
||||
void HandleNewLiquid();
|
||||
};
|
||||
#endif
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "MPQ.h"
|
||||
#include "MPQManager.h"
|
||||
#include <deque>
|
||||
#include <cstdio>
|
||||
|
||||
MPQArchive::MPQArchive(const char* filename)
|
||||
{
|
||||
int result = libmpq__archive_open(&mpq_a, filename, -1);
|
||||
printf("Opening %s\n", filename);
|
||||
if (result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case LIBMPQ_ERROR_OPEN :
|
||||
printf("Error opening archive '%s': Does file really exist?\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_FORMAT : /* bad file format */
|
||||
printf("Error opening archive '%s': Bad file format\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_SEEK : /* seeking in file failed */
|
||||
printf("Error opening archive '%s': Seeking in file failed\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_READ : /* Read error in archive */
|
||||
printf("Error opening archive '%s': Read error in archive\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */
|
||||
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
|
||||
break;
|
||||
default:
|
||||
printf("Error opening archive '%s': Unknown error\n", filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
GetFileListTo(Files);
|
||||
}
|
||||
|
||||
void MPQArchive::close()
|
||||
{
|
||||
libmpq__archive_close(mpq_a);
|
||||
}
|
||||
|
||||
MPQFile::MPQFile(const char* filename):
|
||||
eof(false), buffer(0), pointer(0), size(0)
|
||||
{
|
||||
for (std::deque<MPQArchive*>::iterator i = MPQHandler->Archives.begin(); i != MPQHandler->Archives.end();++i)
|
||||
{
|
||||
mpq_archive* mpq_a = (*i)->mpq_a;
|
||||
|
||||
uint32_t filenum;
|
||||
if(libmpq__file_number(mpq_a, filename, &filenum))
|
||||
continue;
|
||||
libmpq__off_t transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
|
||||
if (size<=1) {
|
||||
// printf("warning: file %s has size %d; cannot Read.\n", filename, size);
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
return;
|
||||
}
|
||||
buffer = new char[size];
|
||||
|
||||
//libmpq_file_getdata
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
/*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/
|
||||
return;
|
||||
|
||||
}
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
size_t MPQFile::Read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof)
|
||||
return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > size_t(size)) {
|
||||
bytes = size - pointer;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
memcpy(dest, &(buffer[pointer]), bytes);
|
||||
|
||||
pointer = rpos;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void MPQFile::seek(int offset)
|
||||
{
|
||||
pointer = offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::seekRelative(int offset)
|
||||
{
|
||||
pointer += offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::close()
|
||||
{
|
||||
delete[] buffer;
|
||||
buffer = 0;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
FILE* MPQFile::GetFileStream()
|
||||
{
|
||||
FILE* file = tmpfile();
|
||||
if (!file)
|
||||
{
|
||||
printf("Could not create temporary file. Please run as Administrator or root\n");
|
||||
exit(1);
|
||||
}
|
||||
fwrite(buffer, sizeof(char), size, file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
return file;
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MPQ_H
|
||||
#define MPQ_H
|
||||
|
||||
#include "libmpq/mpq.h"
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <ctype.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
class MPQArchive
|
||||
{
|
||||
|
||||
public:
|
||||
mpq_archive_s *mpq_a;
|
||||
|
||||
std::vector<std::string> Files;
|
||||
|
||||
MPQArchive(const char* filename);
|
||||
void close();
|
||||
|
||||
void GetFileListTo(std::vector<std::string>& filelist) {
|
||||
uint32_t filenum;
|
||||
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
|
||||
libmpq__off_t size, transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
char* buffer = new char[size + 1];
|
||||
buffer[size] = '\0';
|
||||
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
|
||||
char seps[] = "\n";
|
||||
char* token;
|
||||
|
||||
token = strtok( buffer, seps );
|
||||
uint32 counter = 0;
|
||||
while ((token != NULL) && (counter < size)) {
|
||||
//cout << token << endl;
|
||||
token[strlen(token) - 1] = 0;
|
||||
std::string s = token;
|
||||
filelist.push_back(s);
|
||||
counter += strlen(token) + 2;
|
||||
token = strtok(NULL, seps);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
//MPQHANDLE handle;
|
||||
bool eof;
|
||||
char *buffer;
|
||||
libmpq__off_t pointer,size;
|
||||
|
||||
// disable copying
|
||||
MPQFile(const MPQFile& /*f*/) {}
|
||||
void operator=(const MPQFile& /*f*/) {}
|
||||
|
||||
public:
|
||||
MPQFile(const char* filename); // filenames are not case sensitive
|
||||
~MPQFile() { close(); }
|
||||
size_t Read(void* dest, size_t bytes);
|
||||
FILE* GetFileStream();
|
||||
size_t getSize() { return size; }
|
||||
size_t getPos() { return pointer; }
|
||||
char* getBuffer() { return buffer; }
|
||||
char* getPointer() { return buffer + pointer; }
|
||||
bool isEof() { return eof; }
|
||||
void seek(int offset);
|
||||
void seekRelative(int offset);
|
||||
void close();
|
||||
};
|
||||
|
||||
inline void flipcc(char *fcc)
|
||||
{
|
||||
char t;
|
||||
t=fcc[0];
|
||||
fcc[0]=fcc[3];
|
||||
fcc[3]=t;
|
||||
t=fcc[1];
|
||||
fcc[1]=fcc[2];
|
||||
fcc[2]=t;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "MPQManager.h"
|
||||
#include "MPQ.h"
|
||||
#include "DBC.h"
|
||||
#include "Utils.h"
|
||||
#include <ace/Guard_T.h>
|
||||
|
||||
char const* MPQManager::Files[] = {
|
||||
"common.MPQ",
|
||||
"common-2.MPQ",
|
||||
"expansion.MPQ",
|
||||
"lichking.MPQ",
|
||||
"patch.MPQ",
|
||||
"patch-2.MPQ",
|
||||
"patch-3.MPQ"
|
||||
};
|
||||
|
||||
char const* MPQManager::Languages[] = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
|
||||
|
||||
void MPQManager::Initialize()
|
||||
{
|
||||
InitializeDBC();
|
||||
uint32 size = sizeof(Files) / sizeof(char*);
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
{
|
||||
MPQArchive* arc = new MPQArchive(std::string("Data/" + std::string(Files[i])).c_str());
|
||||
Archives.push_front(arc); // MPQ files have to be transversed in reverse order to properly account for patched files
|
||||
printf("Opened %s\n", Files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void MPQManager::InitializeDBC()
|
||||
{
|
||||
BaseLocale = -1;
|
||||
std::string fileName;
|
||||
uint32 size = sizeof(Languages) / sizeof(char*);
|
||||
MPQArchive* _baseLocale = NULL;
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
{
|
||||
std::string _fileName = "Data/" + std::string(Languages[i]) + "/locale-" + std::string(Languages[i]) + ".MPQ";
|
||||
FILE* file = fopen(_fileName.c_str(), "rb");
|
||||
if (file)
|
||||
{
|
||||
if (BaseLocale == -1)
|
||||
{
|
||||
BaseLocale = i;
|
||||
_baseLocale = new MPQArchive(_fileName.c_str());
|
||||
fileName = _fileName;
|
||||
LocaleFiles[i] = _baseLocale;
|
||||
}
|
||||
else
|
||||
LocaleFiles[i] = new MPQArchive(_fileName.c_str());
|
||||
|
||||
AvailableLocales.insert(i);
|
||||
printf("Detected locale: %s\n", Languages[i]);
|
||||
}
|
||||
}
|
||||
Archives.push_front(_baseLocale);
|
||||
if (BaseLocale == -1)
|
||||
{
|
||||
printf("No locale data detected. Please make sure that the executable is in the same folder as your WoW installation.\n");
|
||||
ASSERT(false);
|
||||
}
|
||||
else
|
||||
printf("Using default locale: %s\n", Languages[BaseLocale]);
|
||||
}
|
||||
|
||||
FILE* MPQManager::GetFile(const std::string& path )
|
||||
{
|
||||
ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
|
||||
MPQFile file(path.c_str());
|
||||
if (file.isEof())
|
||||
return NULL;
|
||||
return file.GetFileStream();
|
||||
}
|
||||
|
||||
DBC* MPQManager::GetDBC(const std::string& name )
|
||||
{
|
||||
std::string path = "DBFilesClient\\" + name + ".dbc";
|
||||
return new DBC(GetFile(path));
|
||||
}
|
||||
|
||||
FILE* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file )
|
||||
{
|
||||
ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL);
|
||||
mpq_archive* mpq_a = file->mpq_a;
|
||||
|
||||
uint32_t filenum;
|
||||
if(libmpq__file_number(mpq_a, path.c_str(), &filenum))
|
||||
return NULL;
|
||||
|
||||
libmpq__off_t transferred;
|
||||
libmpq__off_t size = 0;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
|
||||
if (size <= 1)
|
||||
return NULL;
|
||||
|
||||
uint8* buffer = new uint8[size];
|
||||
|
||||
//libmpq_file_getdata
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
|
||||
// Pack the return into a FILE stream
|
||||
FILE* ret = tmpfile();
|
||||
if (!ret)
|
||||
{
|
||||
printf("Could not create temporary file. Please run as Administrator or root\n");
|
||||
exit(1);
|
||||
}
|
||||
fwrite(buffer, sizeof(uint8), size, ret);
|
||||
fseek(ret, 0, SEEK_SET);
|
||||
delete[] buffer;
|
||||
return ret;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MPQ_MANAGER_H
|
||||
#define MPQ_MANAGER_H
|
||||
|
||||
#include "MPQ.h"
|
||||
#include <ace/Synch.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
class DBC;
|
||||
class MPQManager
|
||||
{
|
||||
public:
|
||||
MPQManager() {}
|
||||
~MPQManager() {}
|
||||
|
||||
void Initialize();
|
||||
FILE* GetFile(const std::string& path);
|
||||
FILE* GetFileFrom(const std::string& path, MPQArchive* file);
|
||||
DBC* GetDBC(const std::string& name);
|
||||
std::vector<std::string> GetAllFiles(std::string extension);
|
||||
|
||||
std::deque<MPQArchive*> Archives;
|
||||
int32 BaseLocale;
|
||||
std::set<uint32> AvailableLocales;
|
||||
std::map<uint32, MPQArchive*> LocaleFiles;
|
||||
|
||||
static char const* Files[];
|
||||
static char const* Languages[];
|
||||
protected:
|
||||
void InitializeDBC();
|
||||
private:
|
||||
ACE_Thread_Mutex mutex;
|
||||
};
|
||||
|
||||
extern MPQManager* MPQHandler;
|
||||
#endif
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "MapChunk.h"
|
||||
#include "ADT.h"
|
||||
#include "LiquidHandler.h"
|
||||
|
||||
MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk)
|
||||
{
|
||||
FILE* stream = chunk->GetStream();
|
||||
Header.Read(stream);
|
||||
fseek(stream, chunk->Offset, SEEK_SET);
|
||||
Index = Header.IndexX + Header.IndexY * 16;
|
||||
GenerateVertices(stream);
|
||||
}
|
||||
|
||||
void MapChunk::GenerateTriangles()
|
||||
{
|
||||
Triangles.reserve(256);
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
if (HasHole(Header.Holes, x / 2, y / 2))
|
||||
continue;
|
||||
|
||||
uint32 topLeft = (17 * y) + x;
|
||||
uint32 topRight = (17 * y) + x + 1;
|
||||
uint32 bottomLeft = (17 * (y + 1)) + x;
|
||||
uint32 bottomRight = (17 * (y + 1)) + x + 1;
|
||||
uint32 center = (17 * y) + 9 + x;
|
||||
|
||||
Constants::TriangleType triangleType = Constants::TRIANGLE_TYPE_TERRAIN;
|
||||
if (Adt->_LiquidHandler && !Adt->_LiquidHandler->MCNKData.empty())
|
||||
{
|
||||
MCNKLiquidData& data = Adt->_LiquidHandler->MCNKData[Index];
|
||||
float maxHeight = std::max(
|
||||
std::max(
|
||||
std::max(std::max(Vertices[topLeft].z, Vertices[topRight].z), Vertices[bottomLeft].z),
|
||||
Vertices[bottomRight].z), Vertices[center].z);
|
||||
if (data.IsWater(x, y, maxHeight))
|
||||
triangleType = Constants::TRIANGLE_TYPE_WATER;
|
||||
}
|
||||
|
||||
Triangles.push_back(Triangle<uint8>(triangleType, topRight, topLeft, center));
|
||||
Triangles.push_back(Triangle<uint8>(triangleType, topLeft, bottomLeft, center));
|
||||
Triangles.push_back(Triangle<uint8>(triangleType, bottomLeft, bottomRight, center));
|
||||
Triangles.push_back(Triangle<uint8>(triangleType, bottomRight, topRight, center));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapChunk::GenerateVertices( FILE* stream )
|
||||
{
|
||||
fseek(stream, Header.OffsetMCVT, SEEK_CUR);
|
||||
Vertices.reserve(125);
|
||||
|
||||
for (int j = 0; j < 17; j++)
|
||||
{
|
||||
int values = j % 2 ? 8 : 9;
|
||||
for (int i = 0; i < values; i++)
|
||||
{
|
||||
float tmp;
|
||||
if (fread(&tmp, sizeof(float), 1, stream) != 1)
|
||||
printf("MapChunk::GenerateVertices: Failed to read some data expected 1, read 0\n");
|
||||
Vector3 vert(Header.Position.x - (j * (Constants::UnitSize * 0.5f)), Header.Position.y - (i * Constants::UnitSize), Header.Position.z + tmp);
|
||||
if (values == 8)
|
||||
vert.y -= Constants::UnitSize * 0.5f;
|
||||
Vertices.push_back(vert);
|
||||
}
|
||||
}
|
||||
// Restore stream position.
|
||||
fseek(stream, Source->Offset, SEEK_SET);
|
||||
}
|
||||
|
||||
bool MapChunk::HasHole( uint32 map, int x, int y )
|
||||
{
|
||||
return (map & 0x0000FFFF) & ((1 << x) << (y << 2));
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MAPCHUNK_H
|
||||
#define MAPCHUNK_H
|
||||
#include "Chunk.h"
|
||||
#include "Utils.h"
|
||||
#include "Constants.h"
|
||||
#include <vector>
|
||||
class ADT;
|
||||
|
||||
class MapChunk
|
||||
{
|
||||
public:
|
||||
MapChunk(ADT* _adt, Chunk* chunk);
|
||||
|
||||
void GenerateTriangles();
|
||||
void GenerateVertices(FILE* stream);
|
||||
static bool HasHole(uint32 map, int x, int y);
|
||||
ADT* Adt;
|
||||
Chunk* Source;
|
||||
MapChunkHeader Header;
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Triangle<uint8> > Triangles;
|
||||
int32 Index;
|
||||
};
|
||||
#endif
|
||||
@@ -1,476 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "MPQManager.h"
|
||||
#include "WDT.h"
|
||||
#include "ContinentBuilder.h"
|
||||
#include "Cache.h"
|
||||
#include "DBC.h"
|
||||
#include "Constants.h"
|
||||
#include "Model.h"
|
||||
|
||||
#include "Recast.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourNavMeshQuery.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
MPQManager* MPQHandler;
|
||||
CacheClass* Cache;
|
||||
|
||||
void ExtractMMaps(std::set<uint32>& mapIds, uint32 threads)
|
||||
{
|
||||
DBC* dbc = MPQHandler->GetDBC("Map");
|
||||
printf("Map.dbc contains %u rows.\n", dbc->Records.size());
|
||||
for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
|
||||
{
|
||||
uint32 mapId = (*itr)->Values[0];
|
||||
|
||||
// Skip this map if a list of specific maps was provided and this one is not contained in it.
|
||||
if (!mapIds.empty() && mapIds.find(mapId) == mapIds.end())
|
||||
{
|
||||
if (Constants::Debug)
|
||||
printf("Map %u will not be built.\n", mapId);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = (*itr)->GetString(1);
|
||||
WDT wdt("World\\maps\\" + name + "\\" + name + ".wdt");
|
||||
if (!wdt.IsValid)
|
||||
{
|
||||
printf("Could not find WDT data for map %u (%s)\n", mapId, name.c_str());
|
||||
continue;
|
||||
}
|
||||
printf("Building %s MapId %u\n", name.c_str(), mapId);
|
||||
ContinentBuilder builder(name, mapId, &wdt, threads);
|
||||
builder.Build();
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractDBCs()
|
||||
{
|
||||
printf("Extracting DBCs\n");
|
||||
// Create the file system structure
|
||||
std::string baseDBCPath = "dbc/";
|
||||
Utils::CreateDir(baseDBCPath);
|
||||
|
||||
std::set<std::string> DBCFiles;
|
||||
const size_t extLen = strlen(".dbc");
|
||||
// Populate list of DBC files
|
||||
// We get the DBC names by going over the (guaranteed to exist) default locale files
|
||||
// Then we look in other locale files in case that they are available.
|
||||
for (std::vector<std::string>::iterator itr = MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.begin(); itr != MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.end(); ++itr)
|
||||
if (itr->rfind(".dbc") == itr->length() - extLen) // Check if the extension is ".dbc"
|
||||
DBCFiles.insert(*itr);
|
||||
|
||||
const size_t folderLen = strlen("DBFilesClient\\");
|
||||
// Iterate over all available locales
|
||||
for (std::set<uint32>::iterator itr = MPQHandler->AvailableLocales.begin(); itr != MPQHandler->AvailableLocales.end(); ++itr)
|
||||
{
|
||||
printf("Extracting DBCs for locale %s\n", MPQManager::Languages[*itr]);
|
||||
std::string path = baseDBCPath;
|
||||
if (*itr != uint32(MPQHandler->BaseLocale))
|
||||
{
|
||||
path += std::string(MPQManager::Languages[*itr]) + "/";
|
||||
Utils::CreateDir(path);
|
||||
}
|
||||
|
||||
std::string component = "component.wow-" + std::string(MPQManager::Languages[*itr]) + ".txt";
|
||||
// Extract the component file
|
||||
Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*itr]), path + component);
|
||||
// Extract the DBC files for the given locale
|
||||
for (std::set<std::string>::iterator itr2 = DBCFiles.begin(); itr2 != DBCFiles.end(); ++itr2)
|
||||
Utils::SaveToDisk(MPQHandler->GetFileFrom(*itr2, MPQHandler->LocaleFiles[*itr]), path + (itr2->c_str() + folderLen));
|
||||
}
|
||||
printf("DBC extraction finished!\n");
|
||||
}
|
||||
|
||||
void ExtractGameobjectModels()
|
||||
{
|
||||
Constants::ToWoWCoords = true;
|
||||
printf("Extracting GameObject models\n");
|
||||
|
||||
std::string baseBuildingsPath = "Buildings/";
|
||||
std::string baseVmapsPath = "vmaps/";
|
||||
Utils::CreateDir(baseVmapsPath);
|
||||
Utils::CreateDir(baseBuildingsPath);
|
||||
|
||||
FILE* modelList = fopen((baseVmapsPath + "GameObjectModels.list").c_str(), "wb");
|
||||
if (!modelList)
|
||||
{
|
||||
printf("Could not create file vmaps/GameObjectModels.list, please make sure that you have the write permissions in the folder\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DBC* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo");
|
||||
for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr)
|
||||
{
|
||||
std::string path = (*itr)->GetString(1);
|
||||
std::string fileName = Utils::GetPlainName(path.c_str());
|
||||
std::string extension = Utils::GetExtension(fileName);
|
||||
// Convert the extension to lowercase
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
if (extension == "mdx" || extension == "m2")
|
||||
{
|
||||
fileName = Utils::FixModelPath(fileName);
|
||||
Model model(path);
|
||||
|
||||
if (model.IsBad)
|
||||
continue;
|
||||
|
||||
FILE* output = fopen((baseBuildingsPath + fileName).c_str(), "wb");
|
||||
if (!output)
|
||||
{
|
||||
printf("Could not create file %s, please check that you have write permissions\n", (baseBuildingsPath + fileName).c_str());
|
||||
continue;
|
||||
}
|
||||
// Placeholder for 0 values
|
||||
int Nop[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
fwrite(Constants::VMAPMagic, 8, 1, output);
|
||||
uint32 numVerts = model.Header.CountBoundingVertices;
|
||||
fwrite(&numVerts, sizeof(uint32), 1, output);
|
||||
uint32 numGroups = 1;
|
||||
fwrite(&numGroups, sizeof(uint32), 1, output);
|
||||
fwrite(Nop, 4 * 3 , 1, output); // rootwmoid, flags, groupid
|
||||
fwrite(Nop, sizeof(float), 3 * 2, output);//bbox, only needed for WMO currently
|
||||
fwrite(Nop, 4, 1, output);// liquidflags
|
||||
fwrite("GRP ", 4, 1, output);
|
||||
|
||||
uint32 branches = 1;
|
||||
uint32 wsize = sizeof(branches) + sizeof(uint32) * branches;
|
||||
fwrite(&wsize, sizeof(uint32), 1, output);
|
||||
fwrite(&branches, sizeof(branches), 1, output);
|
||||
uint32 numTris = model.Header.CountBoundingTriangles;
|
||||
fwrite(&numTris, sizeof(uint32), 1, output);
|
||||
fwrite("INDX", 4, 1, output);
|
||||
wsize = sizeof(uint32) + sizeof(unsigned short) * numTris;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&numTris, sizeof(uint32), 1, output);
|
||||
uint16* indices = new uint16[numTris];
|
||||
|
||||
if (numTris > 0)
|
||||
{
|
||||
uint32 i = 0;
|
||||
for (std::vector<Triangle<uint16> >::iterator itr2 = model.Triangles.begin(); itr2 != model.Triangles.end(); ++itr2, ++i)
|
||||
{
|
||||
indices[i * 3 + 0] = itr2->V0;
|
||||
indices[i * 3 + 1] = itr2->V1;
|
||||
indices[i * 3 + 2] = itr2->V2;
|
||||
}
|
||||
fwrite(indices, sizeof(uint16), numTris, output);
|
||||
}
|
||||
|
||||
|
||||
fwrite("VERT", 4, 1, output);
|
||||
wsize = sizeof(int) + sizeof(float) * 3 * numVerts;
|
||||
fwrite(&wsize, sizeof(int), 1, output);
|
||||
fwrite(&numVerts, sizeof(int), 1, output);
|
||||
float* vertices = new float[numVerts*3];
|
||||
|
||||
if (numVerts > 0)
|
||||
{
|
||||
uint32 i = 0;
|
||||
for (std::vector<Vector3>::iterator itr2 = model.Vertices.begin(); itr2 != model.Vertices.end(); ++itr2, ++i)
|
||||
{
|
||||
vertices[i * 3 + 0] = itr2->x;
|
||||
vertices[i * 3 + 1] = itr2->y;
|
||||
vertices[i * 3 + 2] = itr2->z;
|
||||
}
|
||||
|
||||
fwrite(vertices, sizeof(float), numVerts * 3, output);
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
delete[] indices;
|
||||
delete[] vertices;
|
||||
|
||||
uint32 displayId = (*itr)->Values[0];
|
||||
uint32 pathLength = fileName.size();
|
||||
fwrite(&displayId, sizeof(uint32), 1, modelList);
|
||||
fwrite(&pathLength, sizeof(uint32), 1, modelList);
|
||||
fwrite(fileName.c_str(), sizeof(char), pathLength, modelList);
|
||||
}
|
||||
else if (extension == "wmo")
|
||||
{
|
||||
WorldModelRoot model(path);
|
||||
|
||||
FILE* output = fopen((baseBuildingsPath + fileName).c_str(), "wb");
|
||||
if (!output)
|
||||
{
|
||||
printf("Could not create file %s, please check that you have write permissions\n", (baseBuildingsPath + fileName).c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
fwrite(Constants::VMAPMagic, 1, 8, output);
|
||||
uint32 numVertices = 0;
|
||||
fwrite(&numVertices, sizeof(uint32), 1, output); // will be filled later
|
||||
fwrite(&model.Header.CountGroups, sizeof(uint32), 1, output);
|
||||
fwrite(&model.Header.WmoId, sizeof(uint32), 1, output);
|
||||
|
||||
const char grp[] = { 'G' , 'R' , 'P', ' ' };
|
||||
for (std::vector<WorldModelGroup>::iterator itr2 = model.Groups.begin(); itr2 != model.Groups.end(); ++itr2)
|
||||
{
|
||||
const WMOGroupHeader& header = itr2->Header;
|
||||
fwrite(&header.Flags, sizeof(uint32), 1, output);
|
||||
fwrite(&header.WmoId, sizeof(uint32), 1, output);
|
||||
fwrite(&header.BoundingBox[0], sizeof(uint32), 1, output);
|
||||
fwrite(&header.BoundingBox[1], sizeof(uint32), 1, output);
|
||||
uint32 LiquidFlags = itr2->HasLiquidData ? 1 : 0;
|
||||
fwrite(&LiquidFlags, sizeof(uint32), 1, output);
|
||||
|
||||
fwrite(grp, sizeof(char), sizeof(grp), output);
|
||||
uint32 k = 0;
|
||||
uint32 mobaBatch = itr2->MOBALength / 12;
|
||||
uint32* MobaEx = new uint32[mobaBatch*4];
|
||||
|
||||
for(uint32 i = 8; i < itr2->MOBALength; i += 12)
|
||||
MobaEx[k++] = itr2->MOBA[i];
|
||||
|
||||
int mobaSizeGrp = mobaBatch * 4 + 4;
|
||||
fwrite(&mobaSizeGrp, 4, 1, output);
|
||||
fwrite(&mobaBatch, 4, 1, output);
|
||||
fwrite(MobaEx, 4, k, output);
|
||||
delete[] MobaEx;
|
||||
|
||||
//@TODO: Finish this.
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(modelList);
|
||||
printf("GameObject models extraction finished!");
|
||||
Constants::ToWoWCoords = false;
|
||||
}
|
||||
|
||||
bool HandleArgs(int argc, char** argv, uint32& threads, std::set<uint32>& mapList, bool& debugOutput, uint32& extractFlags)
|
||||
{
|
||||
char* param = NULL;
|
||||
extractFlags = 0;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "--threads") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
return false;
|
||||
|
||||
threads = atoi(param);
|
||||
printf("Using %u threads\n", threads);
|
||||
}
|
||||
else if (strcmp(argv[i], "--maps") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
return false;
|
||||
|
||||
char* copy = strdup(param);
|
||||
char* token = strtok(copy, ",");
|
||||
while (token)
|
||||
{
|
||||
mapList.insert(atoi(token));
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
free(copy);
|
||||
|
||||
printf("Extracting only provided list of maps (%u).\n", uint32(mapList.size()));
|
||||
}
|
||||
else if (strcmp(argv[i], "--debug") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
return false;
|
||||
debugOutput = atoi(param);
|
||||
if (debugOutput)
|
||||
printf("Output will contain debug information (.obj files)\n");
|
||||
}
|
||||
else if (strcmp(argv[i], "--extract") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
return false;
|
||||
|
||||
extractFlags = atoi(param);
|
||||
|
||||
if (!(extractFlags & Constants::EXTRACT_FLAG_ALLOWED)) // Tried to use an invalid flag
|
||||
return false;
|
||||
|
||||
printf("Detected flags: \n");
|
||||
printf("* Extract DBCs: %s\n", (extractFlags & Constants::EXTRACT_FLAG_DBC) ? "Yes" : "No");
|
||||
printf("* Extract Maps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_MAPS) ? "Yes" : "No");
|
||||
printf("* Extract VMaps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_VMAPS) ? "Yes" : "No");
|
||||
printf("* Extract GameObject Models: %s\n", (extractFlags & Constants::EXTRACT_FLAG_GOB_MODELS) ? "Yes" : "No");
|
||||
printf("* Extract MMaps: %s\n", (extractFlags & Constants::EXTRACT_FLAG_MMAPS) ? "Yes" : "No");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintUsage()
|
||||
{
|
||||
printf("MeshExtractor help.\n");
|
||||
printf("* Use \"--threads <number>\" to specify <number> threads, default to 4 (Only available when extracting MMaps)\n");
|
||||
printf("* Use \"--maps a,b,c,d,e\" to extract only the maps specified (Do not use spaces)\n");
|
||||
printf("* Use \"--debug 1\" to generate debug information of the tiles (Only available when extracting MMaps)\n");
|
||||
printf("* Use \"--extract X\" to extract the data specified by the flag X (Note: You can combine the flags with the bitwise OR operator |). Available flags are: \n");
|
||||
{
|
||||
printf("- %u to extract DBCs\n", Constants::EXTRACT_FLAG_DBC);
|
||||
printf("- %u to extract Maps (Not yet implemented)\n", Constants::EXTRACT_FLAG_MAPS);
|
||||
printf("- %u to extract VMaps (Not yet implemented)\n", Constants::EXTRACT_FLAG_VMAPS);
|
||||
printf("- %u to extract GameObject models (Not yet finished, you need to run VMapAssembler on the extracted files)\n", Constants::EXTRACT_FLAG_GOB_MODELS);
|
||||
printf("- %u to extract MMaps (Not yet finished)\n", Constants::EXTRACT_FLAG_MMAPS);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadTile(dtNavMesh*& navMesh, const char* tile)
|
||||
{
|
||||
FILE* f = fopen(tile, "rb");
|
||||
if (!f)
|
||||
return;
|
||||
MmapTileHeader header;
|
||||
|
||||
if (fread(&header, sizeof(MmapTileHeader), 1, f) != 1)
|
||||
return;
|
||||
|
||||
uint8* nav = new uint8[header.size];
|
||||
if (fread(nav, header.size, 1, f) != 1)
|
||||
return;
|
||||
|
||||
navMesh->addTile(nav, header.size, DT_TILE_FREE_DATA, 0, NULL);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
_setmaxstdio(2048);
|
||||
uint32 threads = 4, extractFlags = 0;
|
||||
std::set<uint32> mapIds;
|
||||
|
||||
if (!HandleArgs(argc, argv, threads, mapIds, Constants::Debug, extractFlags))
|
||||
{
|
||||
PrintUsage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (extractFlags == 0)
|
||||
{
|
||||
printf("You must provide valid extract flags.\n");
|
||||
PrintUsage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Cache = new CacheClass();
|
||||
MPQHandler = new MPQManager();
|
||||
MPQHandler->Initialize();
|
||||
|
||||
if (extractFlags & Constants::EXTRACT_FLAG_DBC)
|
||||
ExtractDBCs();
|
||||
|
||||
if (extractFlags & Constants::EXTRACT_FLAG_MMAPS)
|
||||
ExtractMMaps(mapIds, threads);
|
||||
|
||||
if (extractFlags & Constants::EXTRACT_FLAG_GOB_MODELS)
|
||||
ExtractGameobjectModels();
|
||||
|
||||
if (extractFlags & Constants::EXTRACT_FLAG_TEST)
|
||||
{
|
||||
float start[] = { 16226.200195f, 16257.000000f, 13.202200f };
|
||||
float end[] = { 16245.725586f, 16382.465820f, 47.384956f };
|
||||
|
||||
//
|
||||
float m_spos[3];
|
||||
m_spos[0] = -start[1];
|
||||
m_spos[1] = start[2];
|
||||
m_spos[2] = -start[0];
|
||||
|
||||
//
|
||||
float m_epos[3];
|
||||
m_epos[0] = -end[1];
|
||||
m_epos[1] = end[2];
|
||||
m_epos[2] = -end[0];
|
||||
|
||||
//
|
||||
dtQueryFilter m_filter;
|
||||
m_filter.setIncludeFlags(Constants::POLY_AREA_ROAD | Constants::POLY_AREA_TERRAIN);
|
||||
m_filter.setExcludeFlags(Constants::POLY_AREA_WATER);
|
||||
|
||||
//
|
||||
float m_polyPickExt[3];
|
||||
m_polyPickExt[0] = 2.5f;
|
||||
m_polyPickExt[1] = 2.5f;
|
||||
m_polyPickExt[2] = 2.5f;
|
||||
|
||||
//
|
||||
dtPolyRef m_startRef;
|
||||
dtPolyRef m_endRef;
|
||||
|
||||
FILE* mmap = fopen("mmaps/001.mmap", "rb");
|
||||
dtNavMeshParams params;
|
||||
int count = fread(¶ms, sizeof(dtNavMeshParams), 1, mmap);
|
||||
fclose(mmap);
|
||||
if (count != 1)
|
||||
{
|
||||
printf("main: Error reading from .mmap\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dtNavMesh* navMesh = new dtNavMesh();
|
||||
dtNavMeshQuery* navMeshQuery = new dtNavMeshQuery();
|
||||
|
||||
navMesh->init(¶ms);
|
||||
for (int i = 0; i <= 32; ++i)
|
||||
{
|
||||
for (int j = 0; j <= 32; ++j)
|
||||
{
|
||||
char buff[100];
|
||||
sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j);
|
||||
LoadTile(navMesh, buff);
|
||||
}
|
||||
}
|
||||
|
||||
navMeshQuery->init(navMesh, 2048);
|
||||
|
||||
float nearestPt[3];
|
||||
|
||||
navMeshQuery->findNearestPoly(m_spos, m_polyPickExt, &m_filter, &m_startRef, nearestPt);
|
||||
navMeshQuery->findNearestPoly(m_epos, m_polyPickExt, &m_filter, &m_endRef, nearestPt);
|
||||
|
||||
if ( !m_startRef || !m_endRef )
|
||||
{
|
||||
std::cerr << "Could not find any nearby poly's (" << m_startRef << "," << m_endRef << ")" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hops;
|
||||
dtPolyRef* hopBuffer = new dtPolyRef[8192];
|
||||
dtStatus status = navMeshQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, hopBuffer, &hops, 8192);
|
||||
|
||||
int resultHopCount;
|
||||
float* straightPath = new float[2048*3];
|
||||
unsigned char* pathFlags = new unsigned char[2048];
|
||||
dtPolyRef* pathRefs = new dtPolyRef[2048];
|
||||
|
||||
status = navMeshQuery->findStraightPath(m_spos, m_epos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048);
|
||||
std::vector<Vector3> FinalPath;
|
||||
FinalPath.reserve(resultHopCount);
|
||||
for (int32 i = 0; i < resultHopCount; ++i)
|
||||
{
|
||||
Vector3 finalV = Utils::ToWoWCoords(Vector3(straightPath[i * 3 + 0], straightPath[i * 3 + 1], straightPath[i * 3 + 2]));
|
||||
FinalPath.push_back(finalV);
|
||||
printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "Model.h"
|
||||
#include "MPQManager.h"
|
||||
#include "Utils.h"
|
||||
|
||||
Model::Model( std::string path ) : IsCollidable(false), IsBad(false)
|
||||
{
|
||||
Stream = MPQHandler->GetFile(Utils::FixModelPath(path));
|
||||
if (!Stream)
|
||||
{
|
||||
IsBad = true;
|
||||
return;
|
||||
}
|
||||
Header.Read(Stream);
|
||||
if (Header.OffsetBoundingNormals > 0 && Header.OffsetBoundingVertices > 0 &&
|
||||
Header.OffsetBoundingTriangles > 0 && Header.BoundingRadius > 0.0f)
|
||||
{
|
||||
IsCollidable = true;
|
||||
ReadVertices();
|
||||
ReadBoundingNormals();
|
||||
ReadBoundingTriangles();
|
||||
}
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
if (Stream)
|
||||
fclose(Stream);
|
||||
}
|
||||
|
||||
void Model::ReadVertices()
|
||||
{
|
||||
fseek(Stream, Header.OffsetBoundingVertices, SEEK_SET);
|
||||
Vertices.reserve(Header.CountBoundingVertices);
|
||||
for (uint32 i = 0; i < Header.CountBoundingVertices; ++i)
|
||||
{
|
||||
Vertices.push_back(Vector3::Read(Stream));
|
||||
if (Constants::ToWoWCoords)
|
||||
Vertices[i] = Utils::ToWoWCoords(Vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::ReadBoundingTriangles()
|
||||
{
|
||||
fseek(Stream, Header.OffsetBoundingTriangles, SEEK_SET);
|
||||
Triangles.reserve(Header.CountBoundingTriangles / 3);
|
||||
for (uint32 i = 0; i < Header.CountBoundingTriangles / 3; i++)
|
||||
{
|
||||
Triangle<uint16> tri;
|
||||
tri.Type = Constants::TRIANGLE_TYPE_DOODAD;
|
||||
int count = 0;
|
||||
count += fread(&tri.V0, sizeof(uint16), 1, Stream);
|
||||
count += fread(&tri.V1, sizeof(uint16), 1, Stream);
|
||||
count += fread(&tri.V2, sizeof(uint16), 1, Stream);
|
||||
if (count != 3)
|
||||
printf("Model::ReadBoundingTriangles: Error reading data, expected 3, read %d\n", count);
|
||||
Triangles.push_back(tri);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::ReadBoundingNormals()
|
||||
{
|
||||
fseek(Stream, Header.OffsetBoundingNormals, SEEK_SET);
|
||||
Normals.reserve(Header.CountBoundingNormals);
|
||||
for (uint32 i = 0; i < Header.CountBoundingNormals; i++)
|
||||
Normals.push_back(Vector3::Read(Stream));
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
#include <vector>
|
||||
#include "Utils.h"
|
||||
|
||||
class Model
|
||||
{
|
||||
public:
|
||||
Model(std::string path);
|
||||
~Model();
|
||||
|
||||
void ReadVertices();
|
||||
void ReadBoundingTriangles();
|
||||
void ReadBoundingNormals();
|
||||
ModelHeader Header;
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Vector3> Normals;
|
||||
std::vector<Triangle<uint16> > Triangles;
|
||||
bool IsCollidable;
|
||||
FILE* Stream;
|
||||
bool IsBad;
|
||||
};
|
||||
#endif
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "ObjectDataHandler.h"
|
||||
#include "Chunk.h"
|
||||
#include "ADT.h"
|
||||
#include "ChunkedData.h"
|
||||
|
||||
void ObjectDataHandler::ProcessMapChunk( MapChunk* chunk )
|
||||
{
|
||||
ProcessInternal(chunk);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef ODATA_HNDL_H
|
||||
#define ODATA_HNDL_H
|
||||
#include "ADT.h"
|
||||
#include "MapChunk.h"
|
||||
|
||||
class ObjectDataHandler
|
||||
{
|
||||
public:
|
||||
ObjectDataHandler(ADT* _adt) : Source(_adt) {}
|
||||
|
||||
void ProcessMapChunk(MapChunk* chunk);
|
||||
virtual void ProcessInternal(MapChunk* data) = 0;
|
||||
ADT* Source;
|
||||
};
|
||||
#endif
|
||||
@@ -1,404 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "ContinentBuilder.h"
|
||||
#include "TileBuilder.h"
|
||||
#include "Geometry.h"
|
||||
#include "WorldModelRoot.h"
|
||||
#include "Constants.h"
|
||||
#include "Utils.h"
|
||||
#include "Cache.h"
|
||||
#include "ADT.h"
|
||||
#include "WDT.h"
|
||||
#include "Recast.h"
|
||||
#include "RecastAlloc.h"
|
||||
#include "DetourNavMeshBuilder.h"
|
||||
|
||||
#include <ace/Synch.h>
|
||||
|
||||
TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId) :
|
||||
World(world), X(x), Y(y), MapId(mapId), _Geometry(NULL), DataSize(0), cBuilder(_cBuilder)
|
||||
{
|
||||
// Config for normal maps
|
||||
memset(&Config, 0, sizeof(rcConfig));
|
||||
Config.cs = Constants::TileSize / 1800.0f; // TileSize / voxelSize
|
||||
Config.ch = 0.3f;
|
||||
Config.minRegionArea = 36;
|
||||
Config.mergeRegionArea = 144;
|
||||
Config.walkableSlopeAngle = 50.0f;
|
||||
Config.detailSampleDist = 3.0f;
|
||||
Config.detailSampleMaxError = 1.25f;
|
||||
Config.walkableClimb = 1.0f / Config.ch;
|
||||
Config.walkableHeight = 2.1 / Config.ch;
|
||||
Config.walkableRadius = 0.6f / Config.cs;
|
||||
Config.maxEdgeLen = Config.walkableRadius * 8;
|
||||
Config.borderSize = Config.walkableRadius + 8;
|
||||
Config.tileSize = 1800;
|
||||
Config.maxSimplificationError = 1.3f;
|
||||
Config.maxVertsPerPoly = 6;
|
||||
|
||||
// Config for instances
|
||||
memset(&InstanceConfig, 0, sizeof(rcConfig));
|
||||
InstanceConfig.cs = 0.2f;
|
||||
InstanceConfig.ch = 0.3f;
|
||||
InstanceConfig.minRegionArea = 25;
|
||||
InstanceConfig.mergeRegionArea = 100;
|
||||
InstanceConfig.walkableSlopeAngle = 50.0f;
|
||||
InstanceConfig.detailSampleDist = 3.0f;
|
||||
InstanceConfig.detailSampleMaxError = 1.5f;
|
||||
InstanceConfig.walkableClimb = 1.0f / InstanceConfig.ch;
|
||||
InstanceConfig.walkableHeight = 2.1f / InstanceConfig.ch;
|
||||
InstanceConfig.walkableRadius = 0.6f / InstanceConfig.cs;
|
||||
InstanceConfig.maxEdgeLen = 8 * InstanceConfig.walkableRadius;
|
||||
InstanceConfig.maxVertsPerPoly = 6;
|
||||
InstanceConfig.maxSimplificationError = 1.25f;
|
||||
InstanceConfig.borderSize = 0;
|
||||
|
||||
Context = new rcContext;
|
||||
}
|
||||
|
||||
void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ )
|
||||
{
|
||||
bmin = new float[3];
|
||||
bmax = new float[3];
|
||||
bmin[0] = Constants::Origin[0] /*navMeshParams.orig[0]*/ + (Constants::TileSize * X);
|
||||
bmin[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * Y);
|
||||
bmax[0] = Constants::Origin[0] /*navMeshParams.orig[0]*/ + (Constants::TileSize * (X + 1));
|
||||
bmax[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * (Y + 1));
|
||||
}
|
||||
|
||||
void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def)
|
||||
{
|
||||
_Geometry = new Geometry();
|
||||
_Geometry->Transform = true;
|
||||
|
||||
WorldModelHandler::InsertModelGeometry(_Geometry->Vertices, _Geometry->Triangles, def, root, false);
|
||||
|
||||
OutputDebugVertices();
|
||||
}
|
||||
|
||||
uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams )
|
||||
{
|
||||
float* bmin = NULL, *bmax = NULL;
|
||||
|
||||
_Geometry->CalculateBoundingBox(bmin, bmax);
|
||||
|
||||
rcVcopy(InstanceConfig.bmax, bmax);
|
||||
rcVcopy(InstanceConfig.bmin, bmin);
|
||||
|
||||
uint32 numVerts = _Geometry->Vertices.size();
|
||||
uint32 numTris = _Geometry->Triangles.size();
|
||||
float* vertices;
|
||||
int* triangles;
|
||||
uint8* areas;
|
||||
_Geometry->GetRawData(vertices, triangles, areas);
|
||||
|
||||
// this sets the dimensions of the heightfield
|
||||
rcCalcGridSize(InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, &InstanceConfig.width, &InstanceConfig.height);
|
||||
|
||||
rcHeightfield* hf = rcAllocHeightfield();
|
||||
rcCreateHeightfield(Context, *hf, InstanceConfig.width, InstanceConfig.height, InstanceConfig.bmin, InstanceConfig.bmax, InstanceConfig.cs, InstanceConfig.ch);
|
||||
|
||||
rcClearUnwalkableTriangles(Context, InstanceConfig.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas);
|
||||
rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, InstanceConfig.walkableClimb);
|
||||
|
||||
rcFilterLowHangingWalkableObstacles(Context, InstanceConfig.walkableClimb, *hf);
|
||||
rcFilterLedgeSpans(Context, InstanceConfig.walkableHeight, InstanceConfig.walkableClimb, *hf);
|
||||
rcFilterWalkableLowHeightSpans(Context, InstanceConfig.walkableHeight, *hf);
|
||||
|
||||
rcCompactHeightfield* chf = rcAllocCompactHeightfield();
|
||||
rcBuildCompactHeightfield(Context, InstanceConfig.walkableHeight, InstanceConfig.walkableClimb, *hf, *chf);
|
||||
|
||||
rcErodeWalkableArea(Context, InstanceConfig.walkableRadius, *chf);
|
||||
rcBuildDistanceField(Context, *chf);
|
||||
rcBuildRegions(Context, *chf, InstanceConfig.borderSize, InstanceConfig.minRegionArea, InstanceConfig.minRegionArea);
|
||||
|
||||
rcContourSet* contours = rcAllocContourSet();
|
||||
rcBuildContours(Context, *chf, InstanceConfig.maxSimplificationError, InstanceConfig.maxEdgeLen, *contours);
|
||||
|
||||
rcPolyMesh* pmesh = rcAllocPolyMesh();
|
||||
rcBuildPolyMesh(Context, *contours, InstanceConfig.maxVertsPerPoly, *pmesh);
|
||||
|
||||
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
|
||||
rcBuildPolyMeshDetail(Context, *pmesh, *chf, InstanceConfig.detailSampleDist, InstanceConfig.detailSampleMaxError, *dmesh);
|
||||
|
||||
// Set flags according to area types (e.g. Swim for Water)
|
||||
for (int i = 0; i < pmesh->npolys; i++)
|
||||
{
|
||||
if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
|
||||
pmesh->flags[i] = Constants::POLY_FLAG_WALK;
|
||||
else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
|
||||
pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
|
||||
}
|
||||
|
||||
dtNavMeshCreateParams params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
// PolyMesh data
|
||||
params.verts = pmesh->verts;
|
||||
params.vertCount = pmesh->nverts;
|
||||
params.polys = pmesh->polys;
|
||||
params.polyAreas = pmesh->areas;
|
||||
params.polyFlags = pmesh->flags;
|
||||
params.polyCount = pmesh->npolys;
|
||||
params.nvp = pmesh->nvp;
|
||||
// PolyMeshDetail data
|
||||
params.detailMeshes = dmesh->meshes;
|
||||
params.detailVerts = dmesh->verts;
|
||||
params.detailVertsCount = dmesh->nverts;
|
||||
params.detailTris = dmesh->tris;
|
||||
params.detailTriCount = dmesh->ntris;
|
||||
rcVcopy(params.bmin, pmesh->bmin);
|
||||
rcVcopy(params.bmax, pmesh->bmax);
|
||||
// General settings
|
||||
params.ch = InstanceConfig.ch;
|
||||
params.cs = InstanceConfig.cs;
|
||||
params.walkableClimb = InstanceConfig.walkableClimb * InstanceConfig.ch;
|
||||
params.walkableHeight = InstanceConfig.walkableHeight * InstanceConfig.ch;
|
||||
params.walkableRadius = InstanceConfig.walkableRadius * InstanceConfig.cs;
|
||||
params.tileX = X;
|
||||
params.tileY = Y;
|
||||
params.tileLayer = 0;
|
||||
params.buildBvTree = true;
|
||||
|
||||
rcVcopy(params.bmax, bmax);
|
||||
rcVcopy(params.bmin, bmin);
|
||||
|
||||
// Offmesh-connection settings
|
||||
params.offMeshConCount = 0; // none for now
|
||||
|
||||
rcFreeHeightField(hf);
|
||||
rcFreeCompactHeightfield(chf);
|
||||
rcFreeContourSet(contours);
|
||||
delete vertices;
|
||||
delete triangles;
|
||||
delete areas;
|
||||
delete bmin;
|
||||
delete bmax;
|
||||
|
||||
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == 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, skipping.\n");
|
||||
rcFreePolyMesh(pmesh);
|
||||
rcFreePolyMeshDetail(dmesh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int navDataSize;
|
||||
uint8* navData;
|
||||
printf("Creating the navmesh with %i vertices, %i polys, %i triangles!\n", params.vertCount, params.polyCount, params.detailTriCount);
|
||||
bool result = dtCreateNavMeshData(¶ms, &navData, &navDataSize);
|
||||
|
||||
rcFreePolyMesh(pmesh);
|
||||
rcFreePolyMeshDetail(dmesh);
|
||||
|
||||
if (result)
|
||||
{
|
||||
printf("NavMesh created, size %i!\n", navDataSize);
|
||||
DataSize = navDataSize;
|
||||
return navData;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams)
|
||||
{
|
||||
_Geometry = new Geometry();
|
||||
_Geometry->Transform = true;
|
||||
ADT* adt = new ADT(Utils::GetAdtPath(World, X, Y), X, Y);
|
||||
adt->Read();
|
||||
_Geometry->AddAdt(adt);
|
||||
delete adt;
|
||||
|
||||
if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty())
|
||||
return NULL;
|
||||
|
||||
float* bmin = NULL, *bmax = NULL;
|
||||
CalculateTileBounds(bmin, bmax, navMeshParams);
|
||||
_Geometry->CalculateMinMaxHeight(bmin[1], bmax[1]);
|
||||
|
||||
// again, we load everything - wasteful but who cares
|
||||
for (int ty = Y - 1; ty <= Y + 1; ty++)
|
||||
{
|
||||
for (int tx = X - 1; tx <= X + 1; tx++)
|
||||
{
|
||||
// don't load main tile again
|
||||
if (tx == X && ty == Y)
|
||||
continue;
|
||||
|
||||
ADT* _adt = new ADT(Utils::GetAdtPath(World, tx, ty), tx, ty);
|
||||
// If this condition is met, it means that this WDT does not contain the ADT
|
||||
if (!_adt->Data->Stream)
|
||||
{
|
||||
delete _adt;
|
||||
continue;
|
||||
}
|
||||
_adt->Read();
|
||||
_Geometry->AddAdt(_adt);
|
||||
delete _adt;
|
||||
}
|
||||
}
|
||||
|
||||
OutputDebugVertices();
|
||||
|
||||
uint32 numVerts = _Geometry->Vertices.size();
|
||||
uint32 numTris = _Geometry->Triangles.size();
|
||||
float* vertices;
|
||||
int* triangles;
|
||||
uint8* areas;
|
||||
_Geometry->GetRawData(vertices, triangles, areas);
|
||||
_Geometry->Vertices.clear();
|
||||
_Geometry->Triangles.clear();
|
||||
|
||||
// add border
|
||||
bmin[0] -= Config.borderSize * Config.cs;
|
||||
bmin[2] -= Config.borderSize * Config.cs;
|
||||
bmax[0] += Config.borderSize * Config.cs;
|
||||
bmax[2] += Config.borderSize * Config.cs;
|
||||
|
||||
rcHeightfield* hf = rcAllocHeightfield();
|
||||
int width = Config.tileSize + (Config.borderSize * 2);
|
||||
rcCreateHeightfield(Context, *hf, width, width, bmin, bmax, Config.cs, Config.ch);
|
||||
|
||||
rcClearUnwalkableTriangles(Context, Config.walkableSlopeAngle, vertices, numVerts, triangles, numTris, areas);
|
||||
rcRasterizeTriangles(Context, vertices, numVerts, triangles, areas, numTris, *hf, Config.walkableClimb);
|
||||
|
||||
rcFilterLowHangingWalkableObstacles(Context, Config.walkableClimb, *hf);
|
||||
rcFilterLedgeSpans(Context, Config.walkableHeight, Config.walkableClimb, *hf);
|
||||
rcFilterWalkableLowHeightSpans(Context, Config.walkableHeight, *hf);
|
||||
|
||||
rcCompactHeightfield* chf = rcAllocCompactHeightfield();
|
||||
rcBuildCompactHeightfield(Context, Config.walkableHeight, Config.walkableClimb, *hf, *chf);
|
||||
|
||||
rcErodeWalkableArea(Context, Config.walkableRadius, *chf);
|
||||
rcBuildDistanceField(Context, *chf);
|
||||
rcBuildRegions(Context, *chf, Config.borderSize, Config.minRegionArea, Config.mergeRegionArea);
|
||||
|
||||
rcContourSet* contours = rcAllocContourSet();
|
||||
rcBuildContours(Context, *chf, Config.maxSimplificationError, Config.maxEdgeLen, *contours);
|
||||
|
||||
rcPolyMesh* pmesh = rcAllocPolyMesh();
|
||||
rcBuildPolyMesh(Context, *contours, Config.maxVertsPerPoly, *pmesh);
|
||||
|
||||
rcPolyMeshDetail* dmesh = rcAllocPolyMeshDetail();
|
||||
rcBuildPolyMeshDetail(Context, *pmesh, *chf, Config.detailSampleDist, Config.detailSampleMaxError, *dmesh);
|
||||
|
||||
// Set flags according to area types (e.g. Swim for Water)
|
||||
for (int i = 0; i < pmesh->npolys; i++)
|
||||
{
|
||||
if (pmesh->areas[i] == Constants::POLY_AREA_ROAD || pmesh->areas[i] == Constants::POLY_AREA_TERRAIN)
|
||||
pmesh->flags[i] = Constants::POLY_FLAG_WALK;
|
||||
else if (pmesh->areas[i] == Constants::POLY_AREA_WATER)
|
||||
pmesh->flags[i] = Constants::POLY_FLAG_SWIM;
|
||||
}
|
||||
|
||||
dtNavMeshCreateParams params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
// PolyMesh data
|
||||
params.verts = pmesh->verts;
|
||||
params.vertCount = pmesh->nverts;
|
||||
params.polys = pmesh->polys;
|
||||
params.polyAreas = pmesh->areas;
|
||||
params.polyFlags = pmesh->flags;
|
||||
params.polyCount = pmesh->npolys;
|
||||
params.nvp = pmesh->nvp;
|
||||
// PolyMeshDetail data
|
||||
params.detailMeshes = dmesh->meshes;
|
||||
params.detailVerts = dmesh->verts;
|
||||
params.detailVertsCount = dmesh->nverts;
|
||||
params.detailTris = dmesh->tris;
|
||||
params.detailTriCount = dmesh->ntris;
|
||||
// General settings
|
||||
params.ch = Config.ch;
|
||||
params.cs = Config.cs;
|
||||
params.walkableClimb = Config.walkableClimb * Config.ch;
|
||||
params.walkableHeight = Config.walkableHeight * Config.ch;
|
||||
params.walkableRadius = Config.walkableRadius * Config.cs;
|
||||
params.tileX = X;
|
||||
params.tileY = Y;
|
||||
params.tileLayer = 0;
|
||||
params.buildBvTree = true;
|
||||
|
||||
// Recalculate the bounds with the added geometry
|
||||
float* bmin2 = NULL, *bmax2 = NULL;
|
||||
CalculateTileBounds(bmin2, bmax2, navMeshParams);
|
||||
bmin2[1] = bmin[1];
|
||||
bmax2[1] = bmax[1];
|
||||
|
||||
rcVcopy(params.bmax, bmax2);
|
||||
rcVcopy(params.bmin, bmin2);
|
||||
|
||||
// Offmesh-connection settings
|
||||
params.offMeshConCount = 0; // none for now
|
||||
|
||||
rcFreeHeightField(hf);
|
||||
rcFreeCompactHeightfield(chf);
|
||||
rcFreeContourSet(contours);
|
||||
delete vertices;
|
||||
delete triangles;
|
||||
delete areas;
|
||||
delete bmin;
|
||||
delete bmax;
|
||||
|
||||
if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == 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("[%02i, %02i] No polygons to build on tile, skipping.\n", X, Y);
|
||||
rcFreePolyMesh(pmesh);
|
||||
rcFreePolyMeshDetail(dmesh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int navDataSize;
|
||||
uint8* navData;
|
||||
printf("[%02i, %02i] Creating the navmesh with %i vertices, %i polys, %i triangles!\n", X, Y, params.vertCount, params.polyCount, params.detailTriCount);
|
||||
bool result = dtCreateNavMeshData(¶ms, &navData, &navDataSize);
|
||||
|
||||
rcFreePolyMesh(pmesh);
|
||||
rcFreePolyMeshDetail(dmesh);
|
||||
|
||||
if (result)
|
||||
{
|
||||
printf("[%02i, %02i] NavMesh created, size %i!\n", X, Y, navDataSize);
|
||||
DataSize = navDataSize;
|
||||
return navData;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TileBuilder::OutputDebugVertices()
|
||||
{
|
||||
if (Constants::Debug)
|
||||
{
|
||||
char buff[100];
|
||||
sprintf(buff, "mmaps/%s_%02u%02u.obj", World.c_str(), Y, X);
|
||||
FILE* debug = fopen(buff, "wb");
|
||||
for (uint32 i = 0; i < _Geometry->Vertices.size(); ++i)
|
||||
{
|
||||
const Vector3& vector = _Geometry->Vertices[i];
|
||||
fprintf(debug, "v %f %f %f\n", vector.x, vector.y, vector.z);
|
||||
}
|
||||
for (uint32 i = 0; i < _Geometry->Triangles.size(); ++i)
|
||||
{
|
||||
const Triangle<uint32>& triangle = _Geometry->Triangles[i];
|
||||
fprintf(debug, "f %u %u %u\n", triangle.V0 + 1, triangle.V1 + 1, triangle.V2 + 1);
|
||||
}
|
||||
fclose(debug);
|
||||
}
|
||||
}
|
||||
|
||||
TileBuilder::~TileBuilder()
|
||||
{
|
||||
delete Context;
|
||||
delete _Geometry;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef TILE_BUILD_H
|
||||
#define TILE_BUILD_H
|
||||
#include <string>
|
||||
#include "Recast.h"
|
||||
|
||||
#include "Geometry.h"
|
||||
#include "WorldModelRoot.h"
|
||||
|
||||
class ContinentBuilder;
|
||||
class WDT;
|
||||
|
||||
class TileBuilder
|
||||
{
|
||||
public:
|
||||
TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId);
|
||||
~TileBuilder();
|
||||
|
||||
void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams);
|
||||
uint8* BuildTiled(dtNavMeshParams& navMeshParams);
|
||||
uint8* BuildInstance(dtNavMeshParams& navMeshParams);
|
||||
void AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def);
|
||||
void OutputDebugVertices();
|
||||
std::string World;
|
||||
int X;
|
||||
int Y;
|
||||
int MapId;
|
||||
rcConfig Config;
|
||||
rcConfig InstanceConfig;
|
||||
rcContext* Context;
|
||||
Geometry* _Geometry;
|
||||
uint32 DataSize;
|
||||
ContinentBuilder* cBuilder;
|
||||
};
|
||||
#endif
|
||||
@@ -1,554 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "Utils.h"
|
||||
#include "WorldModelHandler.h"
|
||||
#include "Constants.h"
|
||||
#include <cstring>
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Quat.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "direct.h"
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
const float Constants::TileSize = 533.0f + (1/3.0f);
|
||||
const float Constants::MaxXY = 32.0f * Constants::TileSize;
|
||||
const float Constants::ChunkSize = Constants::TileSize / 16.0f;
|
||||
const float Constants::UnitSize = Constants::ChunkSize / 8.0f;
|
||||
const float Constants::Origin[] = { -Constants::MaxXY, 0.0f, -Constants::MaxXY };
|
||||
const float Constants::PI = 3.1415926f;
|
||||
const float Constants::MaxStandableHeight = 1.5f;
|
||||
const char* Constants::VMAPMagic = "VMAP041";
|
||||
bool Constants::ToWoWCoords = false;
|
||||
bool Constants::Debug = false;
|
||||
const float Constants::BaseUnitDim = 0.533333f;
|
||||
const int Constants::VertexPerMap = (Constants::TileSize / Constants::BaseUnitDim) + 0.5f;
|
||||
const int Constants::VertexPerTile = 40;
|
||||
const int Constants::TilesPerMap = Constants::VertexPerMap / Constants::VertexPerTile;
|
||||
|
||||
void Utils::CreateDir( const std::string& Path )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_mkdir( Path.c_str());
|
||||
#else
|
||||
mkdir( Path.c_str(), 0777 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Utils::Reverse(char word[])
|
||||
{
|
||||
int len = strlen(word);
|
||||
for (int i = 0;i < len / 2; i++)
|
||||
{
|
||||
word[i] ^= word[len-i-1];
|
||||
word[len-i-1] ^= word[i];
|
||||
word[i] ^= word[len-i-1];
|
||||
}
|
||||
}
|
||||
|
||||
std::string Utils::ReadString( FILE* file )
|
||||
{
|
||||
std::string ret;
|
||||
while (true)
|
||||
{
|
||||
char b;
|
||||
if (fread(&b, sizeof(char), 1, file) != 1 || b == 0)
|
||||
break;
|
||||
ret.push_back(b);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 Utils::Size( FILE* file )
|
||||
{
|
||||
// store the old position
|
||||
uint32 offset = ftell(file);
|
||||
// Get file size
|
||||
fseek(file, 0, SEEK_END);
|
||||
uint32 size = ftell(file);
|
||||
// reset back to the old position
|
||||
fseek(file, offset, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
|
||||
Vector3 Utils::ToRecast(const Vector3& val )
|
||||
{
|
||||
return Vector3(-val.y, val.z, -val.x);
|
||||
}
|
||||
|
||||
std::string Utils::GetAdtPath(const std::string& world, int x, int y )
|
||||
{
|
||||
return "World\\Maps\\" + world + "\\" + world + "_" + Utils::ToString(x) + "_" + Utils::ToString(y) + ".adt";
|
||||
}
|
||||
|
||||
std::string Utils::FixModelPath(const std::string& path )
|
||||
{
|
||||
return Utils::GetPathBase(path) + ".M2";
|
||||
}
|
||||
|
||||
Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate)
|
||||
{
|
||||
// Sources of information:
|
||||
/// http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18&oldid=3715
|
||||
|
||||
// This function applies to both external doodads and WMOs
|
||||
|
||||
// Rotate our Doodad vertex
|
||||
G3D::Matrix4 rot = G3D::Matrix3::fromEulerAnglesXYZ(Utils::ToRadians(def.Rotation.z), Utils::ToRadians(-def.Rotation.x), Utils::ToRadians(def.Rotation.y + 180));
|
||||
Vector3 ret = Utils::VectorTransform(vec, rot);
|
||||
|
||||
// And finally scale and translate it to our origin
|
||||
ret = ret * def.Scale();
|
||||
if (translate)
|
||||
ret = ret + Vector3(Constants::MaxXY - def.Position.z, Constants::MaxXY - def.Position.x, def.Position.y);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate )
|
||||
{
|
||||
G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW);
|
||||
|
||||
Vector3 ret = Utils::VectorTransform(vec, G3D::Matrix4(quat.toRotationMatrix()));
|
||||
ret = ret * (inst.Scale / 1024.0f);
|
||||
if (translate)
|
||||
ret = ret + Vector3(Constants::MaxXY - inst.Position.z, Constants::MaxXY - inst.Position.x, inst.Position.y);
|
||||
return ret;
|
||||
}
|
||||
|
||||
float Utils::ToRadians( float degrees )
|
||||
{
|
||||
return Constants::PI * degrees / 180.0f;
|
||||
}
|
||||
|
||||
Vector3 Utils::VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal )
|
||||
{
|
||||
G3D::Vector3 ret(vec.x, vec.y, vec.z);
|
||||
ret = matrix.homoMul(ret, normal ? 0 : 1);
|
||||
return Vector3(ret.x, ret.y, ret.z);
|
||||
}
|
||||
|
||||
std::string Utils::GetPathBase(const std::string& path )
|
||||
{
|
||||
size_t lastIndex = path.find_last_of(".");
|
||||
if (lastIndex != std::string::npos)
|
||||
return path.substr(0, lastIndex);
|
||||
return path;
|
||||
}
|
||||
|
||||
Vector3 Vector3::Read( FILE* file )
|
||||
{
|
||||
Vector3 ret;
|
||||
if (fread(&ret, sizeof(Vector3), 1, file) != 1)
|
||||
printf("Vector3::Read: Failed to read some data expected 1, read 0\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate)
|
||||
{
|
||||
if (Utils::Distance(height, 0.0f) > 0.5f)
|
||||
basePosition.z = 0.0f;
|
||||
return Utils::TransformDoodadVertex(def, basePosition + Vector3(x * Constants::UnitSize, y * Constants::UnitSize, height), translate);
|
||||
}
|
||||
|
||||
float Utils::Distance( float x, float y )
|
||||
{
|
||||
return sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
std::string Utils::Replace( std::string str, const std::string& oldStr, const std::string& newStr )
|
||||
{
|
||||
size_t pos = 0;
|
||||
while((pos = str.find(oldStr, pos)) != std::string::npos)
|
||||
{
|
||||
str.replace(pos, oldStr.length(), newStr);
|
||||
pos += newStr.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void Utils::SaveToDisk( FILE* stream, const std::string& path )
|
||||
{
|
||||
FILE* disk = fopen(path.c_str(), "wb");
|
||||
if (!disk)
|
||||
{
|
||||
printf("SaveToDisk: Could not save file %s to disk, please verify that you have write permissions on that directory\n", path.c_str());
|
||||
fclose(stream);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 size = Utils::Size(stream);
|
||||
uint8* data = new uint8[size];
|
||||
// Read the data to an array
|
||||
size_t read = fread(data, size, 1, stream);
|
||||
if (read != 1)
|
||||
{
|
||||
printf("SaveToDisk: Error reading from Stream while trying to save file %s to disk.\n", path.c_str());
|
||||
fclose(disk);
|
||||
fclose(stream);
|
||||
return;
|
||||
}
|
||||
|
||||
// And write it in the file
|
||||
size_t wrote = fwrite(data, size, 1, disk);
|
||||
if (wrote != 1)
|
||||
{
|
||||
printf("SaveToDisk: Error writing to the file while trying to save %s to disk.\n", path.c_str());
|
||||
fclose(stream);
|
||||
fclose(disk);
|
||||
return;
|
||||
}
|
||||
|
||||
// Close the filestream
|
||||
fclose(disk);
|
||||
fclose(stream);
|
||||
|
||||
// Free the used memory
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
Vector3 Utils::ToWoWCoords(const Vector3& vec )
|
||||
{
|
||||
return Vector3(-vec.z, -vec.x, vec.y);
|
||||
}
|
||||
|
||||
std::string Utils::GetExtension( std::string path )
|
||||
{
|
||||
std::string::size_type idx = path.rfind('.');
|
||||
std::string extension = "";
|
||||
|
||||
if(idx != std::string::npos)
|
||||
extension = path.substr(idx+1);
|
||||
return extension;
|
||||
}
|
||||
|
||||
void MapChunkHeader::Read(FILE* stream)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
count += fread(&Flags, sizeof(uint32), 1, stream);
|
||||
count += fread(&IndexX, sizeof(uint32), 1, stream);
|
||||
count += fread(&IndexY, sizeof(uint32), 1, stream);
|
||||
count += fread(&Layers, sizeof(uint32), 1, stream);
|
||||
count += fread(&DoodadRefs, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCVT, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCNR, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCLY, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCRF, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCAL, sizeof(uint32), 1, stream);
|
||||
count += fread(&SizeMCAL, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCSH, sizeof(uint32), 1, stream);
|
||||
count += fread(&SizeMCSH, sizeof(uint32), 1, stream);
|
||||
count += fread(&AreaId, sizeof(uint32), 1, stream);
|
||||
count += fread(&MapObjectRefs, sizeof(uint32), 1, stream);
|
||||
count += fread(&Holes, sizeof(uint32), 1, stream);
|
||||
LowQualityTextureMap = new uint32[4];
|
||||
count += fread(LowQualityTextureMap, sizeof(uint32), 4, stream);
|
||||
count += fread(&PredTex, sizeof(uint32), 1, stream);
|
||||
count += fread(&NumberEffectDoodad, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCSE, sizeof(uint32), 1, stream);
|
||||
count += fread(&SoundEmitters, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCLQ, sizeof(uint32), 1, stream);
|
||||
count += fread(&SizeMCLQ, sizeof(uint32), 1, stream);
|
||||
Position = Vector3::Read(stream);
|
||||
count += fread(&OffsetMCCV, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 27)
|
||||
printf("MapChunkHeader::Read: Failed to read some data expected 27, read %d\n", count);
|
||||
}
|
||||
|
||||
void MHDR::Read(FILE* stream)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
count += fread(&Flags, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMCIN, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMTEX, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMMDX, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMMID, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMWMO, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMWID, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMDDF, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMODF, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMFBO, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMH2O, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetMTFX, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 12)
|
||||
printf("MHDR::Read: Failed to read some data expected 12, read %d\n", count);
|
||||
}
|
||||
|
||||
void ModelHeader::Read(FILE* stream)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
count += fread(&Magic, sizeof(char), 4, stream);
|
||||
Magic[4] = '\0'; // null-terminate it.
|
||||
count += fread(&Version, sizeof(uint32), 1, stream);
|
||||
count += fread(&LengthModelName, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetName, sizeof(uint32), 1, stream);
|
||||
count += fread(&ModelFlags, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountGlobalSequences, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetGlobalSequences, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountAnimations, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetAnimations, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountAnimationLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetAnimationLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountBones, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetBones, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountKeyBoneLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetKeyBoneLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountVertices, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetVertices, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountViews, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountColors, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetColors, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountTextures, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetTextures, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountTransparency, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetTransparency, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountUvAnimation, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetUvAnimation, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountTexReplace, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetTexReplace, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountRenderFlags, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetRenderFlags, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountBoneLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetBoneLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountTexLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetTexLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountTexUnits, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetTexUnits, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountTransLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetTransLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountUvAnimLookup, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetUvAnimLookup, sizeof(uint32), 1, stream);
|
||||
VertexBox[0] = Vector3::Read(stream);
|
||||
VertexBox[1] = Vector3::Read(stream);
|
||||
count += fread(&VertexRadius, sizeof(float), 1, stream);
|
||||
BoundingBox[0] = Vector3::Read(stream);
|
||||
BoundingBox[1] = Vector3::Read(stream);
|
||||
count += fread(&BoundingRadius, sizeof(float), 1, stream);
|
||||
count += fread(&CountBoundingTriangles, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetBoundingTriangles, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountBoundingVertices, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetBoundingVertices, sizeof(uint32), 1, stream);
|
||||
count += fread(&CountBoundingNormals, sizeof(uint32), 1, stream);
|
||||
count += fread(&OffsetBoundingNormals, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 51)
|
||||
printf("ModelHeader::Read: Failed to read some data expected 51, read %d\n", count);
|
||||
|
||||
}
|
||||
|
||||
WorldModelHeader WorldModelHeader::Read(FILE* stream)
|
||||
{
|
||||
WorldModelHeader ret;
|
||||
int count = 0;
|
||||
|
||||
count += fread(&ret.CountMaterials, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountGroups, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountPortals, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountLights, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountModels, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountDoodads, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountSets, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.AmbientColorUnk, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.WmoId, sizeof(uint32), 1, stream);
|
||||
ret.BoundingBox[0] = Vector3::Read(stream);
|
||||
ret.BoundingBox[1] = Vector3::Read(stream);
|
||||
count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 10)
|
||||
printf("WorldModelHeader::Read: Failed to read some data expected 10, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DoodadInstance DoodadInstance::Read(FILE* stream)
|
||||
{
|
||||
DoodadInstance ret;
|
||||
int count = 0;
|
||||
|
||||
count += fread(&ret.FileOffset, sizeof(uint32), 1, stream);
|
||||
ret.Position = Vector3::Read(stream);
|
||||
count += fread(&ret.QuatW, sizeof(float), 1, stream);
|
||||
count += fread(&ret.QuatX, sizeof(float), 1, stream);
|
||||
count += fread(&ret.QuatY, sizeof(float), 1, stream);
|
||||
count += fread(&ret.QuatZ, sizeof(float), 1, stream);
|
||||
count += fread(&ret.Scale, sizeof(float), 1, stream);
|
||||
count += fread(&ret.LightColor, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 7)
|
||||
printf("DoodadInstance::Read: Failed to read some data expected 7, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DoodadSet DoodadSet::Read(FILE* stream)
|
||||
{
|
||||
DoodadSet ret;
|
||||
char name[21];
|
||||
int count = 0;
|
||||
|
||||
count += fread(&name, sizeof(char), 20, stream);
|
||||
name[20] = '\0';
|
||||
ret.Name = name;
|
||||
count += fread(&ret.FirstInstanceIndex, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountInstances, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.UnknownZero, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 23)
|
||||
printf("DoodadSet::Read: Failed to read some data expected 23, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LiquidHeader LiquidHeader::Read(FILE* stream)
|
||||
{
|
||||
LiquidHeader ret;
|
||||
int count = 0;
|
||||
count += fread(&ret.CountXVertices, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountYVertices, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.Width, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.Height, sizeof(uint32), 1, stream);
|
||||
ret.BaseLocation = Vector3::Read(stream);
|
||||
count += fread(&ret.MaterialId, sizeof(uint16), 1, stream);
|
||||
|
||||
if (count != 5)
|
||||
printf("LiquidHeader::Read: Failed to read some data expected 5, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LiquidData LiquidData::Read(FILE* stream, LiquidHeader& header)
|
||||
{
|
||||
LiquidData ret;
|
||||
ret.HeightMap = new float*[header.CountXVertices];
|
||||
for (uint32 i = 0; i < header.CountXVertices; ++i)
|
||||
ret.HeightMap[i] = new float[header.CountYVertices];
|
||||
|
||||
ret.RenderFlags = new uint8*[header.Width];
|
||||
for (uint32 i = 0; i < header.Width; ++i)
|
||||
ret.RenderFlags[i] = new uint8[header.Height];
|
||||
|
||||
for (uint32 y = 0; y < header.CountYVertices; y++)
|
||||
{
|
||||
for (uint32 x = 0; x < header.CountXVertices; x++)
|
||||
{
|
||||
uint32 discard;
|
||||
float tmp;
|
||||
if (fread(&discard, sizeof(uint32), 1, stream) == 1 &&
|
||||
fread(&tmp, sizeof(float), 1, stream) == 1)
|
||||
{
|
||||
ret.HeightMap[x][y] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 y = 0; y < header.Height; y++)
|
||||
{
|
||||
for (uint32 x = 0; x < header.Width; x++)
|
||||
{
|
||||
uint8 tmp = 0;
|
||||
if (fread(&tmp, sizeof(uint8), 1, stream) == 1)
|
||||
ret.RenderFlags[x][y] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
H2ORenderMask H2ORenderMask::Read(FILE* stream)
|
||||
{
|
||||
H2ORenderMask ret;
|
||||
int32 count;
|
||||
if ((count = fread(&ret.Mask, sizeof(uint8), 8, stream)) != 8)
|
||||
printf("H2OHeader::Read: Failed to read some data expected 8, read %d\n", count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MCNKLiquidData::IsWater(int x, int y, float height)
|
||||
{
|
||||
if (!Heights)
|
||||
return false;
|
||||
if (!Mask.ShouldRender(x, y))
|
||||
return false;
|
||||
float diff = Heights[x][y] - height;
|
||||
if (diff > Constants::MaxStandableHeight)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
H2OHeader H2OHeader::Read(FILE* stream)
|
||||
{
|
||||
H2OHeader ret;
|
||||
int count = 0;
|
||||
count += fread(&ret.OffsetInformation, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.LayerCount, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.OffsetRender, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 3)
|
||||
printf("H2OHeader::Read: Failed to read some data expected 3, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
H2OInformation H2OInformation::Read(FILE* stream)
|
||||
{
|
||||
H2OInformation ret;
|
||||
int count = 0;
|
||||
count += fread(&ret.LiquidType, sizeof(uint16), 1, stream);
|
||||
count += fread(&ret.Flags, sizeof(uint16), 1, stream);
|
||||
count += fread(&ret.HeightLevel1, sizeof(float), 1, stream);
|
||||
count += fread(&ret.HeightLevel2, sizeof(float), 1, stream);
|
||||
count += fread(&ret.OffsetX, sizeof(uint8), 1, stream);
|
||||
count += fread(&ret.OffsetY, sizeof(uint8), 1, stream);
|
||||
count += fread(&ret.Width, sizeof(uint8), 1, stream);
|
||||
count += fread(&ret.Height, sizeof(uint8), 1, stream);
|
||||
count += fread(&ret.OffsetMask2, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.OffsetHeightmap, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 10)
|
||||
printf("H2OInformation::Read: Failed to read some data expected 10, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* Utils::GetPlainName(const char* FileName)
|
||||
{
|
||||
char* temp;
|
||||
|
||||
if((temp = (char*)strrchr(FileName, '\\')) != NULL)
|
||||
FileName = temp + 1;
|
||||
return (char*)FileName;
|
||||
}
|
||||
|
||||
WMOGroupHeader WMOGroupHeader::Read( FILE* stream )
|
||||
{
|
||||
WMOGroupHeader ret;
|
||||
int count = 0;
|
||||
count += fread(&ret.OffsetGroupName, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.OffsetDescriptiveName, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.Flags, sizeof(uint32), 1, stream);
|
||||
ret.BoundingBox[0] = Vector3::Read(stream);
|
||||
ret.BoundingBox[1] = Vector3::Read(stream);
|
||||
count += fread(&ret.OffsetPortals, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountPortals, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.CountBatches, sizeof(uint16), 4, stream);
|
||||
count += fread(&ret.Fogs, sizeof(uint8), 4, stream);
|
||||
count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream);
|
||||
count += fread(&ret.WmoId, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 15)
|
||||
printf("WMOGroupHeader::Read: Failed to read some data expected 15, read %d\n", count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,397 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
#include "Define.h"
|
||||
#include "Constants.h"
|
||||
|
||||
#include <ace/Stack_Trace.h>
|
||||
|
||||
struct WorldModelDefinition;
|
||||
class DoodadDefinition;
|
||||
class DoodadInstance;
|
||||
|
||||
#define ASSERT(assertion) { if (!(assertion)) { ACE_Stack_Trace st; fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } }
|
||||
|
||||
struct Vector3
|
||||
{
|
||||
Vector3() {}
|
||||
Vector3(float X, float Y, float Z) : x(X), y(Y), z(Z) {}
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
Vector3 operator +(Vector3 const& other) const
|
||||
{
|
||||
return Vector3(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
Vector3 operator -(Vector3 const& other) const
|
||||
{
|
||||
return Vector3(x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector3 operator *(T s) const
|
||||
{
|
||||
return Vector3(x * s, y * s, z * s);
|
||||
}
|
||||
|
||||
static Vector3 Read(FILE* file);
|
||||
};
|
||||
|
||||
struct TilePos
|
||||
{
|
||||
TilePos(int x, int y) : X(x), Y(y) {}
|
||||
int X;
|
||||
int Y;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Triangle
|
||||
{
|
||||
Triangle() {}
|
||||
Triangle(Constants::TriangleType type, T v0, T v1, T v2) : V0(v0), V1(v1), V2(v2), Type(type) {}
|
||||
T V0;
|
||||
T V1;
|
||||
T V2;
|
||||
Constants::TriangleType Type;
|
||||
};
|
||||
|
||||
class MapChunkHeader
|
||||
{
|
||||
public:
|
||||
MapChunkHeader() {}
|
||||
uint32 Flags;
|
||||
uint32 IndexX;
|
||||
uint32 IndexY;
|
||||
uint32 Layers;
|
||||
uint32 DoodadRefs;
|
||||
uint32 OffsetMCVT;
|
||||
uint32 OffsetMCNR;
|
||||
uint32 OffsetMCLY;
|
||||
uint32 OffsetMCRF;
|
||||
uint32 OffsetMCAL;
|
||||
uint32 SizeMCAL;
|
||||
uint32 OffsetMCSH;
|
||||
uint32 SizeMCSH;
|
||||
uint32 AreaId;
|
||||
uint32 MapObjectRefs;
|
||||
uint32 Holes;
|
||||
uint32* LowQualityTextureMap;
|
||||
uint32 PredTex;
|
||||
uint32 NumberEffectDoodad;
|
||||
uint32 OffsetMCSE;
|
||||
uint32 SoundEmitters;
|
||||
uint32 OffsetMCLQ;
|
||||
uint32 SizeMCLQ;
|
||||
Vector3 Position;
|
||||
uint32 OffsetMCCV;
|
||||
|
||||
void Read(FILE* stream);
|
||||
};
|
||||
|
||||
class MHDR
|
||||
{
|
||||
public:
|
||||
MHDR() {}
|
||||
uint32 Flags;
|
||||
uint32 OffsetMCIN;
|
||||
uint32 OffsetMTEX;
|
||||
uint32 OffsetMMDX;
|
||||
uint32 OffsetMMID;
|
||||
uint32 OffsetMWMO;
|
||||
uint32 OffsetMWID;
|
||||
uint32 OffsetMDDF;
|
||||
uint32 OffsetMODF;
|
||||
uint32 OffsetMFBO;
|
||||
uint32 OffsetMH2O;
|
||||
uint32 OffsetMTFX;
|
||||
|
||||
void Read(FILE* stream);
|
||||
};
|
||||
|
||||
class ModelHeader
|
||||
{
|
||||
public:
|
||||
char Magic[5];
|
||||
uint32 Version;
|
||||
uint32 LengthModelName;
|
||||
uint32 OffsetName;
|
||||
uint32 ModelFlags;
|
||||
uint32 CountGlobalSequences;
|
||||
uint32 OffsetGlobalSequences;
|
||||
uint32 CountAnimations;
|
||||
uint32 OffsetAnimations;
|
||||
uint32 CountAnimationLookup;
|
||||
uint32 OffsetAnimationLookup;
|
||||
uint32 CountBones;
|
||||
uint32 OffsetBones;
|
||||
uint32 CountKeyBoneLookup;
|
||||
uint32 OffsetKeyBoneLookup;
|
||||
uint32 CountVertices;
|
||||
uint32 OffsetVertices;
|
||||
uint32 CountViews;
|
||||
uint32 CountColors;
|
||||
uint32 OffsetColors;
|
||||
uint32 CountTextures;
|
||||
uint32 OffsetTextures;
|
||||
uint32 CountTransparency;
|
||||
uint32 OffsetTransparency;
|
||||
uint32 CountUvAnimation;
|
||||
uint32 OffsetUvAnimation;
|
||||
uint32 CountTexReplace;
|
||||
uint32 OffsetTexReplace;
|
||||
uint32 CountRenderFlags;
|
||||
uint32 OffsetRenderFlags;
|
||||
uint32 CountBoneLookup;
|
||||
uint32 OffsetBoneLookup;
|
||||
uint32 CountTexLookup;
|
||||
uint32 OffsetTexLookup;
|
||||
uint32 CountTexUnits;
|
||||
uint32 OffsetTexUnits;
|
||||
uint32 CountTransLookup;
|
||||
uint32 OffsetTransLookup;
|
||||
uint32 CountUvAnimLookup;
|
||||
uint32 OffsetUvAnimLookup;
|
||||
Vector3 VertexBox[2];
|
||||
float VertexRadius;
|
||||
Vector3 BoundingBox[2];
|
||||
float BoundingRadius;
|
||||
uint32 CountBoundingTriangles;
|
||||
uint32 OffsetBoundingTriangles;
|
||||
uint32 CountBoundingVertices;
|
||||
uint32 OffsetBoundingVertices;
|
||||
uint32 CountBoundingNormals;
|
||||
uint32 OffsetBoundingNormals;
|
||||
|
||||
void Read(FILE* stream);
|
||||
};
|
||||
|
||||
class WorldModelHeader
|
||||
{
|
||||
public:
|
||||
WorldModelHeader() {}
|
||||
uint32 CountMaterials;
|
||||
uint32 CountGroups;
|
||||
uint32 CountPortals;
|
||||
uint32 CountLights;
|
||||
uint32 CountModels;
|
||||
uint32 CountDoodads;
|
||||
uint32 CountSets;
|
||||
uint32 AmbientColorUnk;
|
||||
uint32 WmoId;
|
||||
Vector3 BoundingBox[2];
|
||||
uint32 LiquidTypeRelated;
|
||||
|
||||
static WorldModelHeader Read(FILE* stream);
|
||||
};
|
||||
|
||||
class DoodadInstance
|
||||
{
|
||||
public:
|
||||
DoodadInstance() {}
|
||||
uint32 FileOffset;
|
||||
std::string File;
|
||||
Vector3 Position;
|
||||
float QuatW;
|
||||
float QuatX;
|
||||
float QuatY;
|
||||
float QuatZ;
|
||||
float Scale;
|
||||
uint32 LightColor;
|
||||
|
||||
static DoodadInstance Read(FILE* stream);
|
||||
};
|
||||
|
||||
class DoodadSet
|
||||
{
|
||||
public:
|
||||
DoodadSet() {}
|
||||
std::string Name;
|
||||
uint32 FirstInstanceIndex;
|
||||
uint32 CountInstances;
|
||||
uint32 UnknownZero;
|
||||
|
||||
static DoodadSet Read(FILE* stream);
|
||||
};
|
||||
|
||||
class LiquidHeader
|
||||
{
|
||||
public:
|
||||
LiquidHeader() {}
|
||||
uint32 CountXVertices;
|
||||
uint32 CountYVertices;
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
Vector3 BaseLocation;
|
||||
uint16 MaterialId;
|
||||
|
||||
static LiquidHeader Read(FILE* stream);
|
||||
};
|
||||
|
||||
class LiquidData
|
||||
{
|
||||
public:
|
||||
LiquidData() {}
|
||||
float** HeightMap;
|
||||
uint8** RenderFlags;
|
||||
|
||||
bool ShouldRender(int x, int y)
|
||||
{
|
||||
return RenderFlags[x][y] != 0x0F;
|
||||
}
|
||||
|
||||
static LiquidData Read(FILE* stream, LiquidHeader& header);
|
||||
};
|
||||
|
||||
class H2ORenderMask
|
||||
{
|
||||
public:
|
||||
H2ORenderMask() {}
|
||||
uint8 Mask[8];
|
||||
|
||||
bool ShouldRender(int x, int y)
|
||||
{
|
||||
return (Mask[y] >> x & 1) != 0;
|
||||
}
|
||||
|
||||
static H2ORenderMask Read(FILE* stream);
|
||||
};
|
||||
|
||||
class MCNKLiquidData
|
||||
{
|
||||
public:
|
||||
MCNKLiquidData() {}
|
||||
MCNKLiquidData(float** heights, H2ORenderMask mask) : Heights(heights), Mask(mask) {}
|
||||
|
||||
float** Heights;
|
||||
H2ORenderMask Mask;
|
||||
|
||||
bool IsWater(int x, int y, float height);
|
||||
};
|
||||
|
||||
class H2OHeader
|
||||
{
|
||||
public:
|
||||
H2OHeader() {}
|
||||
uint32 OffsetInformation;
|
||||
uint32 LayerCount;
|
||||
uint32 OffsetRender;
|
||||
|
||||
static H2OHeader Read(FILE* stream);
|
||||
};
|
||||
|
||||
class H2OInformation
|
||||
{
|
||||
public:
|
||||
H2OInformation() {}
|
||||
uint16 LiquidType;
|
||||
uint16 Flags;
|
||||
float HeightLevel1;
|
||||
float HeightLevel2;
|
||||
uint8 OffsetX;
|
||||
uint8 OffsetY;
|
||||
uint8 Width;
|
||||
uint8 Height;
|
||||
uint32 OffsetMask2;
|
||||
uint32 OffsetHeightmap;
|
||||
|
||||
static H2OInformation Read(FILE* stream);
|
||||
};
|
||||
|
||||
class WMOGroupHeader
|
||||
{
|
||||
public:
|
||||
WMOGroupHeader() {}
|
||||
|
||||
uint32 OffsetGroupName;
|
||||
uint32 OffsetDescriptiveName;
|
||||
uint32 Flags;
|
||||
Vector3 BoundingBox[2];
|
||||
uint32 OffsetPortals;
|
||||
uint32 CountPortals;
|
||||
uint16 CountBatches[4];
|
||||
uint8 Fogs[4];
|
||||
uint32 LiquidTypeRelated;
|
||||
uint32 WmoId;
|
||||
|
||||
static WMOGroupHeader Read(FILE* stream);
|
||||
};
|
||||
|
||||
// Dummy class to act as an interface.
|
||||
class IDefinition
|
||||
{
|
||||
public:
|
||||
Vector3 Position;
|
||||
Vector3 Rotation;
|
||||
virtual float Scale() const { return 1.0f; };
|
||||
};
|
||||
|
||||
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
||||
#define MMAP_VERSION 3
|
||||
|
||||
struct MmapTileHeader
|
||||
{
|
||||
uint32 mmapMagic;
|
||||
uint32 dtVersion;
|
||||
uint32 mmapVersion;
|
||||
uint32 size;
|
||||
bool usesLiquids;
|
||||
|
||||
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
||||
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
|
||||
};
|
||||
|
||||
class Utils
|
||||
{
|
||||
public:
|
||||
static void Reverse(char word[]);
|
||||
static std::string ReadString(FILE* file);
|
||||
static uint32 Size(FILE* file);
|
||||
static Vector3 ToRecast(const Vector3& val );
|
||||
static std::string GetAdtPath(const std::string& world, int x, int y);
|
||||
static std::string FixModelPath(const std::string& path);
|
||||
/// They say its better to declare template functions in the header files.
|
||||
template <typename T>
|
||||
static std::string ToString(T val)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << val;
|
||||
return ss.str();
|
||||
}
|
||||
static float ToRadians(float degrees);
|
||||
static std::string GetPathBase(const std::string& path);
|
||||
static Vector3 GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int /*x*/, int /*y*/, bool translate = true);
|
||||
static float Distance(float x, float y);
|
||||
template<typename T>
|
||||
static bool IsAllZero(T* arr, uint32 size)
|
||||
{
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
if (arr[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static std::string Replace( std::string str, const std::string& oldStr, const std::string& newStr );
|
||||
static void CreateDir( const std::string& Path );
|
||||
static void SaveToDisk(FILE* stream, const std::string& path);
|
||||
static Vector3 ToWoWCoords(const Vector3& vec );
|
||||
static std::string GetExtension( std::string path );
|
||||
static char* GetPlainName(const char* FileName);
|
||||
static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate = true);
|
||||
static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false );
|
||||
static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate = true );
|
||||
};
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "WDT.h"
|
||||
#include "Chunk.h"
|
||||
#include "ChunkedData.h"
|
||||
#include "Utils.h"
|
||||
#include "WorldModelHandler.h"
|
||||
|
||||
WDT::WDT(std::string file) : IsGlobalModel(false), IsValid(false), Model(NULL)
|
||||
{
|
||||
Data = new ChunkedData(file, 2);
|
||||
ReadTileTable();
|
||||
ReadGlobalModel();
|
||||
}
|
||||
|
||||
void WDT::ReadGlobalModel()
|
||||
{
|
||||
Chunk* fileChunk = Data->GetChunkByName("MWMO");
|
||||
Chunk* defChunk = Data->GetChunkByName("MODF");
|
||||
if (!fileChunk || !defChunk)
|
||||
return;
|
||||
|
||||
IsGlobalModel = true;
|
||||
ModelDefinition = WorldModelDefinition::Read(defChunk->GetStream());
|
||||
ModelFile = Utils::ReadString(fileChunk->GetStream());
|
||||
Model = new WorldModelRoot(ModelFile);
|
||||
}
|
||||
|
||||
void WDT::ReadTileTable()
|
||||
{
|
||||
Chunk* chunk = Data->GetChunkByName("MAIN");
|
||||
if (!chunk)
|
||||
return;
|
||||
IsValid = true;
|
||||
FILE* stream = chunk->GetStream();
|
||||
for (int y = 0; y < 64; ++y)
|
||||
{
|
||||
for (int x = 0; x < 64; ++x)
|
||||
{
|
||||
const uint32 hasTileFlag = 0x1;
|
||||
uint32 flags;
|
||||
uint32 discard;
|
||||
int count = 0;
|
||||
count += fread(&flags, sizeof(uint32), 1, stream);
|
||||
count += fread(&discard, sizeof(uint32), 1, stream);
|
||||
|
||||
if (count != 2)
|
||||
printf("WDT::ReadTileTable: Failed to read some data expected 2, read %d\n", count);
|
||||
|
||||
if (flags & hasTileFlag)
|
||||
TileTable.push_back(TilePos(x, y));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WDT::HasTile( int x, int y )
|
||||
{
|
||||
for (std::vector<TilePos>::iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr)
|
||||
if (itr->X == x && itr->Y == y)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WDT_H
|
||||
#define WDT_H
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ChunkedData.h"
|
||||
#include "WorldModelHandler.h"
|
||||
#include "WorldModelRoot.h"
|
||||
#include "Utils.h"
|
||||
|
||||
class WDT
|
||||
{
|
||||
public:
|
||||
WDT(std::string file);
|
||||
|
||||
ChunkedData* Data;
|
||||
std::vector<TilePos> TileTable;
|
||||
bool IsGlobalModel;
|
||||
bool IsValid;
|
||||
std::string ModelFile;
|
||||
WorldModelDefinition ModelDefinition;
|
||||
WorldModelRoot* Model;
|
||||
bool HasTile(int x, int y);
|
||||
private:
|
||||
void ReadGlobalModel();
|
||||
void ReadTileTable();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "WorldModelGroup.h"
|
||||
#include "ChunkedData.h"
|
||||
#include "Chunk.h"
|
||||
#include "Utils.h"
|
||||
|
||||
WorldModelGroup::WorldModelGroup( std::string path, int groupIndex ) : GroupIndex(groupIndex), MOBA(NULL), IsBad(false), HasLiquidData(false)
|
||||
{
|
||||
Data = new ChunkedData(path);
|
||||
if (!Data->Stream)
|
||||
{
|
||||
IsBad = true;
|
||||
return;
|
||||
}
|
||||
Chunk* mainChunk = Data->GetChunkByName("MOGP");
|
||||
int32 firstSub = mainChunk->FindSubChunkOffset("MOPY");
|
||||
if (firstSub == -1)
|
||||
return;
|
||||
|
||||
Name = Utils::GetPlainName(path.c_str());
|
||||
|
||||
FILE* stream = mainChunk->GetStream();
|
||||
fseek(stream, firstSub, SEEK_SET);
|
||||
SubData = new ChunkedData(stream, mainChunk->Length - firstSub);
|
||||
|
||||
ReadHeader();
|
||||
ReadMaterials();
|
||||
ReadTriangles();
|
||||
ReadVertices();
|
||||
ReadNormals();
|
||||
ReadLiquid();
|
||||
ReadBatches();
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadNormals()
|
||||
{
|
||||
Chunk* chunk = SubData->GetChunkByName("MONR");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
uint32 normalCount = chunk->Length / 12;
|
||||
ASSERT(normalCount == Vertices.size() && "normalCount is different than the Vertices count");
|
||||
Normals.reserve(normalCount);
|
||||
FILE* stream = chunk->GetStream();
|
||||
for (uint32 i = 0; i < normalCount; i++)
|
||||
Normals.push_back(Vector3::Read(stream));
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadLiquid()
|
||||
{
|
||||
Chunk* chunk = SubData->GetChunkByName("MLIQ");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
HasLiquidData = true;
|
||||
FILE* stream = chunk->GetStream();
|
||||
LiquidDataHeader = LiquidHeader::Read(stream);
|
||||
LiquidDataGeometry = LiquidData::Read(stream, LiquidDataHeader);
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadVertices()
|
||||
{
|
||||
Chunk* chunk = SubData->GetChunkByName("MOVT");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
uint32 verticeCount = chunk->Length / 12;
|
||||
Vertices.reserve(verticeCount);
|
||||
FILE* stream = chunk->GetStream();
|
||||
for (uint32 i = 0; i < verticeCount; i++)
|
||||
Vertices.push_back(Vector3::Read(stream));
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadTriangles()
|
||||
{
|
||||
Chunk* chunk = SubData->GetChunkByName("MOVI");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
uint32 triangleCount = chunk->Length / 6;
|
||||
ASSERT(triangleCount == TriangleFlags.size() && "triangleCount != TriangleFlags.size()");
|
||||
FILE* stream = chunk->GetStream();
|
||||
Triangles.reserve(triangleCount);
|
||||
for (uint32 i = 0; i < triangleCount; i++)
|
||||
{
|
||||
uint16 v0;
|
||||
uint16 v1;
|
||||
uint16 v2;
|
||||
int count = 0;
|
||||
count += fread(&v0, sizeof(uint16), 1, stream);
|
||||
count += fread(&v1, sizeof(uint16), 1, stream);
|
||||
count += fread(&v2, sizeof(uint16), 1, stream);
|
||||
if (count != 3)
|
||||
printf("WorldModelGroup::ReadMaterials: Error reading data, expected 3, read %d\n", count);
|
||||
|
||||
Triangles.push_back(Triangle<uint16>(Constants::TRIANGLE_TYPE_WMO, v0, v1, v2));
|
||||
}
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadMaterials()
|
||||
{
|
||||
Chunk* chunk = SubData->GetChunkByName("MOPY");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
FILE* stream = chunk->GetStream();
|
||||
uint32 triangleCount = chunk->Length / 2;
|
||||
TriangleFlags.reserve(triangleCount);
|
||||
TriangleMaterials.reserve(triangleCount);
|
||||
for (uint32 i = 0; i < triangleCount; i++)
|
||||
{
|
||||
uint8 tmp;
|
||||
if (fread(&tmp, sizeof(uint8), 1, stream) != 1)
|
||||
printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n");
|
||||
TriangleFlags.push_back(tmp);
|
||||
// Read again for material.
|
||||
if (fread(&tmp, sizeof(uint8), 1, stream) != 1)
|
||||
printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n");
|
||||
TriangleMaterials.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadHeader()
|
||||
{
|
||||
Chunk* chunk = Data->GetChunkByName("MOGP");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
FILE* stream = chunk->GetStream();
|
||||
Header = WMOGroupHeader::Read(stream);
|
||||
}
|
||||
|
||||
void WorldModelGroup::ReadBatches()
|
||||
{
|
||||
Chunk* chunk = Data->GetChunkByName("MOBA");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
MOBALength = chunk->Length / 2;
|
||||
MOBA = new uint16[MOBALength];
|
||||
uint32 count = (uint32)fread(MOBA, sizeof(uint16), MOBALength, chunk->GetStream());
|
||||
if (count != MOBALength)
|
||||
printf("WorldModelGroup::ReadBatches: Error reading data, expected %u, read %u\n", MOBALength, count);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WMOGROUP_H
|
||||
#define WMOGROUP_H
|
||||
#include "ChunkedData.h"
|
||||
#include "Utils.h"
|
||||
|
||||
class WorldModelGroup
|
||||
{
|
||||
public:
|
||||
WorldModelGroup(std::string path, int groupIndex);
|
||||
ChunkedData* Data;
|
||||
ChunkedData* SubData;
|
||||
int GroupIndex;
|
||||
std::string Name;
|
||||
WMOGroupHeader Header;
|
||||
|
||||
std::vector<uint8> TriangleFlags;
|
||||
std::vector<uint8> TriangleMaterials;
|
||||
std::vector<Triangle<uint16> > Triangles;
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Vector3> Normals;
|
||||
// @ToDo: Research.
|
||||
uint16* MOBA;
|
||||
uint32 MOBALength;
|
||||
|
||||
bool HasLiquidData;
|
||||
bool IsBad;
|
||||
LiquidHeader LiquidDataHeader;
|
||||
LiquidData LiquidDataGeometry;
|
||||
private:
|
||||
void ReadNormals();
|
||||
void ReadLiquid();
|
||||
void ReadVertices();
|
||||
void ReadTriangles();
|
||||
void ReadMaterials();
|
||||
void ReadHeader();
|
||||
void ReadBatches();
|
||||
};
|
||||
#endif
|
||||
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "WorldModelHandler.h"
|
||||
#include "WorldModelRoot.h"
|
||||
#include "Chunk.h"
|
||||
#include "Cache.h"
|
||||
#include "Model.h"
|
||||
#include "Define.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Quat.h"
|
||||
#include <cstdio>
|
||||
|
||||
WorldModelDefinition WorldModelDefinition::Read( FILE* file )
|
||||
{
|
||||
WorldModelDefinition ret;
|
||||
int count = 0;
|
||||
count += fread(&ret.MwidIndex, sizeof(uint32), 1, file);
|
||||
count += fread(&ret.UniqueId, sizeof(uint32), 1, file);
|
||||
ret.Position = Vector3::Read(file);
|
||||
ret.Rotation = Vector3::Read(file);
|
||||
ret.UpperExtents = Vector3::Read(file);
|
||||
ret.LowerExtents = Vector3::Read(file);
|
||||
count += fread(&ret.Flags, sizeof(uint16), 1, file);
|
||||
count += fread(&ret.DoodadSet, sizeof(uint16), 1, file);
|
||||
uint32 discard;
|
||||
count += fread(&discard, sizeof(uint32), 1, file);
|
||||
|
||||
if (count != 5)
|
||||
printf("WorldModelDefinition::Read: Error reading data, expected 5, read %d\n", count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
WorldModelHandler::WorldModelHandler( ADT* adt ) : ObjectDataHandler(adt), _definitions(NULL), _paths(NULL)
|
||||
{
|
||||
ReadModelPaths();
|
||||
ReadDefinitions();
|
||||
}
|
||||
|
||||
void WorldModelHandler::ProcessInternal( MapChunk* mcnk )
|
||||
{
|
||||
if (!IsSane())
|
||||
return;
|
||||
|
||||
uint32 refCount = mcnk->Header.MapObjectRefs;
|
||||
FILE* stream = mcnk->Source->GetStream();
|
||||
fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET);
|
||||
// Start looping at the last Doodad Ref index
|
||||
for (uint32 i = mcnk->Header.DoodadRefs; i < refCount; i++)
|
||||
{
|
||||
int32 index;
|
||||
if (fread(&index, sizeof(int32), 1, stream) != 1)
|
||||
printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n");
|
||||
|
||||
if (index < 0 || uint32(index) >= _definitions->size())
|
||||
continue;
|
||||
|
||||
WorldModelDefinition wmo = (*_definitions)[index];
|
||||
|
||||
if (_drawn.find(wmo.UniqueId) != _drawn.end())
|
||||
continue;
|
||||
_drawn.insert(wmo.UniqueId);
|
||||
|
||||
if (wmo.MwidIndex >= _paths->size())
|
||||
continue;
|
||||
|
||||
std::string path = (*_paths)[wmo.MwidIndex];
|
||||
WorldModelRoot* model = Cache->WorldModelCache.Get(path);
|
||||
if (!model)
|
||||
{
|
||||
model = new WorldModelRoot(path);
|
||||
Cache->WorldModelCache.Insert(path, model);
|
||||
}
|
||||
|
||||
Vertices.reserve(1000);
|
||||
Triangles.reserve(1000);
|
||||
|
||||
InsertModelGeometry(Vertices, Triangles, wmo, model);
|
||||
}
|
||||
// Restore the stream position
|
||||
fseek(stream, mcnk->Source->Offset, SEEK_SET);
|
||||
}
|
||||
|
||||
void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate )
|
||||
{
|
||||
for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
|
||||
{
|
||||
uint32 vertOffset = verts.size();
|
||||
for (std::vector<Vector3>::iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2)
|
||||
{
|
||||
Vector3 v = Utils::TransformDoodadVertex(def, *itr2, translate);
|
||||
// If translate is false, then we were called directly from the TileBuilder to add data to it's _Geometry member, hence, we have to manually convert the vertices to Recast format.
|
||||
verts.push_back(translate ? v : Utils::ToRecast(v)); // Transform the vertex to world space
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < group->Triangles.size(); ++i)
|
||||
{
|
||||
// only include colliding tris
|
||||
if ((group->TriangleFlags[i] & 0x04) != 0 && group->TriangleMaterials[i] != 0xFF)
|
||||
continue;
|
||||
Triangle<uint16> tri = group->Triangles[i];
|
||||
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, tri.V0 + vertOffset, tri.V1 + vertOffset, tri.V2 + vertOffset));
|
||||
}
|
||||
}
|
||||
|
||||
if (def.DoodadSet < root->DoodadSets.size())
|
||||
{
|
||||
DoodadSet set = root->DoodadSets[def.DoodadSet];
|
||||
std::vector<DoodadInstance> instances;
|
||||
instances.reserve(set.CountInstances);
|
||||
for (uint32 i = set.FirstInstanceIndex; i < (set.CountInstances + set.FirstInstanceIndex); i++)
|
||||
{
|
||||
if (i >= root->DoodadInstances.size())
|
||||
break;
|
||||
instances.push_back(root->DoodadInstances[i]);
|
||||
}
|
||||
|
||||
for (std::vector<DoodadInstance>::iterator instance = instances.begin(); instance != instances.end(); ++instance)
|
||||
{
|
||||
Model* model = Cache->ModelCache.Get(instance->File);
|
||||
if (!model)
|
||||
{
|
||||
model = new Model(instance->File);
|
||||
Cache->ModelCache.Insert(instance->File, model);
|
||||
}
|
||||
|
||||
if (!model->IsCollidable)
|
||||
continue;
|
||||
int vertOffset = verts.size();
|
||||
for (std::vector<Vector3>::iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2)
|
||||
{
|
||||
Vector3 v = Utils::TransformDoodadVertex(def, Utils::TransformWmoDoodad(*instance, def, *itr2, false), translate);
|
||||
verts.push_back(translate ? v : Utils::ToRecast(v));
|
||||
}
|
||||
for (std::vector<Triangle<uint16> >::iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2)
|
||||
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, itr2->V0 + vertOffset, itr2->V1 + vertOffset, itr2->V2 + vertOffset));
|
||||
}
|
||||
|
||||
for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group)
|
||||
{
|
||||
if (!group->HasLiquidData)
|
||||
continue;
|
||||
|
||||
const LiquidHeader& liquidHeader = group->LiquidDataHeader;
|
||||
LiquidData& liquidDataGeometry = group->LiquidDataGeometry;
|
||||
|
||||
for (uint32 y = 0; y < liquidHeader.Height; y++)
|
||||
{
|
||||
for (uint32 x = 0; x < liquidHeader.Width; x++)
|
||||
{
|
||||
|
||||
if (!liquidDataGeometry.ShouldRender(x, y))
|
||||
continue;
|
||||
|
||||
uint32 vertOffset = verts.size();
|
||||
|
||||
Vector3 v1 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
|
||||
liquidDataGeometry.HeightMap[x][y], x, y, translate);
|
||||
Vector3 v2 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
|
||||
liquidDataGeometry.HeightMap[x + 1][y], x + 1, y, translate);
|
||||
Vector3 v3 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
|
||||
liquidDataGeometry.HeightMap[x][y + 1], x, y + 1, translate);
|
||||
Vector3 v4 = Utils::GetLiquidVert(def, liquidHeader.BaseLocation,
|
||||
liquidDataGeometry.HeightMap[x + 1][y + 1], x + 1, y + 1, translate);
|
||||
|
||||
verts.push_back(translate ? v1 : Utils::ToRecast(v1));
|
||||
verts.push_back(translate ? v2 : Utils::ToRecast(v2));
|
||||
verts.push_back(translate ? v3 : Utils::ToRecast(v3));
|
||||
verts.push_back(translate ? v4 : Utils::ToRecast(v4));
|
||||
|
||||
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset + 2, vertOffset + 1));
|
||||
tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldModelHandler::ReadDefinitions()
|
||||
{
|
||||
Chunk* chunk = Source->ObjectData->GetChunkByName("MODF");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
const int32 definitionSize = 64;
|
||||
uint32 definitionCount = chunk->Length / definitionSize;
|
||||
_definitions = new std::vector<WorldModelDefinition>;
|
||||
_definitions->reserve(definitionCount);
|
||||
FILE* stream = chunk->GetStream();
|
||||
for (uint32 i = 0; i < definitionCount; i++)
|
||||
_definitions->push_back(WorldModelDefinition::Read(stream));
|
||||
}
|
||||
|
||||
void WorldModelHandler::ReadModelPaths()
|
||||
{
|
||||
Chunk* mwid = Source->ObjectData->GetChunkByName("MWID");
|
||||
Chunk* mwmo = Source->ObjectData->GetChunkByName("MWMO");
|
||||
if (!mwid || !mwmo)
|
||||
return;
|
||||
|
||||
uint32 paths = mwid->Length / 4;
|
||||
_paths = new std::vector<std::string>;
|
||||
_paths->reserve(paths);
|
||||
for (uint32 i = 0; i < paths; i++)
|
||||
{
|
||||
FILE* stream = mwid->GetStream();
|
||||
fseek(stream, i * 4, SEEK_CUR);
|
||||
uint32 offset;
|
||||
if (fread(&offset, sizeof(uint32), 1, stream) != 1)
|
||||
printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n");
|
||||
FILE* dataStream = mwmo->GetStream();
|
||||
fseek(dataStream, offset + mwmo->Offset, SEEK_SET);
|
||||
_paths->push_back(Utils::ReadString(dataStream));
|
||||
}
|
||||
}
|
||||
|
||||
WorldModelHandler::~WorldModelHandler()
|
||||
{
|
||||
delete _definitions;
|
||||
delete _paths;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WMODEL_HNDL_H
|
||||
#define WMODEL_HNDL_H
|
||||
#include "Define.h"
|
||||
#include "Utils.h"
|
||||
#include "WorldModelRoot.h"
|
||||
#include "ObjectDataHandler.h"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class ADT;
|
||||
|
||||
struct WorldModelDefinition : public IDefinition
|
||||
{
|
||||
public:
|
||||
WorldModelDefinition() {}
|
||||
|
||||
uint32 MwidIndex;
|
||||
uint32 UniqueId;
|
||||
Vector3 UpperExtents;
|
||||
Vector3 LowerExtents;
|
||||
uint16 Flags;
|
||||
uint16 DoodadSet;
|
||||
|
||||
static WorldModelDefinition Read(FILE* file);
|
||||
};
|
||||
|
||||
class WorldModelHandler : public ObjectDataHandler
|
||||
{
|
||||
public:
|
||||
WorldModelHandler(ADT* adt);
|
||||
~WorldModelHandler();
|
||||
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Triangle<uint32> > Triangles;
|
||||
bool IsSane() { return _definitions && _paths; }
|
||||
static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate = true);
|
||||
protected:
|
||||
void ProcessInternal(MapChunk* data);
|
||||
private:
|
||||
void ReadDefinitions();
|
||||
void ReadModelPaths();
|
||||
std::set<uint32> _drawn;
|
||||
std::vector<WorldModelDefinition>* _definitions;
|
||||
std::vector<std::string>* _paths;
|
||||
};
|
||||
#endif
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "WorldModelRoot.h"
|
||||
#include "ChunkedData.h"
|
||||
#include "Utils.h"
|
||||
|
||||
WorldModelRoot::WorldModelRoot( std::string path )
|
||||
{
|
||||
Data = new ChunkedData(path);
|
||||
Path = path;
|
||||
ReadHeader();
|
||||
ReadGroups();
|
||||
ReadDoodadInstances();
|
||||
ReadDoodadSets();
|
||||
}
|
||||
|
||||
WorldModelRoot::~WorldModelRoot()
|
||||
{
|
||||
delete Data;
|
||||
}
|
||||
|
||||
void WorldModelRoot::ReadGroups()
|
||||
{
|
||||
std::string pathBase = Utils::GetPathBase(Path);
|
||||
Groups.reserve(Header.CountGroups);
|
||||
for (uint32 i = 0; i < Header.CountGroups; i++)
|
||||
{
|
||||
char name[200];
|
||||
sprintf(name, "%s_%03u.wmo", pathBase.c_str(), i);
|
||||
WorldModelGroup group(name, i);
|
||||
if (!group.IsBad)
|
||||
Groups.push_back(group);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldModelRoot::ReadDoodadSets()
|
||||
{
|
||||
Chunk* chunk = Data->GetChunkByName("MODS");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
FILE* stream = chunk->GetStream();
|
||||
ASSERT(chunk->Length / 32 == Header.CountSets && "chunk.Length / 32 == Header.CountSets");
|
||||
DoodadSets.reserve(Header.CountSets);
|
||||
for (uint32 i = 0; i < Header.CountSets; i++)
|
||||
DoodadSets.push_back(DoodadSet::Read(stream));
|
||||
}
|
||||
|
||||
void WorldModelRoot::ReadDoodadInstances()
|
||||
{
|
||||
Chunk* chunk = Data->GetChunkByName("MODD");
|
||||
Chunk* nameChunk = Data->GetChunkByName("MODN");
|
||||
if (!chunk || !nameChunk)
|
||||
return;
|
||||
|
||||
const uint32 instanceSize = 40;
|
||||
uint32 countInstances = chunk->Length / instanceSize;
|
||||
DoodadInstances.reserve(countInstances);
|
||||
for (uint32 i = 0; i < countInstances; i++)
|
||||
{
|
||||
FILE* stream = chunk->GetStream();
|
||||
fseek(stream, instanceSize * i, SEEK_CUR);
|
||||
DoodadInstance instance = DoodadInstance::Read(stream);
|
||||
FILE* nameStream = nameChunk->GetStream();
|
||||
if (instance.FileOffset >= nameChunk->Length)
|
||||
continue;
|
||||
fseek(nameStream, instance.FileOffset, SEEK_CUR);
|
||||
instance.File = Utils::ReadString(nameStream);
|
||||
DoodadInstances.push_back(instance);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldModelRoot::ReadHeader()
|
||||
{
|
||||
Chunk* chunk = Data->GetChunkByName("MOHD");
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
FILE* stream = chunk->GetStream();
|
||||
Header = WorldModelHeader::Read(stream);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WMOROOT_H
|
||||
#define WMOROOT_H
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ChunkedData.h"
|
||||
#include "Utils.h"
|
||||
#include "WorldModelGroup.h"
|
||||
|
||||
class WorldModelRoot
|
||||
{
|
||||
public:
|
||||
WorldModelRoot(std::string path);
|
||||
~WorldModelRoot();
|
||||
std::string Path;
|
||||
ChunkedData* Data;
|
||||
WorldModelHeader Header;
|
||||
std::vector<DoodadInstance> DoodadInstances;
|
||||
std::vector<DoodadSet> DoodadSets;
|
||||
std::vector<WorldModelGroup> Groups;
|
||||
private:
|
||||
void ReadGroups();
|
||||
void ReadDoodadSets();
|
||||
void ReadDoodadInstances();
|
||||
void ReadHeader();
|
||||
};
|
||||
#endif
|
||||
@@ -1,6 +0,0 @@
|
||||
Experimental mesh extractor.
|
||||
Original work in C# by stschake
|
||||
Thanks to:
|
||||
Subv
|
||||
~
|
||||
For helping in the porting to C++
|
||||
@@ -1,140 +0,0 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
file(GLOB_RECURSE mmap_gen_sources *.cpp *.h)
|
||||
|
||||
set(mmap_gen_Includes
|
||||
${CMAKE_BINARY_DIR}
|
||||
${ACE_INCLUDE_DIR}
|
||||
${MYSQL_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/zlib
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/bzip2
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Management
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Maps
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Models
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Configuration
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Cryptography
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Cryptography/Authentication
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Database
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/DataStores
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Debugging
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Dynamic/LinkedReference
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Dynamic
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Logging
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Packets
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Threading
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Utilities
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/game-framework/src/Addons
|
||||
${CMAKE_SOURCE_DIR}/src/game
|
||||
${CMAKE_SOURCE_DIR}/src/game/Accounts
|
||||
${CMAKE_SOURCE_DIR}/src/game/Achievements
|
||||
${CMAKE_SOURCE_DIR}/src/game/AI
|
||||
${CMAKE_SOURCE_DIR}/src/game/AI/CoreAI
|
||||
${CMAKE_SOURCE_DIR}/src/game/AI/ScriptedAI
|
||||
${CMAKE_SOURCE_DIR}/src/game/AI/SmartScripts
|
||||
${CMAKE_SOURCE_DIR}/src/game/AuctionHouse
|
||||
${CMAKE_SOURCE_DIR}/src/game/AuctionHouse/AuctionHouseBot
|
||||
${CMAKE_SOURCE_DIR}/src/game/Battlefield
|
||||
${CMAKE_SOURCE_DIR}/src/game/Battlefield/Zones
|
||||
${CMAKE_SOURCE_DIR}/src/game/Battlegrounds
|
||||
${CMAKE_SOURCE_DIR}/src/game/Battlegrounds/Zones
|
||||
${CMAKE_SOURCE_DIR}/src/game/Calendar
|
||||
${CMAKE_SOURCE_DIR}/src/game/Chat
|
||||
${CMAKE_SOURCE_DIR}/src/game/Chat/Channels
|
||||
${CMAKE_SOURCE_DIR}/src/game/Combat
|
||||
${CMAKE_SOURCE_DIR}/src/game/Conditions
|
||||
${CMAKE_SOURCE_DIR}/src/game/DataStores
|
||||
${CMAKE_SOURCE_DIR}/src/game/DungeonFinding
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Creature
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Corpse
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/DynamicObject
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/GameObject
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Item
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Item/Container
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Object
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Object/Updates
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Pet
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Player
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Totem
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Unit
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Vehicle
|
||||
${CMAKE_SOURCE_DIR}/src/game/Entities/Transport
|
||||
${CMAKE_SOURCE_DIR}/src/game/Events
|
||||
${CMAKE_SOURCE_DIR}/src/game/Globals
|
||||
${CMAKE_SOURCE_DIR}/src/game/Grids/Cells
|
||||
${CMAKE_SOURCE_DIR}/src/game/Grids/Notifiers
|
||||
${CMAKE_SOURCE_DIR}/src/game/Grids
|
||||
${CMAKE_SOURCE_DIR}/src/game/Groups
|
||||
${CMAKE_SOURCE_DIR}/src/game/Guilds
|
||||
${CMAKE_SOURCE_DIR}/src/game/Handlers
|
||||
${CMAKE_SOURCE_DIR}/src/game/Instances
|
||||
${CMAKE_SOURCE_DIR}/src/game/Loot
|
||||
${CMAKE_SOURCE_DIR}/src/game/Mails
|
||||
${CMAKE_SOURCE_DIR}/src/game/Maps
|
||||
${CMAKE_SOURCE_DIR}/src/game/Miscellaneous
|
||||
${CMAKE_SOURCE_DIR}/src/game/Movement
|
||||
${CMAKE_SOURCE_DIR}/src/game/Movement/MovementGenerators
|
||||
${CMAKE_SOURCE_DIR}/src/game/Movement/Waypoints
|
||||
${CMAKE_SOURCE_DIR}/src/game/OutdoorPvP
|
||||
${CMAKE_SOURCE_DIR}/src/game/Pools
|
||||
${CMAKE_SOURCE_DIR}/src/game/PrecompiledHeaders
|
||||
${CMAKE_SOURCE_DIR}/src/game/Quests
|
||||
${CMAKE_SOURCE_DIR}/src/game/Reputation
|
||||
${CMAKE_SOURCE_DIR}/src/game/Scripting
|
||||
${CMAKE_SOURCE_DIR}/src/game/Server/Protocol
|
||||
${CMAKE_SOURCE_DIR}/src/game/Server
|
||||
${CMAKE_SOURCE_DIR}/src/game/Skills
|
||||
${CMAKE_SOURCE_DIR}/src/game/Spells
|
||||
${CMAKE_SOURCE_DIR}/src/game/Spells/Auras
|
||||
${CMAKE_SOURCE_DIR}/src/game/Tools
|
||||
${CMAKE_SOURCE_DIR}/src/game/Warden
|
||||
${CMAKE_SOURCE_DIR}/src/game/Warden/Modules
|
||||
${CMAKE_SOURCE_DIR}/src/game/Weather
|
||||
${CMAKE_SOURCE_DIR}/src/game/World
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
set(mmap_gen_Includes
|
||||
${mmap_gen_Includes}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq/win
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${mmap_gen_Includes})
|
||||
|
||||
add_executable(mmaps_generator ${mmap_gen_sources})
|
||||
|
||||
target_link_libraries(mmaps_generator
|
||||
shared
|
||||
collision
|
||||
g3dlib
|
||||
Recast
|
||||
Detour
|
||||
${ACE_LIBRARY}
|
||||
${MYSQL_LIBRARY}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${BZIP2_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS mmaps_generator DESTINATION bin)
|
||||
elseif( WIN32 )
|
||||
install(TARGETS mmaps_generator DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
@@ -1,69 +0,0 @@
|
||||
Generator command line args
|
||||
|
||||
--threads [#] Max number of threads used by the generator
|
||||
Default: 3
|
||||
|
||||
--offMeshInput [file.*] Path to file containing off mesh connections data.
|
||||
Format must be: (see offmesh_example.txt)
|
||||
"map_id tile_x,tile_y (start_x start_y start_z) (end_x end_y end_z) size //optional comments"
|
||||
Single mesh connection per line.
|
||||
|
||||
--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.
|
||||
|
||||
false: use normal metrics (default)
|
||||
|
||||
--maxAngle [#] Max walkable inclination angle
|
||||
|
||||
float between 45 and 90 degrees (default 60)
|
||||
|
||||
--skipLiquid [true|false] extract liquid data for maps
|
||||
|
||||
false: include liquid data (default)
|
||||
|
||||
--skipContinents [true|false] continents are maps 0 (Eastern Kingdoms),
|
||||
1 (Kalimdor), 530 (Outlands), 571 (Northrend)
|
||||
|
||||
false: build continents (default)
|
||||
|
||||
--skipJunkMaps [true|false] junk maps include some unused
|
||||
maps, transport maps, and some other
|
||||
|
||||
true: skip junk maps (default)
|
||||
|
||||
--skipBattlegrounds [true|false] does not include PVP arenas
|
||||
|
||||
false: skip battlegrounds (default)
|
||||
|
||||
--debugOutput [true|false] create debugging files for use with RecastDemo
|
||||
if you are only creating mmaps for use with Moongose,
|
||||
you don't want debugging files
|
||||
|
||||
false: don't create debugging files (default)
|
||||
|
||||
--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
|
||||
|
||||
[#] Build only the map specified by #
|
||||
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
|
||||
|
||||
|
||||
examples:
|
||||
|
||||
movement_extractor
|
||||
builds maps using the default settings (see above for defaults)
|
||||
|
||||
movement_extractor --skipContinents true
|
||||
builds the default maps, except continents
|
||||
|
||||
movement_extractor 0
|
||||
builds all tiles of map 0
|
||||
|
||||
movement_extractor 0 --tile 34,46
|
||||
builds only tile 34,46 of map 0 (this is the southern face of blackrock mountain)
|
||||
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "IntermediateValues.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
IntermediateValues::~IntermediateValues()
|
||||
{
|
||||
rcFreeCompactHeightfield(compactHeightfield);
|
||||
rcFreeHeightField(heightfield);
|
||||
rcFreeContourSet(contours);
|
||||
rcFreePolyMesh(polyMesh);
|
||||
rcFreePolyMeshDetail(polyMeshDetail);
|
||||
}
|
||||
|
||||
void IntermediateValues::writeIV(uint32 mapID, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
char fileName[255];
|
||||
char tileString[25];
|
||||
sprintf(tileString, "[%02u,%02u]: ", tileX, tileY);
|
||||
|
||||
printf("%sWriting debug output... \r", tileString);
|
||||
|
||||
std::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(uint32 mapID, uint32 tileX, uint32 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);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _INTERMEDIATE_VALUES_H
|
||||
#define _INTERMEDIATE_VALUES_H
|
||||
|
||||
#include "PathCommon.h"
|
||||
#include "TerrainBuilder.h"
|
||||
#include "Recast.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
// this class gathers all debug info holding and output
|
||||
struct IntermediateValues
|
||||
{
|
||||
rcHeightfield* heightfield;
|
||||
rcCompactHeightfield* compactHeightfield;
|
||||
rcContourSet* contours;
|
||||
rcPolyMesh* polyMesh;
|
||||
rcPolyMeshDetail* polyMeshDetail;
|
||||
|
||||
IntermediateValues() : heightfield(NULL), compactHeightfield(NULL),
|
||||
contours(NULL), polyMesh(NULL), polyMeshDetail(NULL) {}
|
||||
~IntermediateValues();
|
||||
|
||||
void writeIV(uint32 mapID, uint32 tileX, uint32 tileY);
|
||||
|
||||
void debugWrite(FILE* file, const rcHeightfield* mesh);
|
||||
void debugWrite(FILE* file, const rcCompactHeightfield* chf);
|
||||
void debugWrite(FILE* file, const rcContourSet* cs);
|
||||
void debugWrite(FILE* file, const rcPolyMesh* mesh);
|
||||
void debugWrite(FILE* file, const rcPolyMeshDetail* mesh);
|
||||
|
||||
void generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,974 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "PathCommon.h"
|
||||
#include "MapBuilder.h"
|
||||
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
|
||||
#include "DetourNavMeshBuilder.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include "DetourCommon.h"
|
||||
|
||||
#include "DisableMgr.h"
|
||||
#include <ace/OS_NS_unistd.h>
|
||||
|
||||
uint32 GetLiquidFlags(uint32 /*liquidType*/) { return 0; }
|
||||
namespace DisableMgr
|
||||
{
|
||||
bool IsDisabledFor(DisableType /*type*/, uint32 /*entry*/, Unit const* /*unit*/, uint8 /*flags*/ /*= 0*/) { return false; }
|
||||
}
|
||||
|
||||
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
|
||||
#define MMAP_VERSION 3
|
||||
|
||||
struct MmapTileHeader
|
||||
{
|
||||
uint32 mmapMagic;
|
||||
uint32 dtVersion;
|
||||
uint32 mmapVersion;
|
||||
uint32 size;
|
||||
bool usesLiquids : 1;
|
||||
|
||||
MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
|
||||
mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
|
||||
};
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
|
||||
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
|
||||
bool debugOutput, bool bigBaseUnit, const char* offMeshFilePath) :
|
||||
m_terrainBuilder (NULL),
|
||||
m_debugOutput (debugOutput),
|
||||
m_offMeshFilePath (offMeshFilePath),
|
||||
m_skipContinents (skipContinents),
|
||||
m_skipJunkMaps (skipJunkMaps),
|
||||
m_skipBattlegrounds (skipBattlegrounds),
|
||||
m_maxWalkableAngle (maxWalkableAngle),
|
||||
m_bigBaseUnit (bigBaseUnit),
|
||||
m_rcContext (NULL)
|
||||
{
|
||||
m_terrainBuilder = new TerrainBuilder(skipLiquid);
|
||||
|
||||
m_rcContext = new rcContext(false);
|
||||
|
||||
discoverTiles();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
MapBuilder::~MapBuilder()
|
||||
{
|
||||
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
||||
{
|
||||
(*it).second->clear();
|
||||
delete (*it).second;
|
||||
}
|
||||
|
||||
delete m_terrainBuilder;
|
||||
delete m_rcContext;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::discoverTiles()
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
uint32 mapID, tileX, tileY, tileID, count = 0;
|
||||
char filter[12];
|
||||
|
||||
printf("Discovering maps... ");
|
||||
getDirContents(files, "maps");
|
||||
for (uint32 i = 0; i < files.size(); ++i)
|
||||
{
|
||||
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
||||
if (m_tiles.find(mapID) == m_tiles.end())
|
||||
{
|
||||
m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
files.clear();
|
||||
getDirContents(files, "vmaps", "*.vmtree");
|
||||
for (uint32 i = 0; i < files.size(); ++i)
|
||||
{
|
||||
mapID = uint32(atoi(files[i].substr(0,3).c_str()));
|
||||
m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, new std::set<uint32>));
|
||||
count++;
|
||||
}
|
||||
printf("found %u.\n", count);
|
||||
|
||||
count = 0;
|
||||
printf("Discovering tiles... ");
|
||||
for (TileList::iterator itr = m_tiles.begin(); itr != m_tiles.end(); ++itr)
|
||||
{
|
||||
std::set<uint32>* tiles = (*itr).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);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
std::set<uint32>* MapBuilder::getTileList(uint32 mapID)
|
||||
{
|
||||
TileList::iterator itr = m_tiles.find(mapID);
|
||||
if (itr != m_tiles.end())
|
||||
return (*itr).second;
|
||||
|
||||
std::set<uint32>* tiles = new std::set<uint32>();
|
||||
m_tiles.insert(std::pair<uint32, std::set<uint32>*>(mapID, tiles));
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildAllMaps(int threads)
|
||||
{
|
||||
std::vector<BuilderThread*> _threads;
|
||||
|
||||
BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL;
|
||||
|
||||
for (TileList::iterator it = m_tiles.begin(); it != m_tiles.end(); ++it)
|
||||
{
|
||||
uint32 mapID = it->first;
|
||||
if (!shouldSkipMap(mapID))
|
||||
{
|
||||
if (threads > 0)
|
||||
pool->Enqueue(new MapBuildRequest(mapID));
|
||||
else
|
||||
buildMap(mapID);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < threads; ++i)
|
||||
_threads.push_back(new BuilderThread(this, pool->Queue()));
|
||||
|
||||
// Free memory
|
||||
for (std::vector<BuilderThread*>::iterator _th = _threads.begin(); _th != _threads.end(); ++_th)
|
||||
{
|
||||
(*_th)->wait();
|
||||
delete *_th;
|
||||
}
|
||||
|
||||
delete pool;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY)
|
||||
{
|
||||
maxX = INT_MAX;
|
||||
maxY = INT_MAX;
|
||||
minX = INT_MIN;
|
||||
minY = INT_MIN;
|
||||
|
||||
float bmin[3] = { 0, 0, 0 };
|
||||
float bmax[3] = { 0, 0, 0 };
|
||||
float lmin[3] = { 0, 0, 0 };
|
||||
float lmax[3] = { 0, 0, 0 };
|
||||
MeshData meshData;
|
||||
|
||||
// make sure we process maps which don't have tiles
|
||||
// initialize the static tree, which loads WDT models
|
||||
if (!m_terrainBuilder->loadVMap(mapID, 64, 64, meshData))
|
||||
return;
|
||||
|
||||
// get the coord bounds of the model data
|
||||
if (meshData.solidVerts.size() + meshData.liquidVerts.size() == 0)
|
||||
return;
|
||||
|
||||
// get the coord bounds of the model data
|
||||
if (meshData.solidVerts.size() && meshData.liquidVerts.size())
|
||||
{
|
||||
rcCalcBounds(meshData.solidVerts.getCArray(), meshData.solidVerts.size() / 3, bmin, bmax);
|
||||
rcCalcBounds(meshData.liquidVerts.getCArray(), meshData.liquidVerts.size() / 3, lmin, lmax);
|
||||
rcVmin(bmin, lmin);
|
||||
rcVmax(bmax, lmax);
|
||||
}
|
||||
else if (meshData.solidVerts.size())
|
||||
rcCalcBounds(meshData.solidVerts.getCArray(), meshData.solidVerts.size() / 3, bmin, bmax);
|
||||
else
|
||||
rcCalcBounds(meshData.liquidVerts.getCArray(), meshData.liquidVerts.size() / 3, lmin, lmax);
|
||||
|
||||
// convert coord bounds to grid bounds
|
||||
maxX = 32 - bmin[0] / GRID_SIZE;
|
||||
maxY = 32 - bmin[2] / GRID_SIZE;
|
||||
minX = 32 - bmax[0] / GRID_SIZE;
|
||||
minY = 32 - bmax[2] / GRID_SIZE;
|
||||
}
|
||||
|
||||
void MapBuilder::buildMeshFromFile(char* name)
|
||||
{
|
||||
FILE* file = fopen(name, "rb");
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
printf("Building mesh from file\n");
|
||||
int tileX, tileY, mapId;
|
||||
if (fread(&mapId, sizeof(int), 1, file) != 1)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
if (fread(&tileX, sizeof(int), 1, file) != 1)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
if (fread(&tileY, sizeof(int), 1, file) != 1)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
dtNavMesh* navMesh = NULL;
|
||||
buildNavMesh(mapId, navMesh);
|
||||
if (!navMesh)
|
||||
{
|
||||
printf("Failed creating navmesh! \n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 verticesCount, indicesCount;
|
||||
if (fread(&verticesCount, sizeof(uint32), 1, file) != 1)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fread(&indicesCount, sizeof(uint32), 1, file) != 1)
|
||||
{
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
float* verts = new float[verticesCount];
|
||||
int* inds = new int[indicesCount];
|
||||
|
||||
if (fread(verts, sizeof(float), verticesCount, file) != verticesCount)
|
||||
{
|
||||
fclose(file);
|
||||
delete[] verts;
|
||||
delete[] inds;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fread(inds, sizeof(int), indicesCount, file) != indicesCount)
|
||||
{
|
||||
fclose(file);
|
||||
delete[] verts;
|
||||
delete[] inds;
|
||||
return;
|
||||
}
|
||||
|
||||
MeshData data;
|
||||
|
||||
for (uint32 i = 0; i < verticesCount; ++i)
|
||||
data.solidVerts.append(verts[i]);
|
||||
delete[] verts;
|
||||
|
||||
for (uint32 i = 0; i < indicesCount; ++i)
|
||||
data.solidTris.append(inds[i]);
|
||||
delete[] inds;
|
||||
|
||||
TerrainBuilder::cleanVertices(data.solidVerts, data.solidTris);
|
||||
// get bounds of current tile
|
||||
float bmin[3], bmax[3];
|
||||
getTileBounds(tileX, tileY, data.solidVerts.getCArray(), data.solidVerts.size() / 3, bmin, bmax);
|
||||
|
||||
// build navmesh tile
|
||||
buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
dtNavMesh* navMesh = NULL;
|
||||
buildNavMesh(mapID, navMesh);
|
||||
if (!navMesh)
|
||||
{
|
||||
printf("Failed creating navmesh! \n");
|
||||
return;
|
||||
}
|
||||
|
||||
buildTile(mapID, tileX, tileY, navMesh);
|
||||
dtFreeNavMesh(navMesh);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildMap(uint32 mapID)
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
printf("[Thread %u] Building map %03u:\n", uint32(ACE_Thread::self()), mapID);
|
||||
#endif
|
||||
|
||||
std::set<uint32>* tiles = getTileList(mapID);
|
||||
|
||||
// make sure we process maps which don't have tiles
|
||||
if (!tiles->size())
|
||||
{
|
||||
// convert coord bounds to grid bounds
|
||||
uint32 minX, minY, maxX, maxY;
|
||||
getGridBounds(mapID, minX, minY, maxX, maxY);
|
||||
|
||||
// add all tiles within bounds to tile list.
|
||||
for (uint32 i = minX; i <= maxX; ++i)
|
||||
for (uint32 j = minY; j <= maxY; ++j)
|
||||
tiles->insert(StaticMapTree::packTileID(i, j));
|
||||
}
|
||||
|
||||
if (!tiles->empty())
|
||||
{
|
||||
// build navMesh
|
||||
dtNavMesh* navMesh = NULL;
|
||||
buildNavMesh(mapID, navMesh);
|
||||
if (!navMesh)
|
||||
{
|
||||
printf("[Map %03i] Failed creating navmesh!\n", mapID);
|
||||
return;
|
||||
}
|
||||
|
||||
// now start building mmtiles for each tile
|
||||
printf("[Map %03i] We have %u tiles. \n", mapID, (unsigned int)tiles->size());
|
||||
for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
|
||||
{
|
||||
uint32 tileX, tileY;
|
||||
|
||||
// unpack tile coords
|
||||
StaticMapTree::unpackTileID((*it), tileX, tileY);
|
||||
|
||||
if (shouldSkipTile(mapID, tileX, tileY))
|
||||
continue;
|
||||
|
||||
buildTile(mapID, tileX, tileY, navMesh);
|
||||
}
|
||||
|
||||
dtFreeNavMesh(navMesh);
|
||||
}
|
||||
|
||||
printf("[Map %03i] Complete!\n", mapID);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh)
|
||||
{
|
||||
printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY);
|
||||
|
||||
MeshData meshData;
|
||||
|
||||
// get heightmap data
|
||||
m_terrainBuilder->loadMap(mapID, tileX, tileY, meshData);
|
||||
|
||||
// get model data
|
||||
m_terrainBuilder->loadVMap(mapID, tileY, tileX, meshData);
|
||||
|
||||
// if there is no data, give up now
|
||||
if (!meshData.solidVerts.size() && !meshData.liquidVerts.size())
|
||||
return;
|
||||
|
||||
// remove unused vertices
|
||||
TerrainBuilder::cleanVertices(meshData.solidVerts, meshData.solidTris);
|
||||
TerrainBuilder::cleanVertices(meshData.liquidVerts, meshData.liquidTris);
|
||||
|
||||
// gather all mesh data for final data check, and bounds calculation
|
||||
G3D::Array<float> allVerts;
|
||||
allVerts.append(meshData.liquidVerts);
|
||||
allVerts.append(meshData.solidVerts);
|
||||
|
||||
if (!allVerts.size())
|
||||
return;
|
||||
|
||||
// get bounds of current tile
|
||||
float bmin[3], bmax[3];
|
||||
getTileBounds(tileX, tileY, allVerts.getCArray(), allVerts.size() / 3, bmin, bmax);
|
||||
|
||||
m_terrainBuilder->loadOffMeshConnections(mapID, tileX, tileY, meshData, m_offMeshFilePath);
|
||||
|
||||
// build navmesh tile
|
||||
buildMoveMapTile(mapID, tileX, tileY, meshData, bmin, bmax, navMesh);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildNavMesh(uint32 mapID, dtNavMesh* &navMesh)
|
||||
{
|
||||
std::set<uint32>* tiles = getTileList(mapID);
|
||||
|
||||
// old code for non-statically assigned bitmask sizes:
|
||||
///*** calculate number of bits needed to store tiles & polys ***/
|
||||
//int tileBits = dtIlog2(dtNextPow2(tiles->size()));
|
||||
//if (tileBits < 1) tileBits = 1; // need at least one bit!
|
||||
//int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits;
|
||||
|
||||
int polyBits = STATIC_POLY_BITS;
|
||||
|
||||
int maxTiles = tiles->size();
|
||||
int maxPolysPerTile = 1 << polyBits;
|
||||
|
||||
/*** calculate bounds of map ***/
|
||||
|
||||
uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
|
||||
for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
|
||||
{
|
||||
StaticMapTree::unpackTileID(*it, tileX, tileY);
|
||||
|
||||
if (tileX > tileXMax)
|
||||
tileXMax = tileX;
|
||||
else if (tileX < tileXMin)
|
||||
tileXMin = tileX;
|
||||
|
||||
if (tileY > tileYMax)
|
||||
tileYMax = tileY;
|
||||
else if (tileY < tileYMin)
|
||||
tileYMin = tileY;
|
||||
}
|
||||
|
||||
// use Max because '32 - tileX' is negative for values over 32
|
||||
float bmin[3], bmax[3];
|
||||
getTileBounds(tileXMax, tileYMax, NULL, 0, bmin, bmax);
|
||||
|
||||
/*** now create the navmesh ***/
|
||||
|
||||
// navmesh creation params
|
||||
dtNavMeshParams navMeshParams;
|
||||
memset(&navMeshParams, 0, sizeof(dtNavMeshParams));
|
||||
navMeshParams.tileWidth = GRID_SIZE;
|
||||
navMeshParams.tileHeight = GRID_SIZE;
|
||||
rcVcopy(navMeshParams.orig, bmin);
|
||||
navMeshParams.maxTiles = maxTiles;
|
||||
navMeshParams.maxPolys = maxPolysPerTile;
|
||||
|
||||
navMesh = dtAllocNavMesh();
|
||||
printf("[Map %03i] Creating navMesh...\n", mapID);
|
||||
if (!navMesh->init(&navMeshParams))
|
||||
{
|
||||
printf("[Map %03i] Failed creating navmesh! \n", mapID);
|
||||
return;
|
||||
}
|
||||
|
||||
char fileName[25];
|
||||
sprintf(fileName, "mmaps/%03u.mmap", mapID);
|
||||
|
||||
FILE* file = fopen(fileName, "wb");
|
||||
if (!file)
|
||||
{
|
||||
dtFreeNavMesh(navMesh);
|
||||
char message[1024];
|
||||
sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName);
|
||||
perror(message);
|
||||
return;
|
||||
}
|
||||
|
||||
// now that we know navMesh params are valid, we can write them to file
|
||||
fwrite(&navMeshParams, sizeof(dtNavMeshParams), 1, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
|
||||
MeshData &meshData, float bmin[3], float bmax[3],
|
||||
dtNavMesh* navMesh)
|
||||
{
|
||||
// console output
|
||||
char tileString[20];
|
||||
sprintf(tileString, "[Map %03i] [%02i,%02i]: ", mapID, tileX, tileY);
|
||||
printf("%s Building movemap tiles...\n", tileString);
|
||||
|
||||
IntermediateValues iv;
|
||||
|
||||
float* tVerts = meshData.solidVerts.getCArray();
|
||||
int tVertCount = meshData.solidVerts.size() / 3;
|
||||
int* tTris = meshData.solidTris.getCArray();
|
||||
int tTriCount = meshData.solidTris.size() / 3;
|
||||
|
||||
float* lVerts = meshData.liquidVerts.getCArray();
|
||||
int lVertCount = meshData.liquidVerts.size() / 3;
|
||||
int* lTris = meshData.liquidTris.getCArray();
|
||||
int lTriCount = meshData.liquidTris.size() / 3;
|
||||
uint8* lTriFlags = meshData.liquidType.getCArray();
|
||||
|
||||
// these are WORLD UNIT based metrics
|
||||
// this are basic unit dimentions
|
||||
// value have to divide GRID_SIZE(533.3333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc )
|
||||
const static float BASE_UNIT_DIM = m_bigBaseUnit ? 0.5333333f : 0.2666666f;
|
||||
|
||||
// All are in UNIT metrics!
|
||||
const static int VERTEX_PER_MAP = int(GRID_SIZE/BASE_UNIT_DIM + 0.5f);
|
||||
const static int VERTEX_PER_TILE = m_bigBaseUnit ? 40 : 80; // must divide VERTEX_PER_MAP
|
||||
const static int TILES_PER_MAP = VERTEX_PER_MAP/VERTEX_PER_TILE;
|
||||
|
||||
rcConfig config;
|
||||
memset(&config, 0, sizeof(rcConfig));
|
||||
|
||||
rcVcopy(config.bmin, bmin);
|
||||
rcVcopy(config.bmax, bmax);
|
||||
|
||||
config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
|
||||
config.cs = BASE_UNIT_DIM;
|
||||
config.ch = BASE_UNIT_DIM;
|
||||
config.walkableSlopeAngle = m_maxWalkableAngle;
|
||||
config.tileSize = VERTEX_PER_TILE;
|
||||
config.walkableRadius = m_bigBaseUnit ? 1 : 2;
|
||||
config.borderSize = config.walkableRadius + 3;
|
||||
config.maxEdgeLen = VERTEX_PER_TILE + 1; // anything bigger than tileSize
|
||||
config.walkableHeight = m_bigBaseUnit ? 3 : 6;
|
||||
config.walkableClimb = m_bigBaseUnit ? 2 : 4; // keep less than walkableHeight
|
||||
config.minRegionArea = rcSqr(60);
|
||||
config.mergeRegionArea = rcSqr(50);
|
||||
config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
|
||||
config.detailSampleDist = config.cs * 64;
|
||||
config.detailSampleMaxError = config.ch * 2;
|
||||
|
||||
// this sets the dimensions of the heightfield - should maybe happen before border padding
|
||||
rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
|
||||
|
||||
// allocate subregions : tiles
|
||||
Tile* tiles = new Tile[TILES_PER_MAP * TILES_PER_MAP];
|
||||
|
||||
// Initialize per tile config.
|
||||
rcConfig tileCfg = config;
|
||||
tileCfg.width = config.tileSize + config.borderSize*2;
|
||||
tileCfg.height = config.tileSize + config.borderSize*2;
|
||||
|
||||
// merge per tile poly and detail meshes
|
||||
rcPolyMesh** pmmerge = new rcPolyMesh*[TILES_PER_MAP * TILES_PER_MAP];
|
||||
rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[TILES_PER_MAP * TILES_PER_MAP];
|
||||
int nmerge = 0;
|
||||
// build all tiles
|
||||
for (int y = 0; y < TILES_PER_MAP; ++y)
|
||||
{
|
||||
for (int x = 0; x < TILES_PER_MAP; ++x)
|
||||
{
|
||||
Tile& tile = tiles[x + y * TILES_PER_MAP];
|
||||
|
||||
// Calculate the per tile bounding box.
|
||||
tileCfg.bmin[0] = config.bmin[0] + float(x*config.tileSize - config.borderSize)*config.cs;
|
||||
tileCfg.bmin[2] = config.bmin[2] + float(y*config.tileSize - config.borderSize)*config.cs;
|
||||
tileCfg.bmax[0] = config.bmin[0] + float((x+1)*config.tileSize + config.borderSize)*config.cs;
|
||||
tileCfg.bmax[2] = config.bmin[2] + float((y+1)*config.tileSize + config.borderSize)*config.cs;
|
||||
|
||||
// build heightfield
|
||||
tile.solid = rcAllocHeightfield();
|
||||
if (!tile.solid || !rcCreateHeightfield(m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
|
||||
{
|
||||
printf("%s Failed building heightfield! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
// mark all walkable tiles, both liquids and solids
|
||||
unsigned char* triFlags = new unsigned char[tTriCount];
|
||||
memset(triFlags, NAV_GROUND, tTriCount*sizeof(unsigned char));
|
||||
rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
|
||||
rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb);
|
||||
delete[] triFlags;
|
||||
|
||||
rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *tile.solid);
|
||||
rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
|
||||
rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid);
|
||||
|
||||
rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
|
||||
|
||||
// compact heightfield spans
|
||||
tile.chf = rcAllocCompactHeightfield();
|
||||
if (!tile.chf || !rcBuildCompactHeightfield(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf))
|
||||
{
|
||||
printf("%s Failed compacting heightfield! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
// build polymesh intermediates
|
||||
if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, *tile.chf))
|
||||
{
|
||||
printf("%s Failed eroding area! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rcBuildDistanceField(m_rcContext, *tile.chf))
|
||||
{
|
||||
printf("%s Failed building distance field! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rcBuildRegions(m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
|
||||
{
|
||||
printf("%s Failed building regions! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
tile.cset = rcAllocContourSet();
|
||||
if (!tile.cset || !rcBuildContours(m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset))
|
||||
{
|
||||
printf("%s Failed building contours! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
// build polymesh
|
||||
tile.pmesh = rcAllocPolyMesh();
|
||||
if (!tile.pmesh || !rcBuildPolyMesh(m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh))
|
||||
{
|
||||
printf("%s Failed building polymesh! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
tile.dmesh = rcAllocPolyMeshDetail();
|
||||
if (!tile.dmesh || !rcBuildPolyMeshDetail(m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.dmesh))
|
||||
{
|
||||
printf("%s Failed building polymesh detail! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
// free those up
|
||||
// we may want to keep them in the future for debug
|
||||
// but right now, we don't have the code to merge them
|
||||
rcFreeHeightField(tile.solid);
|
||||
tile.solid = NULL;
|
||||
rcFreeCompactHeightfield(tile.chf);
|
||||
tile.chf = NULL;
|
||||
rcFreeContourSet(tile.cset);
|
||||
tile.cset = NULL;
|
||||
|
||||
pmmerge[nmerge] = tile.pmesh;
|
||||
dmmerge[nmerge] = tile.dmesh;
|
||||
nmerge++;
|
||||
}
|
||||
}
|
||||
|
||||
iv.polyMesh = rcAllocPolyMesh();
|
||||
if (!iv.polyMesh)
|
||||
{
|
||||
printf("%s alloc iv.polyMesh FIALED!\n", tileString);
|
||||
delete[] pmmerge;
|
||||
delete[] dmmerge;
|
||||
delete[] tiles;
|
||||
return;
|
||||
}
|
||||
rcMergePolyMeshes(m_rcContext, pmmerge, nmerge, *iv.polyMesh);
|
||||
|
||||
iv.polyMeshDetail = rcAllocPolyMeshDetail();
|
||||
if (!iv.polyMeshDetail)
|
||||
{
|
||||
printf("%s alloc m_dmesh FIALED!\n", tileString);
|
||||
delete[] pmmerge;
|
||||
delete[] dmmerge;
|
||||
delete[] tiles;
|
||||
return;
|
||||
}
|
||||
rcMergePolyMeshDetails(m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail);
|
||||
|
||||
// free things up
|
||||
delete[] pmmerge;
|
||||
delete[] dmmerge;
|
||||
delete[] tiles;
|
||||
|
||||
// set polygons as walkable
|
||||
// TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
|
||||
for (int i = 0; i < iv.polyMesh->npolys; ++i)
|
||||
if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA)
|
||||
iv.polyMesh->flags[i] = iv.polyMesh->areas[i];
|
||||
|
||||
// setup mesh parameters
|
||||
dtNavMeshCreateParams params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.verts = iv.polyMesh->verts;
|
||||
params.vertCount = iv.polyMesh->nverts;
|
||||
params.polys = iv.polyMesh->polys;
|
||||
params.polyAreas = iv.polyMesh->areas;
|
||||
params.polyFlags = iv.polyMesh->flags;
|
||||
params.polyCount = iv.polyMesh->npolys;
|
||||
params.nvp = iv.polyMesh->nvp;
|
||||
params.detailMeshes = iv.polyMeshDetail->meshes;
|
||||
params.detailVerts = iv.polyMeshDetail->verts;
|
||||
params.detailVertsCount = iv.polyMeshDetail->nverts;
|
||||
params.detailTris = iv.polyMeshDetail->tris;
|
||||
params.detailTriCount = iv.polyMeshDetail->ntris;
|
||||
|
||||
params.offMeshConVerts = meshData.offMeshConnections.getCArray();
|
||||
params.offMeshConCount = meshData.offMeshConnections.size()/6;
|
||||
params.offMeshConRad = meshData.offMeshConnectionRads.getCArray();
|
||||
params.offMeshConDir = meshData.offMeshConnectionDirs.getCArray();
|
||||
params.offMeshConAreas = meshData.offMeshConnectionsAreas.getCArray();
|
||||
params.offMeshConFlags = meshData.offMeshConnectionsFlags.getCArray();
|
||||
|
||||
params.walkableHeight = BASE_UNIT_DIM*config.walkableHeight; // agent height
|
||||
params.walkableRadius = BASE_UNIT_DIM*config.walkableRadius; // agent radius
|
||||
params.walkableClimb = BASE_UNIT_DIM*config.walkableClimb; // keep less that walkableHeight (aka agent height)!
|
||||
params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) / GRID_SIZE;
|
||||
params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) / GRID_SIZE;
|
||||
rcVcopy(params.bmin, bmin);
|
||||
rcVcopy(params.bmax, bmax);
|
||||
params.cs = config.cs;
|
||||
params.ch = config.ch;
|
||||
params.tileLayer = 0;
|
||||
params.buildBvTree = true;
|
||||
|
||||
// will hold final navmesh
|
||||
unsigned char* navData = NULL;
|
||||
int navDataSize = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// these values are checked within dtCreateNavMeshData - handle them here
|
||||
// so we have a clear error message
|
||||
if (params.nvp > DT_VERTS_PER_POLYGON)
|
||||
{
|
||||
printf("%s Invalid verts-per-polygon value! \n", tileString);
|
||||
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("%s No polygons to build on tile! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
if (!params.detailMeshes || !params.detailVerts || !params.detailTris)
|
||||
{
|
||||
printf("%s No detail mesh to build tile! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("%s Building navmesh tile...\n", tileString);
|
||||
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
|
||||
{
|
||||
printf("%s Failed building navmesh tile! \n", tileString);
|
||||
continue;
|
||||
}
|
||||
|
||||
dtTileRef tileRef = 0;
|
||||
printf("%s Adding tile to navmesh...\n", tileString);
|
||||
// DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
|
||||
// is removed via removeTile()
|
||||
dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
|
||||
if (!tileRef || dtResult != DT_SUCCESS)
|
||||
{
|
||||
printf("%s Failed adding tile to navmesh! \n", tileString);
|
||||
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, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName);
|
||||
perror(message);
|
||||
navMesh->removeTile(tileRef, NULL, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("%s Writing to file...\n", tileString);
|
||||
|
||||
// write header
|
||||
MmapTileHeader header;
|
||||
header.usesLiquids = m_terrainBuilder->usesLiquids();
|
||||
header.size = uint32(navDataSize);
|
||||
fwrite(&header, sizeof(MmapTileHeader), 1, file);
|
||||
|
||||
// write data
|
||||
fwrite(navData, sizeof(unsigned char), navDataSize, file);
|
||||
fclose(file);
|
||||
|
||||
// now that tile is written to disk, we can unload it
|
||||
navMesh->removeTile(tileRef, NULL, NULL);
|
||||
}
|
||||
while (0);
|
||||
|
||||
if (m_debugOutput)
|
||||
{
|
||||
// restore padding so that the debug visualization is correct
|
||||
for (int i = 0; i < iv.polyMesh->nverts; ++i)
|
||||
{
|
||||
unsigned short* v = &iv.polyMesh->verts[i*3];
|
||||
v[0] += (unsigned short)config.borderSize;
|
||||
v[2] += (unsigned short)config.borderSize;
|
||||
}
|
||||
|
||||
iv.generateObjFile(mapID, tileX, tileY, meshData);
|
||||
iv.writeIV(mapID, tileX, tileY);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void MapBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
|
||||
{
|
||||
// this is for elevation
|
||||
if (verts && vertCount)
|
||||
rcCalcBounds(verts, vertCount, bmin, bmax);
|
||||
else
|
||||
{
|
||||
bmin[1] = FLT_MIN;
|
||||
bmax[1] = FLT_MAX;
|
||||
}
|
||||
|
||||
// this is for width and depth
|
||||
bmax[0] = (32 - int(tileX)) * GRID_SIZE;
|
||||
bmax[2] = (32 - int(tileY)) * GRID_SIZE;
|
||||
bmin[0] = bmax[0] - GRID_SIZE;
|
||||
bmin[2] = bmax[2] - GRID_SIZE;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool MapBuilder::shouldSkipMap(uint32 mapID)
|
||||
{
|
||||
if (m_skipContinents)
|
||||
switch (mapID)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 530:
|
||||
case 571:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_skipJunkMaps)
|
||||
switch (mapID)
|
||||
{
|
||||
case 13: // test.wdt
|
||||
case 25: // ScottTest.wdt
|
||||
case 29: // Test.wdt
|
||||
case 42: // Colin.wdt
|
||||
case 169: // EmeraldDream.wdt (unused, and very large)
|
||||
case 451: // development.wdt
|
||||
case 573: // ExteriorTest.wdt
|
||||
case 597: // CraigTest.wdt
|
||||
case 605: // development_nonweighted.wdt
|
||||
case 606: // QA_DVD.wdt
|
||||
return true;
|
||||
default:
|
||||
if (isTransportMap(mapID))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_skipBattlegrounds)
|
||||
switch (mapID)
|
||||
{
|
||||
case 30: // AV
|
||||
case 37: // ?
|
||||
case 489: // WSG
|
||||
case 529: // AB
|
||||
case 566: // EotS
|
||||
case 607: // SotA
|
||||
case 628: // IoC
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool MapBuilder::isTransportMap(uint32 mapID)
|
||||
{
|
||||
switch (mapID)
|
||||
{
|
||||
// transport maps
|
||||
case 582:
|
||||
case 584:
|
||||
case 586:
|
||||
case 587:
|
||||
case 588:
|
||||
case 589:
|
||||
case 590:
|
||||
case 591:
|
||||
case 592:
|
||||
case 593:
|
||||
case 594:
|
||||
case 596:
|
||||
case 610:
|
||||
case 612:
|
||||
case 613:
|
||||
case 614:
|
||||
case 620:
|
||||
case 621:
|
||||
case 622:
|
||||
case 623:
|
||||
case 641:
|
||||
case 642:
|
||||
case 647:
|
||||
case 672:
|
||||
case 673:
|
||||
case 712:
|
||||
case 713:
|
||||
case 718:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool MapBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
char fileName[255];
|
||||
sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX);
|
||||
FILE* file = fopen(fileName, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
MmapTileHeader header;
|
||||
int count = fread(&header, sizeof(MmapTileHeader), 1, file);
|
||||
fclose(file);
|
||||
if (count != 1)
|
||||
return false;
|
||||
|
||||
if (header.mmapMagic != MMAP_MAGIC || header.dtVersion != uint32(DT_NAVMESH_VERSION))
|
||||
return false;
|
||||
|
||||
if (header.mmapVersion != MMAP_VERSION)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _MAP_BUILDER_H
|
||||
#define _MAP_BUILDER_H
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include "TerrainBuilder.h"
|
||||
#include "IntermediateValues.h"
|
||||
|
||||
#include "Recast.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
#include <ace/Task.h>
|
||||
#include <ace/Activation_Queue.h>
|
||||
#include <ace/Method_Request.h>
|
||||
|
||||
using namespace VMAP;
|
||||
|
||||
// G3D namespace typedefs conflicts with ACE typedefs
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
typedef std::map<uint32, std::set<uint32>*> TileList;
|
||||
struct Tile
|
||||
{
|
||||
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}
|
||||
~Tile()
|
||||
{
|
||||
rcFreeCompactHeightfield(chf);
|
||||
rcFreeContourSet(cset);
|
||||
rcFreeHeightField(solid);
|
||||
rcFreePolyMesh(pmesh);
|
||||
rcFreePolyMeshDetail(dmesh);
|
||||
}
|
||||
rcCompactHeightfield* chf;
|
||||
rcHeightfield* solid;
|
||||
rcContourSet* cset;
|
||||
rcPolyMesh* pmesh;
|
||||
rcPolyMeshDetail* dmesh;
|
||||
};
|
||||
|
||||
class MapBuilder
|
||||
{
|
||||
public:
|
||||
MapBuilder(float maxWalkableAngle = 55.f,
|
||||
bool skipLiquid = false,
|
||||
bool skipContinents = false,
|
||||
bool skipJunkMaps = true,
|
||||
bool skipBattlegrounds = false,
|
||||
bool debugOutput = false,
|
||||
bool bigBaseUnit = false,
|
||||
const char* offMeshFilePath = NULL);
|
||||
|
||||
~MapBuilder();
|
||||
|
||||
// builds all mmap tiles for the specified map id (ignores skip settings)
|
||||
void buildMap(uint32 mapID);
|
||||
void buildMeshFromFile(char* name);
|
||||
|
||||
// builds an mmap tile for the specified map and its mesh
|
||||
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY);
|
||||
|
||||
// builds list of maps, then builds all of mmap tiles (based on the skip settings)
|
||||
void buildAllMaps(int threads);
|
||||
|
||||
private:
|
||||
// detect maps and tiles
|
||||
void discoverTiles();
|
||||
std::set<uint32>* getTileList(uint32 mapID);
|
||||
|
||||
void buildNavMesh(uint32 mapID, dtNavMesh* &navMesh);
|
||||
|
||||
void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh);
|
||||
|
||||
// move map building
|
||||
void buildMoveMapTile(uint32 mapID,
|
||||
uint32 tileX,
|
||||
uint32 tileY,
|
||||
MeshData &meshData,
|
||||
float bmin[3],
|
||||
float bmax[3],
|
||||
dtNavMesh* navMesh);
|
||||
|
||||
void getTileBounds(uint32 tileX, uint32 tileY,
|
||||
float* verts, int vertCount,
|
||||
float* bmin, float* bmax);
|
||||
void getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY);
|
||||
|
||||
bool shouldSkipMap(uint32 mapID);
|
||||
bool isTransportMap(uint32 mapID);
|
||||
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY);
|
||||
|
||||
TerrainBuilder* m_terrainBuilder;
|
||||
TileList m_tiles;
|
||||
|
||||
bool m_debugOutput;
|
||||
|
||||
const char* m_offMeshFilePath;
|
||||
bool m_skipContinents;
|
||||
bool m_skipJunkMaps;
|
||||
bool m_skipBattlegrounds;
|
||||
|
||||
float m_maxWalkableAngle;
|
||||
bool m_bigBaseUnit;
|
||||
|
||||
// build performance - not really used for now
|
||||
rcContext* m_rcContext;
|
||||
};
|
||||
|
||||
class MapBuildRequest : public ACE_Method_Request
|
||||
{
|
||||
public:
|
||||
MapBuildRequest(uint32 mapId) : _mapId(mapId) {}
|
||||
|
||||
virtual int call()
|
||||
{
|
||||
/// @ Actually a creative way of unabstracting the class and returning a member variable
|
||||
return (int)_mapId;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _mapId;
|
||||
};
|
||||
|
||||
class BuilderThread : public ACE_Task_Base
|
||||
{
|
||||
private:
|
||||
MapBuilder* _builder;
|
||||
ACE_Activation_Queue* _queue;
|
||||
|
||||
public:
|
||||
BuilderThread(MapBuilder* builder, ACE_Activation_Queue* queue) : _builder(builder), _queue(queue) { activate(); }
|
||||
|
||||
int svc()
|
||||
{
|
||||
/// @ Set a timeout for dequeue attempts (only used when the queue is empty) as it will never get populated after thread starts
|
||||
ACE_Time_Value timeout(5);
|
||||
ACE_Method_Request* request = NULL;
|
||||
while ((request = _queue->dequeue(&timeout)) != NULL)
|
||||
{
|
||||
_builder->buildMap(request->call());
|
||||
delete request;
|
||||
request = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class BuilderThreadPool
|
||||
{
|
||||
public:
|
||||
BuilderThreadPool() : _queue(new ACE_Activation_Queue()) {}
|
||||
~BuilderThreadPool() { _queue->queue()->close(); delete _queue; }
|
||||
|
||||
void Enqueue(MapBuildRequest* request)
|
||||
{
|
||||
_queue->enqueue(request);
|
||||
}
|
||||
|
||||
ACE_Activation_Queue* Queue() { return _queue; }
|
||||
|
||||
private:
|
||||
ACE_Activation_Queue* _queue;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _MMAP_COMMON_H
|
||||
#define _MMAP_COMMON_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ace/OS_NS_sys_time.h>
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <stddef.h>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "Database/DatabaseEnv.h"
|
||||
|
||||
enum NavTerrain
|
||||
{
|
||||
NAV_EMPTY = 0x00,
|
||||
NAV_GROUND = 0x01,
|
||||
NAV_MAGMA = 0x02,
|
||||
NAV_SLIME = 0x04,
|
||||
NAV_WATER = 0x08,
|
||||
NAV_UNUSED1 = 0x10,
|
||||
NAV_UNUSED2 = 0x20,
|
||||
NAV_UNUSED3 = 0x40,
|
||||
NAV_UNUSED4 = 0x80
|
||||
// we only have 8 bits
|
||||
};
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
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');
|
||||
}
|
||||
|
||||
enum ListFilesResult
|
||||
{
|
||||
LISTFILE_DIRECTORY_NOT_FOUND = 0,
|
||||
LISTFILE_OK = 1
|
||||
};
|
||||
|
||||
inline ListFilesResult getDirContents(std::vector<std::string> &fileList, std::string dirpath = ".", std::string filter = "*")
|
||||
{
|
||||
#ifdef WIN32
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA findFileInfo;
|
||||
std::string directory;
|
||||
|
||||
directory = dirpath + "/" + filter;
|
||||
|
||||
hFind = FindFirstFile(directory.c_str(), &findFileInfo);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return LISTFILE_DIRECTORY_NOT_FOUND;
|
||||
do
|
||||
{
|
||||
if ((findFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
||||
fileList.push_back(std::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(std::string(dp->d_name));
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (dirp)
|
||||
closedir(dirp);
|
||||
else
|
||||
return LISTFILE_DIRECTORY_NOT_FOUND;
|
||||
#endif
|
||||
|
||||
return LISTFILE_OK;
|
||||
}
|
||||
|
||||
inline uint32 getMSTime()
|
||||
{
|
||||
static const ACE_Time_Value ApplicationStartTime = ACE_OS::gettimeofday();
|
||||
return (ACE_OS::gettimeofday() - ApplicationStartTime).msec();
|
||||
}
|
||||
|
||||
inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
|
||||
{
|
||||
// getMSTime() have limited data range and this is case when it overflow in this tick
|
||||
if (oldMSTime > newMSTime)
|
||||
return (0xFFFFFFFF - oldMSTime) + newMSTime;
|
||||
else
|
||||
return newMSTime - oldMSTime;
|
||||
}
|
||||
|
||||
inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
|
||||
{
|
||||
return getMSTimeDiff(oldMSTime, getMSTime());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "PathCommon.h"
|
||||
#include "MapBuilder.h"
|
||||
|
||||
using namespace MMAP;
|
||||
|
||||
bool checkDirectories(bool debugOutput)
|
||||
{
|
||||
std::vector<std::string> dirFiles;
|
||||
|
||||
if (getDirContents(dirFiles, "maps") == LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
|
||||
{
|
||||
printf("'maps' directory is empty or does not exist\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dirFiles.clear();
|
||||
if (getDirContents(dirFiles, "vmaps", "*.vmtree") == LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
|
||||
{
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
char* &offMeshInputPath,
|
||||
char* &file,
|
||||
int& threads)
|
||||
{
|
||||
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;
|
||||
threads = atoi(param);
|
||||
printf("Using %i threads to extract mmaps\n", threads);
|
||||
}
|
||||
else if (strcmp(argv[i], "--file") == 0)
|
||||
{
|
||||
param = argv[++i];
|
||||
if (!param)
|
||||
return false;
|
||||
file = param;
|
||||
}
|
||||
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
|
||||
{
|
||||
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);
|
||||
getchar(); // Wait for user input
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int threads = 3, mapnum = -1;
|
||||
float maxAngle = 55.0f;
|
||||
int tileX = -1, tileY = -1;
|
||||
bool skipLiquid = false,
|
||||
skipContinents = false,
|
||||
skipJunkMaps = true,
|
||||
skipBattlegrounds = false,
|
||||
debugOutput = false,
|
||||
silent = false,
|
||||
bigBaseUnit = false;
|
||||
char* offMeshInputPath = NULL;
|
||||
char* file = NULL;
|
||||
|
||||
bool validParam = handleArgs(argc, argv, mapnum,
|
||||
tileX, tileY, maxAngle,
|
||||
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
|
||||
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
|
||||
|
||||
if (!validParam)
|
||||
return silent ? -1 : finish("You have specified invalid parameters", -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(maxAngle, skipLiquid, skipContinents, skipJunkMaps,
|
||||
skipBattlegrounds, debugOutput, bigBaseUnit, offMeshInputPath);
|
||||
|
||||
uint32 start = getMSTime();
|
||||
if (file)
|
||||
builder.buildMeshFromFile(file);
|
||||
else if (tileX > -1 && tileY > -1 && mapnum >= 0)
|
||||
builder.buildSingleTile(mapnum, tileX, tileY);
|
||||
else if (mapnum >= 0)
|
||||
builder.buildMap(uint32(mapnum));
|
||||
else
|
||||
builder.buildAllMaps(threads);
|
||||
|
||||
if (!silent)
|
||||
printf("Finished. MMAPS were built in %u ms!\n", GetMSTimeDiffToNow(start));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,923 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "TerrainBuilder.h"
|
||||
|
||||
#include "PathCommon.h"
|
||||
#include "MapBuilder.h"
|
||||
|
||||
#include "VMapManager2.h"
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
#include <vector>
|
||||
|
||||
// ******************************************
|
||||
// Map file format defines
|
||||
// ******************************************
|
||||
struct map_fileheader
|
||||
{
|
||||
uint32 mapMagic;
|
||||
uint32 versionMagic;
|
||||
uint32 buildMagic;
|
||||
uint32 areaMapOffset;
|
||||
uint32 areaMapSize;
|
||||
uint32 heightMapOffset;
|
||||
uint32 heightMapSize;
|
||||
uint32 liquidMapOffset;
|
||||
uint32 liquidMapSize;
|
||||
uint32 holesOffset;
|
||||
uint32 holesSize;
|
||||
};
|
||||
|
||||
#define MAP_HEIGHT_NO_HEIGHT 0x0001
|
||||
#define MAP_HEIGHT_AS_INT16 0x0002
|
||||
#define MAP_HEIGHT_AS_INT8 0x0004
|
||||
|
||||
struct map_heightHeader
|
||||
{
|
||||
uint32 fourcc;
|
||||
uint32 flags;
|
||||
float gridHeight;
|
||||
float gridMaxHeight;
|
||||
};
|
||||
|
||||
#define MAP_LIQUID_NO_TYPE 0x0001
|
||||
#define MAP_LIQUID_NO_HEIGHT 0x0002
|
||||
|
||||
struct map_liquidHeader
|
||||
{
|
||||
uint32 fourcc;
|
||||
uint16 flags;
|
||||
uint16 liquidType;
|
||||
uint8 offsetX;
|
||||
uint8 offsetY;
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
float liquidLevel;
|
||||
};
|
||||
|
||||
#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_LIQUID_TYPE_DARK_WATER 0x10
|
||||
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
|
||||
char const* MAP_VERSION_MAGIC = "v1.3";
|
||||
|
||||
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)
|
||||
{
|
||||
if (loadMap(mapID, tileX, tileY, meshData, ENTIRE))
|
||||
{
|
||||
loadMap(mapID, tileX+1, tileY, meshData, LEFT);
|
||||
loadMap(mapID, tileX-1, tileY, meshData, RIGHT);
|
||||
loadMap(mapID, tileX, tileY+1, meshData, TOP);
|
||||
loadMap(mapID, tileX, tileY-1, meshData, BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion)
|
||||
{
|
||||
char mapFileName[255];
|
||||
sprintf(mapFileName, "maps/%03u%02u%02u.map", mapID, tileY, tileX);
|
||||
|
||||
FILE* mapFile = fopen(mapFileName, "rb");
|
||||
if (!mapFile)
|
||||
return false;
|
||||
|
||||
map_fileheader fheader;
|
||||
if (fread(&fheader, sizeof(map_fileheader), 1, mapFile) != 1 ||
|
||||
fheader.versionMagic != *((uint32 const*)(MAP_VERSION_MAGIC)))
|
||||
{
|
||||
fclose(mapFile);
|
||||
printf("%s is the wrong version, please extract new .map files\n", mapFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
map_heightHeader hheader;
|
||||
fseek(mapFile, fheader.heightMapOffset, SEEK_SET);
|
||||
|
||||
bool haveTerrain = false;
|
||||
bool haveLiquid = false;
|
||||
if (fread(&hheader, sizeof(map_heightHeader), 1, mapFile) == 1)
|
||||
{
|
||||
haveTerrain = !(hheader.flags & MAP_HEIGHT_NO_HEIGHT);
|
||||
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)
|
||||
{
|
||||
float heightMultiplier;
|
||||
float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ];
|
||||
int expected = V9_SIZE_SQ + V8_SIZE_SQ;
|
||||
|
||||
if (hheader.flags & MAP_HEIGHT_AS_INT8)
|
||||
{
|
||||
uint8 v9[V9_SIZE_SQ];
|
||||
uint8 v8[V8_SIZE_SQ];
|
||||
int count = 0;
|
||||
count += fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile);
|
||||
count += fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile);
|
||||
if (count != expected)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
|
||||
|
||||
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;
|
||||
|
||||
for (int i = 0; i < V9_SIZE_SQ; ++i)
|
||||
V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
|
||||
|
||||
for (int 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];
|
||||
int count = 0;
|
||||
count += fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile);
|
||||
count += fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile);
|
||||
if (count != expected)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
|
||||
|
||||
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;
|
||||
|
||||
for (int i = 0; i < V9_SIZE_SQ; ++i)
|
||||
V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
|
||||
|
||||
for (int i = 0; i < V8_SIZE_SQ; ++i)
|
||||
V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = 0;
|
||||
count += fread(V9, sizeof(float), V9_SIZE_SQ, mapFile);
|
||||
count += fread(V8, sizeof(float), V8_SIZE_SQ, mapFile);
|
||||
if (count != expected)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
|
||||
}
|
||||
|
||||
// hole data
|
||||
if (fheader.holesSize != 0)
|
||||
{
|
||||
memset(holes, 0, fheader.holesSize);
|
||||
fseek(mapFile, fheader.holesOffset, SEEK_SET);
|
||||
if (fread(holes, fheader.holesSize, 1, mapFile) != 1)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
|
||||
}
|
||||
|
||||
int count = meshData.solidVerts.size() / 3;
|
||||
float xoffset = (float(tileX)-32)*GRID_SIZE;
|
||||
float yoffset = (float(tileY)-32)*GRID_SIZE;
|
||||
|
||||
float coord[3];
|
||||
|
||||
for (int 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 (int 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 indices[] = { 0, 0, 0 };
|
||||
int loopStart = 0, loopEnd = 0, loopInc = 0;
|
||||
getLoopVars(portion, loopStart, loopEnd, loopInc);
|
||||
for (int i = loopStart; i < loopEnd; i+=loopInc)
|
||||
for (int 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)
|
||||
{
|
||||
map_liquidHeader lheader;
|
||||
fseek(mapFile, fheader.liquidMapOffset, SEEK_SET);
|
||||
if (fread(&lheader, sizeof(map_liquidHeader), 1, mapFile) != 1)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
|
||||
|
||||
|
||||
float* liquid_map = NULL;
|
||||
|
||||
if (!(lheader.flags & MAP_LIQUID_NO_TYPE))
|
||||
if (fread(liquid_type, sizeof(liquid_type), 1, mapFile) != 1)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
|
||||
|
||||
if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
|
||||
{
|
||||
uint32 toRead = lheader.width * lheader.height;
|
||||
liquid_map = new float [toRead];
|
||||
if (fread(liquid_map, sizeof(float), toRead, mapFile) != toRead)
|
||||
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
|
||||
}
|
||||
|
||||
if (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[] = { 0, 0, 0 };
|
||||
int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP;
|
||||
getLoopVars(portion, loopStart, loopEnd, loopInc);
|
||||
|
||||
// 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 = 0, loopEnd = 0, loopInc = 0, 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;
|
||||
// FIXME: "warning: the address of ‘liquid_type’ will always evaluate as ‘true’"
|
||||
|
||||
// if there is no liquid, don't use liquid
|
||||
if (!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 && fheader.holesSize != 0)
|
||||
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();
|
||||
int 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;
|
||||
|
||||
std::vector<GroupModel> groupModels;
|
||||
worldModel->getGroupModels(groupModels);
|
||||
|
||||
// all M2s need to have triangle indices reversed
|
||||
bool isM2 = instance.name.find(".m2") != std::string::npos || instance.name.find(".M2") != std::string::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);
|
||||
G3D::Vector3 position = instance.iPos;
|
||||
position.x -= 32*GRID_SIZE;
|
||||
position.y -= 32*GRID_SIZE;
|
||||
|
||||
for (std::vector<GroupModel>::iterator it = groupModels.begin(); it != groupModels.end(); ++it)
|
||||
{
|
||||
std::vector<G3D::Vector3> tempVertices;
|
||||
std::vector<G3D::Vector3> transformedVertices;
|
||||
std::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)
|
||||
{
|
||||
std::vector<G3D::Vector3> liqVerts;
|
||||
std::vector<int> liqTris;
|
||||
uint32 tilesX, tilesY, vertsX, vertsY;
|
||||
G3D::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
|
||||
|
||||
G3D::Vector3 vert;
|
||||
for (uint32 x = 0; x < vertsX; ++x)
|
||||
for (uint32 y = 0; y < vertsY; ++y)
|
||||
{
|
||||
vert = G3D::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(std::vector<G3D::Vector3> &source, std::vector<G3D::Vector3> &transformedVertices, float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position)
|
||||
{
|
||||
for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
|
||||
{
|
||||
// apply tranform, then mirror along the horizontal axes
|
||||
G3D::Vector3 v((*it) * rotation * scale + position);
|
||||
v.x *= -1.f;
|
||||
v.y *= -1.f;
|
||||
transformedVertices.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void TerrainBuilder::copyVertices(std::vector<G3D::Vector3> &source, G3D::Array<float> &dest)
|
||||
{
|
||||
for (std::vector<G3D::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(std::vector<MeshTriangle> &source, G3D::Array<int> &dest, int offset, bool flip)
|
||||
{
|
||||
if (flip)
|
||||
{
|
||||
for (std::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 (std::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)
|
||||
{
|
||||
std::map<int, int> vertMap;
|
||||
|
||||
int* t = tris.getCArray();
|
||||
float* v = verts.getCArray();
|
||||
|
||||
G3D::Array<float> cleanVerts;
|
||||
int index, count = 0;
|
||||
// collect all the vertex indices from triangle
|
||||
for (int i = 0; i < tris.size(); ++i)
|
||||
{
|
||||
if (vertMap.find(t[i]) != vertMap.end())
|
||||
continue;
|
||||
std::pair<int, int> val;
|
||||
val.first = t[i];
|
||||
|
||||
index = val.first;
|
||||
val.second = count;
|
||||
|
||||
vertMap.insert(val);
|
||||
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)
|
||||
{
|
||||
std::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];
|
||||
uint32 mid, tx, ty;
|
||||
float size;
|
||||
if (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) != 10)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _MMAP_TERRAIN_BUILDER_H
|
||||
#define _MMAP_TERRAIN_BUILDER_H
|
||||
|
||||
#include "PathCommon.h"
|
||||
#include "WorldModel.h"
|
||||
|
||||
#include "G3D/Array.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Matrix3.h"
|
||||
|
||||
namespace MMAP
|
||||
{
|
||||
enum Spot
|
||||
{
|
||||
TOP = 1,
|
||||
RIGHT = 2,
|
||||
LEFT = 3,
|
||||
BOTTOM = 4,
|
||||
ENTIRE = 5
|
||||
};
|
||||
|
||||
enum Grid
|
||||
{
|
||||
GRID_V8,
|
||||
GRID_V9
|
||||
};
|
||||
|
||||
static const int V9_SIZE = 129;
|
||||
static const int V9_SIZE_SQ = V9_SIZE*V9_SIZE;
|
||||
static const int V8_SIZE = 128;
|
||||
static const int V8_SIZE_SQ = V8_SIZE*V8_SIZE;
|
||||
static const float GRID_SIZE = 533.3333f;
|
||||
static const float GRID_PART_SIZE = GRID_SIZE/V8_SIZE;
|
||||
|
||||
// see contrib/extractor/system.cpp, CONF_use_minHeight
|
||||
static const float INVALID_MAP_LIQ_HEIGHT = -500.f;
|
||||
static const float INVALID_MAP_LIQ_HEIGHT_MAX = 5000.0f;
|
||||
|
||||
// see following files:
|
||||
// contrib/extractor/system.cpp
|
||||
// src/game/Map.cpp
|
||||
|
||||
struct MeshData
|
||||
{
|
||||
G3D::Array<float> solidVerts;
|
||||
G3D::Array<int> solidTris;
|
||||
|
||||
G3D::Array<float> liquidVerts;
|
||||
G3D::Array<int> liquidTris;
|
||||
G3D::Array<uint8> liquidType;
|
||||
|
||||
// offmesh connection data
|
||||
G3D::Array<float> offMeshConnections; // [p0y,p0z,p0x,p1y,p1z,p1x] - per connection
|
||||
G3D::Array<float> offMeshConnectionRads;
|
||||
G3D::Array<unsigned char> offMeshConnectionDirs;
|
||||
G3D::Array<unsigned char> offMeshConnectionsAreas;
|
||||
G3D::Array<unsigned short> offMeshConnectionsFlags;
|
||||
};
|
||||
|
||||
class TerrainBuilder
|
||||
{
|
||||
public:
|
||||
TerrainBuilder(bool skipLiquid);
|
||||
~TerrainBuilder();
|
||||
|
||||
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
|
||||
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
|
||||
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, const char* offMeshFilePath);
|
||||
|
||||
bool usesLiquids() { return !m_skipLiquid; }
|
||||
|
||||
// vert and triangle methods
|
||||
static void transform(std::vector<G3D::Vector3> &original, std::vector<G3D::Vector3> &transformed,
|
||||
float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position);
|
||||
static void copyVertices(std::vector<G3D::Vector3> &source, G3D::Array<float> &dest);
|
||||
static void copyIndices(std::vector<VMAP::MeshTriangle> &source, G3D::Array<int> &dest, int offest, bool flip);
|
||||
static void copyIndices(G3D::Array<int> &src, G3D::Array<int> &dest, int offset);
|
||||
static void cleanVertices(G3D::Array<float> &verts, G3D::Array<int> &tris);
|
||||
private:
|
||||
/// Loads a portion of a map's terrain
|
||||
bool loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion);
|
||||
|
||||
/// Sets loop variables for selecting only certain parts of a map's terrain
|
||||
void getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc);
|
||||
|
||||
/// Controls whether liquids are loaded
|
||||
bool m_skipLiquid;
|
||||
|
||||
/// Load the map terrain from file
|
||||
bool loadHeightMap(uint32 mapID, uint32 tileX, uint32 tileY, G3D::Array<float> &vertices, G3D::Array<int> &triangles, Spot portion);
|
||||
|
||||
/// Get the vector coordinate for a specific position
|
||||
void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v);
|
||||
|
||||
/// Get the triangle's vector indices for a specific position
|
||||
void getHeightTriangle(int square, Spot triangle, int* indices, bool liquid = false);
|
||||
|
||||
/// Determines if the specific position's triangles should be rendered
|
||||
bool isHole(int square, const uint16 holes[16][16]);
|
||||
|
||||
/// Get the liquid vector coordinate for a specific position
|
||||
void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v);
|
||||
|
||||
/// Get the liquid type for a specific position
|
||||
uint8 getLiquidType(int square, const uint8 liquid_type[16][16]);
|
||||
|
||||
// hide parameterless and copy constructor
|
||||
TerrainBuilder();
|
||||
TerrainBuilder(const TerrainBuilder &tb);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "MapTree.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "WorldModel.h"
|
||||
#include "ModelInstance.h"
|
||||
|
||||
#include "Database/DatabaseEnv.h"
|
||||
LoginDatabaseWorkerPool LoginDatabase;
|
||||
WorldDatabaseWorkerPool WorldDatabase;
|
||||
|
||||
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(std::vector<GroupModel> &groupModels)
|
||||
{
|
||||
groupModels = this->groupModels;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/WorldModel.h
|
||||
void GroupModel::getMeshData(std::vector<G3D::Vector3> &vertices, std::vector<MeshTriangle> &triangles, WmoLiquid* &liquid)
|
||||
{
|
||||
vertices = this->vertices;
|
||||
triangles = this->triangles;
|
||||
liquid = iLiquid;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/ModelInstance.h
|
||||
WorldModel* ModelInstance::getWorldModel()
|
||||
{
|
||||
return iModel;
|
||||
}
|
||||
|
||||
// declared in src/shared/vmap/WorldModel.h
|
||||
void WmoLiquid::getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const
|
||||
{
|
||||
tilesX = iTilesX;
|
||||
tilesY = iTilesY;
|
||||
corner = iCorner;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright (C)
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Debugging
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Maps
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Models
|
||||
${ACE_INCLUDE_DIR}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_executable(vmap4assembler VMapAssembler.cpp)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
set_target_properties(vmap4assembler PROPERTIES LINK_FLAGS "-framework Carbon")
|
||||
endif()
|
||||
|
||||
target_link_libraries(vmap4assembler
|
||||
collision
|
||||
g3dlib
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS vmap4assembler DESTINATION bin)
|
||||
elseif( WIN32 )
|
||||
install(TARGETS vmap4assembler DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "TileAssembler.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
{
|
||||
std::cout << "usage: " << argv[0] << " <raw data dir> <vmap dest dir>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string src = argv[1];
|
||||
std::string dest = argv[2];
|
||||
|
||||
std::cout << "using " << src << " as source directory and writing output to " << dest << std::endl;
|
||||
|
||||
VMAP::TileAssembler* ta = new VMAP::TileAssembler(src, dest);
|
||||
|
||||
if (!ta->convertWorld2())
|
||||
{
|
||||
std::cout << "exit with errors" << std::endl;
|
||||
delete ta;
|
||||
return 1;
|
||||
}
|
||||
|
||||
delete ta;
|
||||
std::cout << "Ok, all done" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
# Copyright (C)
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
file(GLOB_RECURSE sources *.cpp *.h)
|
||||
|
||||
set(include_Dirs
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
set(include_Dirs
|
||||
${include_Dirs}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/libmpq/win
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(${include_Dirs})
|
||||
|
||||
add_executable(vmap4extractor ${sources})
|
||||
|
||||
target_link_libraries(vmap4extractor
|
||||
mpq
|
||||
${BZIP2_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS vmap4extractor DESTINATION bin)
|
||||
elseif( WIN32 )
|
||||
install(TARGETS vmap4extractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "adtfile.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
char const* GetPlainName(char const* FileName)
|
||||
{
|
||||
const char * szTemp;
|
||||
|
||||
if((szTemp = strrchr(FileName, '\\')) != NULL)
|
||||
FileName = szTemp + 1;
|
||||
return FileName;
|
||||
}
|
||||
|
||||
char* GetPlainName(char* FileName)
|
||||
{
|
||||
char * szTemp;
|
||||
|
||||
if((szTemp = strrchr(FileName, '\\')) != NULL)
|
||||
FileName = szTemp + 1;
|
||||
return FileName;
|
||||
}
|
||||
|
||||
void fixnamen(char* name, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len-3; i++)
|
||||
{
|
||||
if (i > 0 && name[i] >= 'A' && name[i] <= 'Z' && isalpha(name[i-1]))
|
||||
name[i] |= 0x20;
|
||||
else if ((i == 0 || !isalpha(name[i-1])) && name[i]>='a' && name[i]<='z')
|
||||
name[i] &= ~0x20;
|
||||
}
|
||||
//extension in lowercase
|
||||
for (size_t i = len - 3; i < len; i++)
|
||||
name[i] |= 0x20;
|
||||
}
|
||||
|
||||
void fixname2(char* name, size_t len)
|
||||
{
|
||||
for (size_t i=0; i<len-3; i++)
|
||||
{
|
||||
if(name[i] == ' ')
|
||||
name[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
char* GetExtension(char* FileName)
|
||||
{
|
||||
if (char* szTemp = strrchr(FileName, '.'))
|
||||
return szTemp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ADTFile::ADTFile(char* filename): ADT(filename), nWMO(0), nMDX(0), WmoInstansName(NULL), ModelInstansName(NULL)
|
||||
{
|
||||
Adtfilename.append(filename);
|
||||
}
|
||||
|
||||
bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
|
||||
{
|
||||
if(ADT.isEof ())
|
||||
return false;
|
||||
|
||||
uint32 size;
|
||||
|
||||
string xMap;
|
||||
string yMap;
|
||||
|
||||
Adtfilename.erase(Adtfilename.find(".adt"),4);
|
||||
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));
|
||||
//string AdtMapNumber = xMap + ' ' + yMap + ' ' + GetPlainName((char*)Adtfilename.c_str());
|
||||
//printf("Processing map %s...\n", AdtMapNumber.c_str());
|
||||
//printf("MapNumber = %s\n", TempMapNumber.c_str());
|
||||
//printf("xMap = %s\n", xMap.c_str());
|
||||
//printf("yMap = %s\n", yMap.c_str());
|
||||
|
||||
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 string[size];
|
||||
while (p<buf+size)
|
||||
{
|
||||
fixnamen(p,strlen(p));
|
||||
char* s = GetPlainName(p);
|
||||
fixname2(s,strlen(s));
|
||||
|
||||
ModelInstansName[t++] = s;
|
||||
|
||||
string path(p);
|
||||
ExtractSingleModel(path);
|
||||
|
||||
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 string[size];
|
||||
while (p<buf+size)
|
||||
{
|
||||
char* s = GetPlainName(p);
|
||||
fixnamen(s, strlen(s));
|
||||
fixname2(s, strlen(s));
|
||||
p += strlen(p) + 1;
|
||||
WmoInstansName[q++] = s;
|
||||
}
|
||||
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].c_str(), map_num, tileX, tileY, dirfile);
|
||||
}
|
||||
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].c_str(), map_num, tileX, tileY, dirfile);
|
||||
}
|
||||
delete[] WmoInstansName;
|
||||
}
|
||||
}
|
||||
//======================
|
||||
ADT.seek(nextpos);
|
||||
}
|
||||
ADT.close();
|
||||
fclose(dirfile);
|
||||
return true;
|
||||
}
|
||||
|
||||
ADTFile::~ADTFile()
|
||||
{
|
||||
ADT.close();
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef ADT_H
|
||||
#define ADT_H
|
||||
|
||||
#include "mpq_libmpq04.h"
|
||||
#include "wmo.h"
|
||||
#include "model.h"
|
||||
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
#define UNITSIZE (CHUNKSIZE / 8.0f)
|
||||
|
||||
class Liquid;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
}svec;
|
||||
|
||||
struct vec
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
};
|
||||
|
||||
struct triangle
|
||||
{
|
||||
vec v[3];
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float v9[16*8+1][16*8+1];
|
||||
float v8[16*8][16*8];
|
||||
}Cell;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double v9[9][9];
|
||||
double v8[8][8];
|
||||
uint16 area_id;
|
||||
//Liquid *lq;
|
||||
float waterlevel[9][9];
|
||||
uint8 flag;
|
||||
}chunk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
chunk ch[16][16];
|
||||
}mcell;
|
||||
|
||||
struct MapChunkHeader
|
||||
{
|
||||
uint32 flags;
|
||||
uint32 ix;
|
||||
uint32 iy;
|
||||
uint32 nLayers;
|
||||
uint32 nDoodadRefs;
|
||||
uint32 ofsHeight;
|
||||
uint32 ofsNormal;
|
||||
uint32 ofsLayer;
|
||||
uint32 ofsRefs;
|
||||
uint32 ofsAlpha;
|
||||
uint32 sizeAlpha;
|
||||
uint32 ofsShadow;
|
||||
uint32 sizeShadow;
|
||||
uint32 areaid;
|
||||
uint32 nMapObjRefs;
|
||||
uint32 holes;
|
||||
uint16 s1;
|
||||
uint16 s2;
|
||||
uint32 d1;
|
||||
uint32 d2;
|
||||
uint32 d3;
|
||||
uint32 predTex;
|
||||
uint32 nEffectDoodad;
|
||||
uint32 ofsSndEmitters;
|
||||
uint32 nSndEmitters;
|
||||
uint32 ofsLiquid;
|
||||
uint32 sizeLiquid;
|
||||
float zpos;
|
||||
float xpos;
|
||||
float ypos;
|
||||
uint32 textureId;
|
||||
uint32 props;
|
||||
uint32 effectId;
|
||||
};
|
||||
|
||||
|
||||
class ADTFile
|
||||
{
|
||||
private:
|
||||
//size_t mcnk_offsets[256], mcnk_sizes[256];
|
||||
MPQFile ADT;
|
||||
//mcell Mcell;
|
||||
string Adtfilename;
|
||||
public:
|
||||
ADTFile(char* filename);
|
||||
~ADTFile();
|
||||
int nWMO;
|
||||
int nMDX;
|
||||
string* WmoInstansName;
|
||||
string* ModelInstansName;
|
||||
bool init(uint32 map_num, uint32 tileX, uint32 tileY);
|
||||
//void LoadMapChunks();
|
||||
|
||||
//uint32 wmo_count;
|
||||
/*
|
||||
const mcell& Getmcell() const
|
||||
{
|
||||
return Mcell;
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
const char * GetPlainName(const char * FileName);
|
||||
char * GetPlainName(char * FileName);
|
||||
char * GetExtension(char * FileName);
|
||||
void fixnamen(char *name, size_t len);
|
||||
void fixname2(char *name, size_t len);
|
||||
//void fixMapNamen(char *name, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "dbcfile.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
DBCFile::DBCFile(const std::string& filename):
|
||||
filename(filename), recordSize(0), recordCount(0), fieldCount(0), stringSize(0), data(NULL), stringTable(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
unsigned char header[4];
|
||||
unsigned int na,nb,es,ss;
|
||||
|
||||
f.read(header,4); // File Header
|
||||
|
||||
if (header[0]!='W' || header[1]!='D' || header[2]!='B' || header[3] != 'C')
|
||||
{
|
||||
f.close();
|
||||
data = NULL;
|
||||
printf("Critical Error: An error occured while trying to read the DBCFile %s.", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
//assert(header[0]=='W' && header[1]=='D' && header[2]=='B' && header[3] == 'C');
|
||||
|
||||
f.read(&na,4); // Number of records
|
||||
f.read(&nb,4); // Number of fields
|
||||
f.read(&es,4); // Size of a record
|
||||
f.read(&ss,4); // String size
|
||||
|
||||
recordSize = es;
|
||||
recordCount = na;
|
||||
fieldCount = nb;
|
||||
stringSize = ss;
|
||||
//assert(fieldCount*4 == recordSize);
|
||||
assert(fieldCount*4 >= recordSize);
|
||||
|
||||
data = new unsigned char[recordSize*recordCount+stringSize];
|
||||
stringTable = data + recordSize*recordCount;
|
||||
f.read(data,recordSize*recordCount+stringSize);
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
DBCFile::~DBCFile()
|
||||
{
|
||||
delete [] data;
|
||||
}
|
||||
|
||||
DBCFile::Record DBCFile::getRecord(size_t id)
|
||||
{
|
||||
assert(data);
|
||||
return Record(*this, data + id*recordSize);
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::begin()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, data);
|
||||
}
|
||||
|
||||
DBCFile::Iterator DBCFile::end()
|
||||
{
|
||||
assert(data);
|
||||
return Iterator(*this, stringTable);
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef DBCFILE_H
|
||||
#define DBCFILE_H
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
class DBCFile
|
||||
{
|
||||
public:
|
||||
DBCFile(const std::string &filename);
|
||||
~DBCFile();
|
||||
|
||||
// Open database. It must be openened before it can be used.
|
||||
bool open();
|
||||
|
||||
// TODO: Add a close function?
|
||||
|
||||
// Database exceptions
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &message): message(message)
|
||||
{ }
|
||||
virtual ~Exception()
|
||||
{ }
|
||||
const std::string &getMessage() {return message;}
|
||||
private:
|
||||
std::string message;
|
||||
};
|
||||
|
||||
//
|
||||
class NotFound: public Exception
|
||||
{
|
||||
public:
|
||||
NotFound(): Exception("Key was not found")
|
||||
{ }
|
||||
};
|
||||
|
||||
// Iteration over database
|
||||
class Iterator;
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
Record& operator= (const Record& r)
|
||||
{
|
||||
file = r.file;
|
||||
offset = r.offset;
|
||||
return *this;
|
||||
}
|
||||
float getFloat(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<float*>(offset+field*4);
|
||||
}
|
||||
unsigned int getUInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<unsigned int*>(offset+(field*4));
|
||||
}
|
||||
int getInt(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
return *reinterpret_cast<int*>(offset+field*4);
|
||||
}
|
||||
unsigned char getByte(size_t ofs) const
|
||||
{
|
||||
assert(ofs < file.recordSize);
|
||||
return *reinterpret_cast<unsigned char*>(offset+ofs);
|
||||
}
|
||||
const char *getString(size_t field) const
|
||||
{
|
||||
assert(field < file.fieldCount);
|
||||
size_t stringOffset = getUInt(field);
|
||||
assert(stringOffset < file.stringSize);
|
||||
//char * tmp = (char*)file.stringTable + stringOffset;
|
||||
//unsigned char * tmp2 = file.stringTable + stringOffset;
|
||||
return reinterpret_cast<char*>(file.stringTable + stringOffset);
|
||||
}
|
||||
private:
|
||||
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
|
||||
DBCFile &file;
|
||||
unsigned char *offset;
|
||||
|
||||
friend class DBCFile;
|
||||
friend class Iterator;
|
||||
};
|
||||
|
||||
/* Iterator that iterates over records */
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(DBCFile &file, unsigned char *offset):
|
||||
record(file, offset) {}
|
||||
/// Advance (prefix only)
|
||||
Iterator & operator++() {
|
||||
record.offset += record.file.recordSize;
|
||||
return *this;
|
||||
}
|
||||
/// Return address of current instance
|
||||
Record const & operator*() const { return record; }
|
||||
const Record* operator->() const {
|
||||
return &record;
|
||||
}
|
||||
/// Comparison
|
||||
bool operator==(const Iterator &b) const
|
||||
{
|
||||
return record.offset == b.record.offset;
|
||||
}
|
||||
bool operator!=(const Iterator &b) const
|
||||
{
|
||||
return record.offset != b.record.offset;
|
||||
}
|
||||
private:
|
||||
Record record;
|
||||
};
|
||||
|
||||
// Get record by id
|
||||
Record getRecord(size_t id);
|
||||
/// Get begin iterator over records
|
||||
Iterator begin();
|
||||
/// Get begin iterator over records
|
||||
Iterator end();
|
||||
/// Trivial
|
||||
size_t getRecordCount() const { return recordCount;}
|
||||
size_t getFieldCount() const { return fieldCount; }
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
size_t recordSize;
|
||||
size_t recordCount;
|
||||
size_t fieldCount;
|
||||
size_t stringSize;
|
||||
unsigned char *data;
|
||||
unsigned char *stringTable;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "model.h"
|
||||
#include "dbcfile.h"
|
||||
#include "adtfile.h"
|
||||
#include "vmapexport.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
bool ExtractSingleModel(std::string& fname)
|
||||
{
|
||||
char * name = GetPlainName((char*)fname.c_str());
|
||||
char * ext = GetExtension(name);
|
||||
|
||||
// < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file
|
||||
if (!strcmp(ext, ".mdx"))
|
||||
{
|
||||
// replace .mdx -> .m2
|
||||
fname.erase(fname.length()-2,2);
|
||||
fname.append("2");
|
||||
}
|
||||
// >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file
|
||||
// nothing do
|
||||
|
||||
std::string output(szWorkDirWmo);
|
||||
output += "/";
|
||||
output += name;
|
||||
|
||||
if (FileExists(output.c_str()))
|
||||
return true;
|
||||
|
||||
Model mdl(fname);
|
||||
if (!mdl.open())
|
||||
return false;
|
||||
|
||||
return mdl.ConvertToVMAPModel(output.c_str());
|
||||
}
|
||||
|
||||
void ExtractGameobjectModels()
|
||||
{
|
||||
printf("Extracting GameObject models...");
|
||||
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;
|
||||
|
||||
std::string modelListPath = basepath + "temp_gameobject_models";
|
||||
FILE* model_list = fopen(modelListPath.c_str(), "wb");
|
||||
if (!model_list)
|
||||
{
|
||||
printf("Fatal error: Could not open file %s\n", modelListPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (DBCFile::Iterator it = dbc.begin(); it != dbc.end(); ++it)
|
||||
{
|
||||
path = it->getString(1);
|
||||
|
||||
if (path.length() < 4)
|
||||
continue;
|
||||
|
||||
fixnamen((char*)path.c_str(), path.size());
|
||||
char * name = GetPlainName((char*)path.c_str());
|
||||
fixname2(name, strlen(name));
|
||||
|
||||
char * ch_ext = GetExtension(name);
|
||||
if (!ch_ext)
|
||||
continue;
|
||||
|
||||
strToLower(ch_ext);
|
||||
|
||||
bool result = false;
|
||||
if (!strcmp(ch_ext, ".wmo"))
|
||||
{
|
||||
result = ExtractSingleWmo(path);
|
||||
}
|
||||
else if (!strcmp(ch_ext, ".mdl"))
|
||||
{
|
||||
// TODO: extract .mdl files, if needed
|
||||
continue;
|
||||
}
|
||||
else //if (!strcmp(ch_ext, ".mdx") || !strcmp(ch_ext, ".m2"))
|
||||
{
|
||||
result = ExtractSingleModel(path);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
uint32 displayId = it->getUInt(0);
|
||||
uint32 path_length = strlen(name);
|
||||
fwrite(&displayId, sizeof(uint32), 1, model_list);
|
||||
fwrite(&path_length, sizeof(uint32), 1, model_list);
|
||||
fwrite(name, sizeof(char), path_length, model_list);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(model_list);
|
||||
|
||||
printf("Done!\n");
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef LOAD_LIB_H
|
||||
#define LOAD_LIB_H
|
||||
|
||||
#ifdef WIN32
|
||||
typedef __int64 int64;
|
||||
typedef __int32 int32;
|
||||
typedef __int16 int16;
|
||||
typedef __int8 int8;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef unsigned __int16 uint16;
|
||||
typedef unsigned __int8 uint8;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#ifndef uint64_t
|
||||
#ifdef __linux__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#endif
|
||||
typedef int64_t int64;
|
||||
typedef int32_t int32;
|
||||
typedef int16_t int16;
|
||||
typedef int8_t int8;
|
||||
typedef uint64_t uint64;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint8_t uint8;
|
||||
#endif
|
||||
|
||||
#define FILE_FORMAT_VERSION 18
|
||||
|
||||
//
|
||||
// File version chunk
|
||||
//
|
||||
struct file_MVER
|
||||
{
|
||||
union{
|
||||
uint32 fcc;
|
||||
char fcc_txt[4];
|
||||
};
|
||||
uint32 size;
|
||||
uint32 ver;
|
||||
};
|
||||
|
||||
class FileLoader{
|
||||
uint8 *data;
|
||||
uint32 data_size;
|
||||
public:
|
||||
virtual bool prepareLoadedData();
|
||||
uint8 *GetData() {return data;}
|
||||
uint32 GetDataSize() {return data_size;}
|
||||
|
||||
file_MVER *version;
|
||||
FileLoader();
|
||||
~FileLoader();
|
||||
bool loadFile(char *filename, bool log = true);
|
||||
virtual void free();
|
||||
};
|
||||
#endif
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "model.h"
|
||||
#include "wmo.h"
|
||||
#include "mpq_libmpq04.h"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
|
||||
Model::Model(std::string &filename) : filename(filename), vertices(0), indices(0)
|
||||
{
|
||||
memset(&header, 0, sizeof(header));
|
||||
}
|
||||
|
||||
bool Model::open()
|
||||
{
|
||||
MPQFile f(filename.c_str());
|
||||
|
||||
if (f.isEof())
|
||||
{
|
||||
f.close();
|
||||
// Do not show this error on console to avoid confusion, the extractor can continue working even if some models fail to load
|
||||
//printf("Error loading model %s\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_unload();
|
||||
|
||||
memcpy(&header, f.getBuffer(), sizeof(ModelHeader));
|
||||
if(header.nBoundingTriangles > 0)
|
||||
{
|
||||
f.seek(0);
|
||||
f.seekRelative(header.ofsBoundingVertices);
|
||||
vertices = new Vec3D[header.nBoundingVertices];
|
||||
f.read(vertices,header.nBoundingVertices*12);
|
||||
for (uint32 i=0; i<header.nBoundingVertices; i++)
|
||||
vertices[i] = fixCoordSystem(vertices[i]);
|
||||
f.seek(0);
|
||||
f.seekRelative(header.ofsBoundingTriangles);
|
||||
indices = new uint16[header.nBoundingTriangles];
|
||||
f.read(indices,header.nBoundingTriangles*2);
|
||||
f.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("not included %s\n", filename.c_str());
|
||||
f.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Model::ConvertToVMAPModel(const char * outfilename)
|
||||
{
|
||||
int N[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
FILE* output=fopen(outfilename, "wb");
|
||||
if (!output)
|
||||
{
|
||||
printf("Can't create the output file '%s'\n",outfilename);
|
||||
return false;
|
||||
}
|
||||
fwrite(szRawVMAPMagic, 8, 1, output);
|
||||
uint32 nVertices = header.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 = header.nBoundingTriangles;
|
||||
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)
|
||||
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)
|
||||
{
|
||||
for(uint32 vpos=0; vpos <nVertices; ++vpos)
|
||||
std::swap(vertices[vpos].y, vertices[vpos].z);
|
||||
|
||||
fwrite(vertices, sizeof(float)*3, nVertices, output);
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Vec3D fixCoordSystem(Vec3D v)
|
||||
{
|
||||
return Vec3D(v.x, v.z, -v.y);
|
||||
}
|
||||
|
||||
Vec3D fixCoordSystem2(Vec3D v)
|
||||
{
|
||||
return Vec3D(v.x, v.z, v.y);
|
||||
}
|
||||
|
||||
ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile)
|
||||
{
|
||||
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]);
|
||||
f.read(&scale, 2);
|
||||
f.read(&flags, 2);
|
||||
// scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
|
||||
sc = scale / 1024.0f;
|
||||
|
||||
char tempname[512];
|
||||
sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);
|
||||
FILE* 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;
|
||||
int count = fread(&nVertices, sizeof (int), 1, input);
|
||||
fclose(input);
|
||||
|
||||
if (count != 1 || nVertices == 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=strlen(ModelInstName);
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
|
||||
|
||||
/* int realx1 = (int) ((float) pos.x / 533.333333f);
|
||||
int realy1 = (int) ((float) pos.z / 533.333333f);
|
||||
int realx2 = (int) ((float) pos.x / 533.333333f);
|
||||
int realy2 = (int) ((float) pos.z / 533.333333f);
|
||||
|
||||
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
|
||||
MapName,
|
||||
ModelInstName,
|
||||
(float) pos.x, (float) pos.y, (float) pos.z,
|
||||
(float) rot.x, (float) rot.y, (float) rot.z,
|
||||
sc,
|
||||
nVertices,
|
||||
realx1, realy1,
|
||||
realx2, realy2
|
||||
); */
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include "loadlib/loadlib.h"
|
||||
#include "vec3d.h"
|
||||
#include "modelheaders.h"
|
||||
#include <vector>
|
||||
|
||||
class MPQFile;
|
||||
|
||||
Vec3D fixCoordSystem(Vec3D v);
|
||||
|
||||
class Model
|
||||
{
|
||||
private:
|
||||
void _unload()
|
||||
{
|
||||
delete[] vertices;
|
||||
delete[] indices;
|
||||
vertices = NULL;
|
||||
indices = NULL;
|
||||
}
|
||||
std::string filename;
|
||||
public:
|
||||
ModelHeader header;
|
||||
Vec3D* vertices;
|
||||
uint16* indices;
|
||||
|
||||
bool open();
|
||||
bool ConvertToVMAPModel(char const* outfilename);
|
||||
|
||||
Model(std::string& filename);
|
||||
~Model() { _unload(); }
|
||||
};
|
||||
|
||||
class ModelInstance
|
||||
{
|
||||
public:
|
||||
uint32 id;
|
||||
Vec3D pos, rot;
|
||||
uint16 scale, flags;
|
||||
float sc;
|
||||
|
||||
ModelInstance() : id(0), scale(0), flags(0), sc(0.0f) {}
|
||||
ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#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)
|
||||
|
||||
struct ModelHeader
|
||||
{
|
||||
char id[4];
|
||||
uint8 version[4];
|
||||
uint32 nameLength;
|
||||
uint32 nameOfs;
|
||||
uint32 type;
|
||||
uint32 nGlobalSequences;
|
||||
uint32 ofsGlobalSequences;
|
||||
uint32 nAnimations;
|
||||
uint32 ofsAnimations;
|
||||
uint32 nAnimationLookup;
|
||||
uint32 ofsAnimationLookup;
|
||||
uint32 nBones;
|
||||
uint32 ofsBones;
|
||||
uint32 nKeyBoneLookup;
|
||||
uint32 ofsKeyBoneLookup;
|
||||
uint32 nVertices;
|
||||
uint32 ofsVertices;
|
||||
uint32 nViews;
|
||||
uint32 nColors;
|
||||
uint32 ofsColors;
|
||||
uint32 nTextures;
|
||||
uint32 ofsTextures;
|
||||
uint32 nTransparency;
|
||||
uint32 ofsTransparency;
|
||||
uint32 nTextureanimations;
|
||||
uint32 ofsTextureanimations;
|
||||
uint32 nTexReplace;
|
||||
uint32 ofsTexReplace;
|
||||
uint32 nRenderFlags;
|
||||
uint32 ofsRenderFlags;
|
||||
uint32 nBoneLookupTable;
|
||||
uint32 ofsBoneLookupTable;
|
||||
uint32 nTexLookup;
|
||||
uint32 ofsTexLookup;
|
||||
uint32 nTexUnits;
|
||||
uint32 ofsTexUnits;
|
||||
uint32 nTransLookup;
|
||||
uint32 ofsTransLookup;
|
||||
uint32 nTexAnimLookup;
|
||||
uint32 ofsTexAnimLookup;
|
||||
float floats[14];
|
||||
uint32 nBoundingTriangles;
|
||||
uint32 ofsBoundingTriangles;
|
||||
uint32 nBoundingVertices;
|
||||
uint32 ofsBoundingVertices;
|
||||
uint32 nBoundingNormals;
|
||||
uint32 ofsBoundingNormals;
|
||||
uint32 nAttachments;
|
||||
uint32 ofsAttachments;
|
||||
uint32 nAttachLookup;
|
||||
uint32 ofsAttachLookup;
|
||||
uint32 nAttachments_2;
|
||||
uint32 ofsAttachments_2;
|
||||
uint32 nLights;
|
||||
uint32 ofsLights;
|
||||
uint32 nCameras;
|
||||
uint32 ofsCameras;
|
||||
uint32 nCameraLookup;
|
||||
uint32 ofsCameraLookup;
|
||||
uint32 nRibbonEmitters;
|
||||
uint32 ofsRibbonEmitters;
|
||||
uint32 nParticleEmitters;
|
||||
uint32 ofsParticleEmitters;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "mpq_libmpq04.h"
|
||||
#include <deque>
|
||||
#include <cstdio>
|
||||
|
||||
ArchiveSet gOpenArchives;
|
||||
|
||||
MPQArchive::MPQArchive(const char* filename)
|
||||
{
|
||||
int result = libmpq__archive_open(&mpq_a, filename, -1);
|
||||
printf("Opening %s\n", filename);
|
||||
if(result) {
|
||||
switch(result) {
|
||||
case LIBMPQ_ERROR_OPEN :
|
||||
printf("Error opening archive '%s': Does file really exist?\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_FORMAT : /* bad file format */
|
||||
printf("Error opening archive '%s': Bad file format\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_SEEK : /* seeking in file failed */
|
||||
printf("Error opening archive '%s': Seeking in file failed\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_READ : /* Read error in archive */
|
||||
printf("Error opening archive '%s': Read error in archive\n", filename);
|
||||
break;
|
||||
case LIBMPQ_ERROR_MALLOC : /* maybe not enough memory? :) */
|
||||
printf("Error opening archive '%s': Maybe not enough memory\n", filename);
|
||||
break;
|
||||
default:
|
||||
printf("Error opening archive '%s': Unknown error\n", filename);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
gOpenArchives.push_front(this);
|
||||
}
|
||||
|
||||
void MPQArchive::close()
|
||||
{
|
||||
//gOpenArchives.erase(erase(&mpq_a);
|
||||
libmpq__archive_close(mpq_a);
|
||||
}
|
||||
|
||||
MPQFile::MPQFile(const char* filename):
|
||||
eof(false),
|
||||
buffer(0),
|
||||
pointer(0),
|
||||
size(0)
|
||||
{
|
||||
for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i)
|
||||
{
|
||||
mpq_archive *mpq_a = (*i)->mpq_a;
|
||||
|
||||
uint32 filenum;
|
||||
if(libmpq__file_number(mpq_a, filename, &filenum)) continue;
|
||||
libmpq__off_t transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
// HACK: in patch.mpq some files don't want to open and give 1 for filesize
|
||||
if (size<=1) {
|
||||
// printf("info: file %s has size %d; considered dummy file.\n", filename, size);
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
return;
|
||||
}
|
||||
buffer = new char[size];
|
||||
|
||||
//libmpq_file_getdata
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
/*libmpq_file_getdata(&mpq_a, hash, fileno, (unsigned char*)buffer);*/
|
||||
return;
|
||||
|
||||
}
|
||||
eof = true;
|
||||
buffer = 0;
|
||||
}
|
||||
|
||||
size_t MPQFile::read(void* dest, size_t bytes)
|
||||
{
|
||||
if (eof) return 0;
|
||||
|
||||
size_t rpos = pointer + bytes;
|
||||
if (rpos > size_t(size)) {
|
||||
bytes = size - pointer;
|
||||
eof = true;
|
||||
}
|
||||
|
||||
memcpy(dest, &(buffer[pointer]), bytes);
|
||||
|
||||
pointer = rpos;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void MPQFile::seek(int offset)
|
||||
{
|
||||
pointer = offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::seekRelative(int offset)
|
||||
{
|
||||
pointer += offset;
|
||||
eof = (pointer >= size);
|
||||
}
|
||||
|
||||
void MPQFile::close()
|
||||
{
|
||||
if (buffer) delete[] buffer;
|
||||
buffer = 0;
|
||||
eof = true;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef MPQ_H
|
||||
#define MPQ_H
|
||||
|
||||
#include "loadlib/loadlib.h"
|
||||
#include "libmpq/mpq.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class MPQArchive
|
||||
{
|
||||
|
||||
public:
|
||||
mpq_archive_s *mpq_a;
|
||||
|
||||
MPQArchive(const char* filename);
|
||||
void close();
|
||||
|
||||
void GetFileListTo(vector<string>& filelist) {
|
||||
uint32_t filenum;
|
||||
if(libmpq__file_number(mpq_a, "(listfile)", &filenum)) return;
|
||||
libmpq__off_t size, transferred;
|
||||
libmpq__file_unpacked_size(mpq_a, filenum, &size);
|
||||
|
||||
char *buffer = new char[size + 1];
|
||||
buffer[size] = '\0';
|
||||
|
||||
libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred);
|
||||
|
||||
char seps[] = "\n";
|
||||
char *token;
|
||||
|
||||
token = strtok( buffer, seps );
|
||||
uint32 counter = 0;
|
||||
while ((token != NULL) && (counter < size)) {
|
||||
//cout << token << endl;
|
||||
token[strlen(token) - 1] = 0;
|
||||
string s = token;
|
||||
filelist.push_back(s);
|
||||
counter += strlen(token) + 2;
|
||||
token = strtok(NULL, seps);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
typedef std::deque<MPQArchive*> ArchiveSet;
|
||||
|
||||
class MPQFile
|
||||
{
|
||||
//MPQHANDLE handle;
|
||||
bool eof;
|
||||
char *buffer;
|
||||
libmpq__off_t pointer,size;
|
||||
|
||||
// disable copying
|
||||
MPQFile(const MPQFile& /*f*/) {}
|
||||
void operator=(const MPQFile& /*f*/) {}
|
||||
|
||||
public:
|
||||
MPQFile(const char* filename); // filenames are not case sensitive
|
||||
~MPQFile() { close(); }
|
||||
size_t read(void* dest, size_t bytes);
|
||||
size_t getSize() { return size; }
|
||||
size_t getPos() { return pointer; }
|
||||
char* getBuffer() { return buffer; }
|
||||
char* getPointer() { return buffer + pointer; }
|
||||
bool isEof() { return eof; }
|
||||
void seek(int offset);
|
||||
void seekRelative(int offset);
|
||||
void close();
|
||||
};
|
||||
|
||||
inline void flipcc(char *fcc)
|
||||
{
|
||||
char t;
|
||||
t=fcc[0];
|
||||
fcc[0]=fcc[3];
|
||||
fcc[3]=t;
|
||||
t=fcc[1];
|
||||
fcc[1]=fcc[2];
|
||||
fcc[2]=t;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,236 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef VEC3D_H
|
||||
#define VEC3D_H
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
class Vec3D
|
||||
{
|
||||
public:
|
||||
float x,y,z;
|
||||
|
||||
Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {}
|
||||
|
||||
Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {}
|
||||
|
||||
Vec3D& operator= (const Vec3D &v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D operator+ (const Vec3D &v) const
|
||||
{
|
||||
Vec3D r(x+v.x,y+v.y,z+v.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
Vec3D operator- (const Vec3D &v) const
|
||||
{
|
||||
Vec3D r(x-v.x,y-v.y,z-v.z);
|
||||
return r;
|
||||
}
|
||||
|
||||
float operator* (const Vec3D &v) const
|
||||
{
|
||||
return x*v.x + y*v.y + z*v.z;
|
||||
}
|
||||
|
||||
Vec3D operator* (float d) const
|
||||
{
|
||||
Vec3D r(x*d,y*d,z*d);
|
||||
return r;
|
||||
}
|
||||
|
||||
friend Vec3D operator* (float d, const Vec3D& v)
|
||||
{
|
||||
return v * d;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Vec3D& operator+= (const Vec3D &v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D& operator-= (const Vec3D &v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D& operator*= (float d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
z *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float lengthSquared() const
|
||||
{
|
||||
return x*x+y*y+z*z;
|
||||
}
|
||||
|
||||
float length() const
|
||||
{
|
||||
return sqrt(x*x+y*y+z*z);
|
||||
}
|
||||
|
||||
Vec3D& normalize()
|
||||
{
|
||||
this->operator*= (1.0f/length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3D operator~ () const
|
||||
{
|
||||
Vec3D r(*this);
|
||||
r.normalize();
|
||||
return r;
|
||||
}
|
||||
|
||||
friend std::istream& operator>>(std::istream& in, Vec3D& v)
|
||||
{
|
||||
in >> v.x >> v.y >> v.z;
|
||||
return in;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const Vec3D& v)
|
||||
{
|
||||
out << v.x << " " << v.y << " " << v.z;
|
||||
return out;
|
||||
}
|
||||
|
||||
operator float*()
|
||||
{
|
||||
return (float*)this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Vec2D
|
||||
{
|
||||
public:
|
||||
float x,y;
|
||||
|
||||
Vec2D(float x0 = 0.0f, float y0 = 0.0f) : x(x0), y(y0) {}
|
||||
|
||||
Vec2D(const Vec2D& v) : x(v.x), y(v.y) {}
|
||||
|
||||
Vec2D& operator= (const Vec2D &v) {
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D operator+ (const Vec2D &v) const
|
||||
{
|
||||
Vec2D r(x+v.x,y+v.y);
|
||||
return r;
|
||||
}
|
||||
|
||||
Vec2D operator- (const Vec2D &v) const
|
||||
{
|
||||
Vec2D r(x-v.x,y-v.y);
|
||||
return r;
|
||||
}
|
||||
|
||||
float operator* (const Vec2D &v) const
|
||||
{
|
||||
return x*v.x + y*v.y;
|
||||
}
|
||||
|
||||
Vec2D operator* (float d) const
|
||||
{
|
||||
Vec2D r(x*d,y*d);
|
||||
return r;
|
||||
}
|
||||
|
||||
friend Vec2D operator* (float d, const Vec2D& v)
|
||||
{
|
||||
return v * d;
|
||||
}
|
||||
|
||||
Vec2D& operator+= (const Vec2D &v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D& operator-= (const Vec2D &v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D& operator*= (float d)
|
||||
{
|
||||
x *= d;
|
||||
y *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float lengthSquared() const
|
||||
{
|
||||
return x*x+y*y;
|
||||
}
|
||||
|
||||
float length() const
|
||||
{
|
||||
return sqrt(x*x+y*y);
|
||||
}
|
||||
|
||||
Vec2D& normalize()
|
||||
{
|
||||
this->operator*= (1.0f/length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec2D operator~ () const
|
||||
{
|
||||
Vec2D r(*this);
|
||||
r.normalize();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
friend std::istream& operator>>(std::istream& in, Vec2D& v)
|
||||
{
|
||||
in >> v.x >> v.y;
|
||||
return in;
|
||||
}
|
||||
|
||||
operator float*()
|
||||
{
|
||||
return (float*)this;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,526 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef 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 "mpq_libmpq04.h"
|
||||
|
||||
#include "vmapexport.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
#define MPQ_BLOCK_SIZE 0x1000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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 = false;
|
||||
|
||||
// Constants
|
||||
|
||||
//static const char * szWorkDirMaps = ".\\Maps";
|
||||
const char* szWorkDirWmo = "./Buildings";
|
||||
const char* szRawVMAPMagic = "VMAP041";
|
||||
|
||||
// Local testing functions
|
||||
|
||||
bool FileExists(const char* file)
|
||||
{
|
||||
if (FILE* n = fopen(file, "rb"))
|
||||
{
|
||||
fclose(n);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void strToLower(char* str)
|
||||
{
|
||||
while(*str)
|
||||
{
|
||||
*str=tolower(*str);
|
||||
++str;
|
||||
}
|
||||
}
|
||||
|
||||
// copied from contrib/extractor/System.cpp
|
||||
void ReadLiquidTypeTableDBC()
|
||||
{
|
||||
printf("Read LiquidType.dbc file...");
|
||||
DBCFile dbc("DBFilesClient\\LiquidType.dbc");
|
||||
if(!dbc.open())
|
||||
{
|
||||
printf("Fatal error: Invalid LiquidType.dbc file format!\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("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count);
|
||||
}
|
||||
|
||||
bool ExtractWmo()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
//const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"};
|
||||
|
||||
for (ArchiveSet::const_iterator ar_itr = gOpenArchives.begin(); ar_itr != gOpenArchives.end() && success; ++ar_itr)
|
||||
{
|
||||
vector<string> filelist;
|
||||
|
||||
(*ar_itr)->GetFileListTo(filelist);
|
||||
for (vector<string>::iterator fname = filelist.begin(); fname != filelist.end() && success; ++fname)
|
||||
{
|
||||
if (fname->find(".wmo") != string::npos)
|
||||
success = ExtractSingleWmo(*fname);
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
printf("\nExtract wmo complete (No (fatal) errors)\n");
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ExtractSingleWmo(std::string& fname)
|
||||
{
|
||||
// Copy files from archive
|
||||
|
||||
char szLocalFile[1024];
|
||||
const char * plain_name = GetPlainName(fname.c_str());
|
||||
sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name);
|
||||
fixnamen(szLocalFile,strlen(szLocalFile));
|
||||
|
||||
if (FileExists(szLocalFile))
|
||||
return true;
|
||||
|
||||
int p = 0;
|
||||
// Select root wmo files
|
||||
char const* rchr = strrchr(plain_name, '_');
|
||||
if (rchr != NULL)
|
||||
{
|
||||
char cpy[4];
|
||||
memcpy(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;
|
||||
std::cout << "Extracting " << fname << std::endl;
|
||||
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);
|
||||
int Wmo_nVertices = 0;
|
||||
//printf("root has %d groups\n", froot->nGroups);
|
||||
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_%03u.wmo", temp, i);
|
||||
//printf("Trying to open groupfile %s\n",groupFileName);
|
||||
|
||||
string s = groupFileName;
|
||||
WMOGroup fgroup(s);
|
||||
if(!fgroup.open())
|
||||
{
|
||||
printf("Could not open all Group file for: %s\n", plain_name);
|
||||
file_ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void ParsMapFiles()
|
||||
{
|
||||
char fn[512];
|
||||
//char id_filename[64];
|
||||
char id[10];
|
||||
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\n[", map_ids[i].id);
|
||||
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);
|
||||
delete ADT;
|
||||
}
|
||||
}
|
||||
printf("#");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("]\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)
|
||||
{
|
||||
if(!hasInputPathParam)
|
||||
getGamePath();
|
||||
|
||||
printf("\nGame path: %s\n", input_path);
|
||||
|
||||
char path[512];
|
||||
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");
|
||||
pArchiveNames.push_back(in_path + *i + "/lichking-locale-" + *i + ".MPQ");
|
||||
}
|
||||
|
||||
// open expansion and common files
|
||||
pArchiveNames.push_back(input_path + string("common.MPQ"));
|
||||
pArchiveNames.push_back(input_path + string("common-2.MPQ"));
|
||||
pArchiveNames.push_back(input_path + string("expansion.MPQ"));
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processArgv(int argc, char ** argv, const char *versionString)
|
||||
{
|
||||
bool result = true;
|
||||
hasInputPathParam = false;
|
||||
preciseVectorData = false;
|
||||
|
||||
for(int i = 1; i < argc; ++i)
|
||||
{
|
||||
if(strcmp("-s",argv[i]) == 0)
|
||||
{
|
||||
preciseVectorData = false;
|
||||
}
|
||||
else if(strcmp("-d",argv[i]) == 0)
|
||||
{
|
||||
if((i+1)<argc)
|
||||
{
|
||||
hasInputPathParam = true;
|
||||
strcpy(input_path, argv[i+1]);
|
||||
if (input_path[strlen(input_path) - 1] != '\\' && input_path[strlen(input_path) - 1] != '/')
|
||||
strcat(input_path, "/");
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else if(strcmp("-?",argv[1]) == 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
else if(strcmp("-l",argv[i]) == 0)
|
||||
{
|
||||
preciseVectorData = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!result)
|
||||
{
|
||||
printf("Extract %s.\n",versionString);
|
||||
printf("%s [-?][-s][-l][-d <path>]\n", argv[0]);
|
||||
printf(" -s : (default) small size (data size optimization), ~500MB less vmap data.\n");
|
||||
printf(" -l : large size, ~500MB more vmap data. (might contain more details)\n");
|
||||
printf(" -d <path>: Path to the vector data source folder.\n");
|
||||
printf(" -? : This message.\n");
|
||||
}
|
||||
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)
|
||||
{
|
||||
bool success=true;
|
||||
const char *versionString = "V4.00 2012_02";
|
||||
|
||||
// Use command line arguments, when some
|
||||
if (!processArgv(argc, argv, versionString))
|
||||
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;
|
||||
if (!stat(sdir.c_str(), &status) || !stat(sdir_bin.c_str(), &status))
|
||||
{
|
||||
printf("Your output directory seems to be polluted, please use an empty directory!\n");
|
||||
printf("<press return to exit>");
|
||||
char garbage[2];
|
||||
return scanf("%c", garbage);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Extract %s. Beginning work ....\n",versionString);
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
// Create the working directory
|
||||
if (mkdir(szWorkDirWmo
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
, 0711
|
||||
#endif
|
||||
))
|
||||
success = (errno == EEXIST);
|
||||
|
||||
// prepare archive name list
|
||||
std::vector<std::string> archiveNames;
|
||||
fillArchiveNameVector(archiveNames);
|
||||
for (size_t i=0; i < archiveNames.size(); ++i)
|
||||
{
|
||||
MPQArchive *archive = new MPQArchive(archiveNames[i].c_str());
|
||||
if (gOpenArchives.empty() || 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;
|
||||
}
|
||||
ReadLiquidTypeTableDBC();
|
||||
|
||||
// extract data
|
||||
if (success)
|
||||
success = ExtractWmo();
|
||||
|
||||
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
//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 - %s\n",map_ids[x].name);
|
||||
}
|
||||
|
||||
|
||||
delete dbc;
|
||||
ParsMapFiles();
|
||||
delete [] map_ids;
|
||||
//nError = ERROR_SUCCESS;
|
||||
// Extract models, listed in DameObjectDisplayInfo.dbc
|
||||
ExtractGameobjectModels();
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
if (!success)
|
||||
{
|
||||
printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n",versionString, preciseVectorData);
|
||||
getchar();
|
||||
}
|
||||
|
||||
printf("Extract %s. Work complete. No errors.\n",versionString);
|
||||
delete [] LiqType;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef VMAPEXPORT_H
|
||||
#define VMAPEXPORT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
enum ModelFlags
|
||||
{
|
||||
MOD_M2 = 1,
|
||||
MOD_WORLDSPAWN = 1<<1,
|
||||
MOD_HAS_BOUND = 1<<2
|
||||
};
|
||||
|
||||
extern const char * szWorkDirWmo;
|
||||
extern const char * szRawVMAPMagic; // vmap magic string for extracted raw vmap data
|
||||
|
||||
bool FileExists(const char * file);
|
||||
void strToLower(char* str);
|
||||
|
||||
bool ExtractSingleWmo(std::string& fname);
|
||||
bool ExtractSingleModel(std::string& fname);
|
||||
|
||||
void ExtractGameobjectModels();
|
||||
|
||||
#endif
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "wdtfile.h"
|
||||
#include "adtfile.h"
|
||||
#include <cstdio>
|
||||
|
||||
char * wdtGetPlainName(char * FileName)
|
||||
{
|
||||
char * szTemp;
|
||||
|
||||
if((szTemp = strrchr(FileName, '\\')) != NULL)
|
||||
FileName = szTemp + 1;
|
||||
return FileName;
|
||||
}
|
||||
|
||||
WDTFile::WDTFile(char* file_name, char* file_name1) : WDT(file_name), gWmoInstansName(NULL), gnWMO(0)
|
||||
{
|
||||
filename.append(file_name1,strlen(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)
|
||||
{
|
||||
char* s=wdtGetPlainName(p);
|
||||
fixnamen(s,strlen(s));
|
||||
p=p+strlen(p)+1;
|
||||
gWmoInstansName[q++] = s;
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(fourcc, "MODF"))
|
||||
{
|
||||
// global wmo instance data
|
||||
if (size)
|
||||
{
|
||||
gnWMO = (int)size / 64;
|
||||
|
||||
for (int i = 0; i < gnWMO; ++i)
|
||||
{
|
||||
int id;
|
||||
WDT.read(&id, 4);
|
||||
WMOInstance inst(WDT,gWmoInstansName[id].c_str(), mapID, 65, 65, dirfile);
|
||||
}
|
||||
|
||||
delete[] gWmoInstansName;
|
||||
}
|
||||
}
|
||||
WDT.seek((int)nextpos);
|
||||
}
|
||||
|
||||
WDT.close();
|
||||
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);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WDTFILE_H
|
||||
#define WDTFILE_H
|
||||
|
||||
#include "mpq_libmpq04.h"
|
||||
#include "wmo.h"
|
||||
#include <string>
|
||||
#include "stdlib.h"
|
||||
|
||||
class ADTFile;
|
||||
|
||||
class WDTFile
|
||||
{
|
||||
private:
|
||||
MPQFile WDT;
|
||||
string filename;
|
||||
public:
|
||||
WDTFile(char* file_name, char* file_name1);
|
||||
~WDTFile(void);
|
||||
bool init(char* map_id, unsigned int mapID);
|
||||
|
||||
string* gWmoInstansName;
|
||||
int gnWMO;
|
||||
|
||||
ADTFile* GetMap(int x, int z);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,556 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "vmapexport.h"
|
||||
#include "wmo.h"
|
||||
#include "vec3d.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#undef min
|
||||
#undef max
|
||||
#include "mpq_libmpq04.h"
|
||||
|
||||
using namespace std;
|
||||
extern uint16 *LiqType;
|
||||
|
||||
WMORoot::WMORoot(std::string &filename)
|
||||
: filename(filename), col(0), nTextures(0), nGroups(0), nP(0), nLights(0),
|
||||
nModels(0), nDoodads(0), nDoodadSets(0), RootWMOID(0), liquidType(0)
|
||||
{
|
||||
memset(bbcorn1, 0, sizeof(bbcorn1));
|
||||
memset(bbcorn2, 0, sizeof(bbcorn2));
|
||||
}
|
||||
|
||||
bool WMORoot::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);
|
||||
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)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
WMOGroup::WMOGroup(const std::string &filename) :
|
||||
filename(filename), MOPY(0), MOVI(0), MoviEx(0), MOVT(0), MOBA(0), MobaEx(0),
|
||||
hlq(0), LiquEx(0), LiquBytes(0), groupName(0), descGroupName(0), mogpFlags(0),
|
||||
moprIdx(0), moprNItems(0), nBatchA(0), nBatchB(0), nBatchC(0), fogIdx(0),
|
||||
liquidType(0), groupWMOID(0), mopy_size(0), moba_size(0), LiquEx_size(0),
|
||||
nVertices(0), nTriangles(0), liquflags(0)
|
||||
{
|
||||
memset(bbcorn1, 0, sizeof(bbcorn1));
|
||||
memset(bbcorn2, 0, sizeof(bbcorn2));
|
||||
}
|
||||
|
||||
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 preciseVectorData)
|
||||
{
|
||||
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 (preciseVectorData)
|
||||
{
|
||||
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");
|
||||
// no need to exit?
|
||||
}
|
||||
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");
|
||||
// no need to exit?
|
||||
}
|
||||
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*static_cast<int>(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, static_cast<int>(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 ((liquidEntry - 1) & 3)
|
||||
{
|
||||
case 0:
|
||||
liquidEntry = ((mogpFlags & 0x80000) != 0) + 13;
|
||||
break;
|
||||
case 1:
|
||||
liquidEntry = 14;
|
||||
break;
|
||||
case 2:
|
||||
liquidEntry = 19;
|
||||
break;
|
||||
case 3:
|
||||
liquidEntry = 20;
|
||||
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;
|
||||
}
|
||||
|
||||
WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
|
||||
: currx(0), curry(0), wmo(NULL), doodadset(0), pos(), indx(0), id(0), d2(0), d3(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);
|
||||
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;
|
||||
int count = fread(&nVertices, sizeof (int), 1, input);
|
||||
fclose(input);
|
||||
|
||||
if (count != 1 || nVertices == 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=strlen(WmoInstName);
|
||||
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
|
||||
fwrite(WmoInstName, sizeof(char), nlen, pDirfile);
|
||||
|
||||
/* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n",
|
||||
MapName,
|
||||
WmoInstName,
|
||||
(float) x, (float) pos.y, (float) z,
|
||||
(float) rot.x, (float) rot.y, (float) rot.z,
|
||||
nVertices,
|
||||
realx1, realy1,
|
||||
realx2, realy2
|
||||
); */
|
||||
|
||||
// fclose(dirfile);
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef WMO_H
|
||||
#define WMO_H
|
||||
#define TILESIZE (533.33333f)
|
||||
#define CHUNKSIZE ((TILESIZE) / 16.0f)
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "vec3d.h"
|
||||
#include "loadlib/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
|
||||
|
||||
class WMOInstance;
|
||||
class WMOManager;
|
||||
class MPQFile;
|
||||
|
||||
/* for whatever reason a certain company just can't stick to one coordinate system... */
|
||||
static inline Vec3D fixCoords(const Vec3D &v){ return Vec3D(v.z, v.x, v.y); }
|
||||
|
||||
class WMORoot
|
||||
{
|
||||
private:
|
||||
std::string filename;
|
||||
public:
|
||||
unsigned int col;
|
||||
uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType;
|
||||
float bbcorn1[3];
|
||||
float bbcorn2[3];
|
||||
|
||||
WMORoot(std::string& filename);
|
||||
|
||||
bool open();
|
||||
bool ConvertToVMAPRootWmo(FILE* output);
|
||||
};
|
||||
|
||||
struct WMOLiquidHeader
|
||||
{
|
||||
int xverts, yverts, xtiles, ytiles;
|
||||
float pos_x;
|
||||
float pos_y;
|
||||
float pos_z;
|
||||
short type;
|
||||
};
|
||||
|
||||
struct WMOLiquidVert
|
||||
{
|
||||
uint16 unk1;
|
||||
uint16 unk2;
|
||||
float height;
|
||||
};
|
||||
|
||||
class WMOGroup
|
||||
{
|
||||
private:
|
||||
std::string filename;
|
||||
public:
|
||||
// MOGP
|
||||
|
||||
char* MOPY;
|
||||
uint16* MOVI;
|
||||
uint16* MoviEx;
|
||||
float* MOVT;
|
||||
uint16* MOBA;
|
||||
int* MobaEx;
|
||||
WMOLiquidHeader* hlq;
|
||||
WMOLiquidVert* LiquEx;
|
||||
char* LiquBytes;
|
||||
int groupName, descGroupName;
|
||||
int mogpFlags;
|
||||
float bbcorn1[3];
|
||||
float bbcorn2[3];
|
||||
uint16 moprIdx;
|
||||
uint16 moprNItems;
|
||||
uint16 nBatchA;
|
||||
uint16 nBatchB;
|
||||
uint32 nBatchC, fogIdx, liquidType, groupWMOID;
|
||||
|
||||
int mopy_size, moba_size;
|
||||
int LiquEx_size;
|
||||
unsigned int nVertices; // number when loaded
|
||||
int nTriangles; // number when loaded
|
||||
uint32 liquflags;
|
||||
|
||||
WMOGroup(std::string const& filename);
|
||||
~WMOGroup();
|
||||
|
||||
bool open();
|
||||
int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool preciseVectorData);
|
||||
};
|
||||
|
||||
class WMOInstance
|
||||
{
|
||||
static std::set<int> ids;
|
||||
public:
|
||||
std::string MapName;
|
||||
int currx;
|
||||
int curry;
|
||||
WMOGroup* wmo;
|
||||
int doodadset;
|
||||
Vec3D pos;
|
||||
Vec3D pos2, pos3, rot;
|
||||
uint32 indx, id, d2, d3;
|
||||
|
||||
WMOInstance(MPQFile&f , char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
|
||||
|
||||
static void reset();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
add_subdirectory(src)
|
||||
@@ -1,661 +0,0 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "AddonMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <list>
|
||||
#include <openssl/md5.h>
|
||||
|
||||
namespace AddonMgr
|
||||
{
|
||||
|
||||
// Anonymous namespace ensures file scope of all the stuff inside it, even
|
||||
// if you add something more to this namespace somewhere else.
|
||||
namespace
|
||||
{
|
||||
// List of saved addons (in DB).
|
||||
typedef std::list<SavedAddon> SavedAddonsList;
|
||||
|
||||
SavedAddonsList m_knownAddons;
|
||||
BannedAddonList m_bannedAddons;
|
||||
}
|
||||
|
||||
void LoadFromDB()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT name, crc FROM addons");
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 known addons. DB table `addons` is empty!");
|
||||
sLog->outString();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
std::string name = fields[0].GetString();
|
||||
uint32 crc = fields[1].GetUInt32();
|
||||
|
||||
m_knownAddons.push_back(SavedAddon(name, crc));
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u known addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
oldMSTime = getMSTime();
|
||||
result = CharacterDatabase.Query("SELECT id, name, version, UNIX_TIMESTAMP(timestamp) FROM banned_addons");
|
||||
if (result)
|
||||
{
|
||||
uint32 count = 0;
|
||||
uint32 offset = 102;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
BannedAddon addon;
|
||||
addon.Id = fields[0].GetUInt32() + offset;
|
||||
addon.Timestamp = uint32(fields[3].GetUInt64());
|
||||
|
||||
std::string name = fields[1].GetString();
|
||||
std::string version = fields[2].GetString();
|
||||
|
||||
MD5(reinterpret_cast<uint8 const*>(name.c_str()), name.length(), addon.NameMD5);
|
||||
MD5(reinterpret_cast<uint8 const*>(version.c_str()), version.length(), addon.VersionMD5);
|
||||
|
||||
m_bannedAddons.push_back(addon);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u banned addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
}
|
||||
|
||||
void SaveAddon(AddonInfo const& addon)
|
||||
{
|
||||
std::string name = addon.Name;
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ADDON);
|
||||
|
||||
stmt->setString(0, name);
|
||||
stmt->setUInt32(1, addon.CRC);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
m_knownAddons.push_back(SavedAddon(addon.Name, addon.CRC));
|
||||
}
|
||||
|
||||
SavedAddon const* GetAddonInfo(const std::string& name)
|
||||
{
|
||||
for (SavedAddonsList::const_iterator it = m_knownAddons.begin(); it != m_knownAddons.end(); ++it)
|
||||
{
|
||||
SavedAddon const& addon = (*it);
|
||||
if (addon.Name == name)
|
||||
return &addon;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BannedAddonList const* GetBannedAddons()
|
||||
{
|
||||
return &m_bannedAddons;
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _ADDONMGR_H
|
||||
#define _ADDONMGR_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
struct AddonInfo
|
||||
{
|
||||
AddonInfo(const std::string& name, uint8 enabled, uint32 crc, uint8 state, bool crcOrPubKey)
|
||||
: Name(name), Enabled(enabled), CRC(crc), State(state), UsePublicKeyOrCRC(crcOrPubKey) {}
|
||||
|
||||
std::string Name;
|
||||
uint8 Enabled;
|
||||
uint32 CRC;
|
||||
uint8 State;
|
||||
bool UsePublicKeyOrCRC;
|
||||
};
|
||||
|
||||
struct SavedAddon
|
||||
{
|
||||
SavedAddon(const std::string& name, uint32 crc) : Name(name)
|
||||
{
|
||||
CRC = crc;
|
||||
}
|
||||
|
||||
std::string Name;
|
||||
uint32 CRC;
|
||||
};
|
||||
|
||||
struct BannedAddon
|
||||
{
|
||||
uint32 Id;
|
||||
uint8 NameMD5[16];
|
||||
uint8 VersionMD5[16];
|
||||
uint32 Timestamp;
|
||||
};
|
||||
|
||||
#define STANDARD_ADDON_CRC 0x4c1c776d
|
||||
|
||||
namespace AddonMgr
|
||||
{
|
||||
void LoadFromDB();
|
||||
void SaveAddon(AddonInfo const& addon);
|
||||
SavedAddon const* GetAddonInfo(const std::string& name);
|
||||
|
||||
typedef std::list<BannedAddon> BannedAddonList;
|
||||
BannedAddonList const* GetBannedAddons();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
if( USE_COREPCH )
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE sources_Addons Addons/*.cpp Addons/*.h)
|
||||
file(GLOB sources_localdir *.cpp *.h)
|
||||
|
||||
# Build gamefw sourcelist
|
||||
#
|
||||
|
||||
if (USE_COREPCH)
|
||||
set(gamefw_STAT_PCH_HDR PrecompiledHeaders/gamefwPCH.h)
|
||||
set(gamefw_STAT_PCH_SRC PrecompiledHeaders/gamefwPCH.cpp)
|
||||
endif()
|
||||
|
||||
set(gamefw_STAT_SRCS
|
||||
${gamefw_STAT_SRCS}
|
||||
${sources_Addons}
|
||||
${sources_localdir}
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Detour
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/recastnavigation/Recast
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/g3dlite/include
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/SFMT
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/deps/zlib
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Management
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Models
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/lib-collision/src/Maps
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Configuration
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Cryptography
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Cryptography/Authentication
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Database
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/DataStores
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Debugging
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Dynamic/LinkedReference
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Dynamic
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Logging
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Packets
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Threading
|
||||
${CMAKE_SOURCE_DIR}/modules/worldengine/nucleus/src/Utilities
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Addons
|
||||
${ACE_INCLUDE_DIR}
|
||||
${MYSQL_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_library(gamefw STATIC
|
||||
${gamefw_STAT_SRCS}
|
||||
${gamefw_STAT_PCH_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(gamefw
|
||||
${ACE_LIBRARY}
|
||||
)
|
||||
|
||||
# Generate precompiled header
|
||||
if (USE_COREPCH)
|
||||
add_cxx_pch(gamefw ${gamefw_STAT_PCH_HDR} ${gamefw_STAT_PCH_SRC})
|
||||
endif ()
|
||||
@@ -1 +0,0 @@
|
||||
#include "gamefwPCH.h"
|
||||
@@ -1,3 +0,0 @@
|
||||
//add here most rarely modified headers to speed up debug build compilation
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# enable/disable GDB execution
|
||||
export GDB_ENABLED=0
|
||||
|
||||
# [optional] gdb file
|
||||
# default: gdb.txt
|
||||
export GDB=""
|
||||
|
||||
# directory where binary are stored
|
||||
export BINPATH=""
|
||||
|
||||
# Put here the pid you configured on your worldserver.conf file
|
||||
# needed when GDB_ENABLED=1
|
||||
export SERVERPID=""
|
||||
|
||||
# path to configuration file (including the file name)
|
||||
# ex: /home/user/azerothcore/etc/worldserver.conf
|
||||
export CONFIG=""
|
||||
|
||||
# path of log files
|
||||
# needed by restarter to store its logs
|
||||
export LOGS_PATH="";
|
||||
|
||||
# exec name
|
||||
# ex: worldserver
|
||||
export SERVERBIN=""
|
||||
|
||||
# prefix name for log files
|
||||
# to avoid collision with other restarters
|
||||
export LOG_PREFIX_NAME=""
|
||||
|
||||
# [optional] name of screen service
|
||||
# if no specified, screen util won't be used
|
||||
export SCREEN_NAME=""
|
||||
|
||||
# [optional] overwrite default screen options: -A -m -d -S
|
||||
# WARNING: if you are running it under a systemd service
|
||||
# please do not remove -m -d arguments from screen if are you using it,
|
||||
# or keep WITH_CONSOLE=0 .
|
||||
# otherwise the journald-logging system will take 100% of CPU slowing
|
||||
# down the whole machine. It's because a systemd service should have
|
||||
# low console output.
|
||||
export SCREEN_OPTIONS=""
|
||||
|
||||
# enable/disable it to show the output
|
||||
# within console, if disable the output will be redirect to
|
||||
# logging files
|
||||
#
|
||||
export WITH_CONSOLE=0
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
|
||||
source $PATH_RUNENGINE/run-engine
|
||||
|
||||
# you must create your conf
|
||||
# copying conf.sh.dist
|
||||
# and renaming as below
|
||||
source ./conf-auth.sh
|
||||
|
||||
restarter
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
|
||||
source $PATH_RUNENGINE/run-engine
|
||||
|
||||
# you must create your conf
|
||||
# copying conf.sh.dist
|
||||
# and renaming as below
|
||||
source ./conf-world.sh
|
||||
|
||||
restarter
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
|
||||
source $PATH_RUNENGINE/run-engine
|
||||
|
||||
# you must create your conf
|
||||
# copying conf.sh.dist
|
||||
# and renaming as below
|
||||
source ./conf-auth.sh
|
||||
|
||||
starter
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PATH_RUNENGINE="./"
|
||||
|
||||
source $PATH_RUNENGINE/run-engine
|
||||
|
||||
# you must create your conf
|
||||
# copying conf.sh.dist
|
||||
# and renaming as below
|
||||
source ./conf-world.sh
|
||||
|
||||
starter
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user