Directory Structure [step 1]: moving files

working on #672

NOTE: This commit can't be compiled!!
This commit is contained in:
Yehonal
2017-10-12 20:00:52 +02:00
parent 4df28fd29c
commit f06f32849f
2508 changed files with 0 additions and 1325 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(&params, 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(&params, 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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(&params, 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(&params);
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;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(&params, 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(&params, &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(&params, 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(&params, &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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +0,0 @@
Experimental mesh extractor.
Original work in C# by stschake
Thanks to:
Subv
~
For helping in the porting to C++

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(&params, 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(&params, &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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
); */
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +0,0 @@
add_subdirectory(src)

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +0,0 @@
#include "gamefwPCH.h"

View File

@@ -1,3 +0,0 @@
//add here most rarely modified headers to speed up debug build compilation

View File

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

View File

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

View File

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

View File

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

View File

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