27#include <boost/filesystem/directory.hpp>
28#include <boost/filesystem/operations.hpp>
29#include <boost/filesystem/path.hpp>
33#include <unordered_map>
39#include <boost/filesystem.hpp>
54#define MAX_PATH_LENGTH 128
81static constexpr std::array<std::string_view, 12>
MpqLocaleNames = {
"enGB",
"enUS",
"deDE",
"esES",
"frFR",
"koKR",
"zhCN",
"zhTW",
"enCN",
"enTW",
"esMX",
"ruRU" };
89 if (!fs::create_directory(path))
90 throw std::runtime_error(
"Unable to create directory" + path.string());
97 "%s -[var] [value]\n"\
98 "-i set input path (max %d characters)\n"\
99 "-o set output path (max %d characters)\n"\
100 "-e extract only MAP(1)/DBC(2)/Camera(4) - standard: all(7)\n"\
101 "-f height stored as int (less map size but lost some accuracy) 1 by default\n"\
108 for(
int c = 1; c < argc; ++c)
172 printf(
"Fatal error: Not found %s file!\n", filename.c_str());
179 size_t pos = text.find(
"version=\"");
180 size_t pos1 = pos + strlen(
"version=\"");
181 size_t pos2 = text.find(
'"',pos1);
182 if (pos == text.npos || pos2 == text.npos || pos1 >= pos2)
184 printf(
"Fatal error: Invalid %s file format!\n", filename.c_str());
188 std::string build_str = text.substr(pos1,pos2-pos1);
190 int build = atoi(build_str.c_str());
193 printf(
"Fatal error: Invalid %s file format!\n", filename.c_str());
202 printf(
"Read Map.dbc file... ");
203 DBCFile dbc(
"DBFilesClient\\Map.dbc");
207 printf(
"Fatal error: Invalid Map.dbc file format!\n");
218 size_t max_map_name_length =
sizeof(
map_ids[x].name);
219 if (strlen(map_name) >= max_map_name_length)
221 printf(
"Fatal error: Map name too long!\n");
225 strncpy(
map_ids[x].name, map_name, max_map_name_length);
226 map_ids[x].name[max_map_name_length - 1] =
'\0';
234 printf(
"Read LiquidType.dbc file...");
235 DBCFile dbc(
"DBFilesClient\\LiquidType.dbc");
238 printf(
"Fatal error: Invalid LiquidType.dbc file format!\n");
277#define MAP_AREA_NO_AREA 0x0001
286#define MAP_HEIGHT_NO_HEIGHT 0x0001
287#define MAP_HEIGHT_AS_INT16 0x0002
288#define MAP_HEIGHT_AS_INT8 0x0004
289#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008
299#define MAP_LIQUID_TYPE_NO_WATER 0x00
300#define MAP_LIQUID_TYPE_WATER 0x01
301#define MAP_LIQUID_TYPE_OCEAN 0x02
302#define MAP_LIQUID_TYPE_MAGMA 0x04
303#define MAP_LIQUID_TYPE_SLIME 0x08
305#define MAP_LIQUID_TYPE_DARK_WATER 0x10
307#define MAP_LIQUID_NO_TYPE 0x0001
308#define MAP_LIQUID_NO_HEIGHT 0x0002
325 return 255 / maxDiff;
330 return 65535 / maxDiff;
351bool ConvertADT(std::string
const& inputPath, std::string
const& outputPath,
int ,
int ,
uint32 build)
361 printf(
"Can't find cells in '%s'\n", inputPath.c_str());
385 bool fullAreaData =
false;
404 areaHeader.
flags = 0;
492 float maxHeight = -20000;
493 float minHeight = 20000;
499 if (maxHeight < h) maxHeight = h;
500 if (minHeight > h) minHeight = h;
508 if (maxHeight < h) maxHeight = h;
509 if (minHeight > h) minHeight = h;
530 bool hasFlightBox =
false;
543 heightHeader.
flags = 0;
547 if (maxHeight == minHeight)
567 float diff = maxHeight - minHeight;
625 if (liquid->
flags[y][x] != 0x0F)
628 if (liquid->
flags[y][x] & (1<<7))
653 fprintf(stderr,
"Wrong liquid detect in MCLQ chunk");
706 printf(
"\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->
LiquidType, inputPath.c_str(), i, j);
711 printf(
"Wrong liquid detect in MH2O chunk");
732 bool fullType =
false;
749 if (firstLiquidFlag == 0 && !fullType)
757 int minX = 255, minY = 255;
758 int maxX = 0, maxY = 0;
767 if (minX > x) minX = x;
768 if (maxX < x) maxX = x;
769 if (minY > y) minY = y;
770 if (maxY < y) maxY = y;
772 if (maxHeight < h) maxHeight = h;
773 if (minHeight > h) minHeight = h;
785 liquidHeader.
flags = 0;
789 liquidHeader.
width = maxX - minX + 1 + 1;
790 liquidHeader.
height = maxY - minY + 1 + 1;
793 if (maxHeight == minHeight)
815 bool hasHoles =
false;
825 if (!hasHoles && cell->
holes != 0)
847 std::ofstream outFile(outputPath, std::ofstream::out | std::ofstream::binary);
850 printf(
"Can't create the output file '%s'\n", outputPath.c_str());
854 outFile.write(
reinterpret_cast<char const*
>(&map),
sizeof(map));
856 outFile.write(
reinterpret_cast<char const*
>(&areaHeader),
sizeof(areaHeader));
861 outFile.write(
reinterpret_cast<char const*
>(&heightHeader),
sizeof(heightHeader));
876 outFile.write(
reinterpret_cast<char const*
>(
V9),
sizeof(
V9));
877 outFile.write(
reinterpret_cast<char const*
>(
V8),
sizeof(
V8));
890 outFile.write(
reinterpret_cast<char const*
>(&liquidHeader),
sizeof(liquidHeader));
900 for (
int y = 0; y < liquidHeader.
height; y++)
907 outFile.write(
reinterpret_cast<char const*
>(
holes), map.
holesSize);
915 std::string mpqFileName;
916 std::string outputFileName;
917 std::string mpqMapName;
919 printf(
"Extracting maps...\n");
929 printf(
"Convert map files\n");
937 if (!wdt.
loadFile(mpqMapName,
false))
952 ConvertADT(mpqFileName, outputFileName, y, x, build);
955 printf(
"Processing........................%d%%\r", (100 * (y+1)) /
WDT_MAP_SIZE);
961bool ExtractFile(
char const* mpq_name, std::string
const& filename )
963 FILE *output = fopen(filename.c_str(),
"wb");
966 printf(
"Can't create the output file '%s'\n", filename.c_str());
979 printf(
"Extracting dbc files...\n");
981 std::set<std::string> dbcfiles;
986 std::vector<std::string> files;
987 i->GetFileListTo(files);
988 for (std::vector<std::string>::iterator iter = files.begin(); iter != files.end(); ++iter)
989 if (iter->rfind(
".dbc") == iter->length() - strlen(
".dbc"))
990 dbcfiles.insert(*iter);
1006 std::string filename = path + mpq_name;
1013 for (std::set<std::string>::iterator iter = dbcfiles.begin(); iter != dbcfiles.end(); ++iter)
1015 std::string filename = path;
1016 filename += (iter->c_str() + strlen(
"DBFilesClient\\"));
1018 if (boost::filesystem::exists(filename))
1024 printf(
"Extracted %u DBC files\n\n", count);
1029 printf(
"Extracting camera files...\n");
1030 DBCFile camdbc(
"DBFilesClient\\CinematicCamera.dbc");
1034 printf(
"Unable to open CinematicCamera.dbc. Camera extract aborted.\n");
1039 std::vector<std::string> camerafiles;
1042 for (
size_t i = 0; i < cam_count; ++i)
1045 size_t loc = camFile.find(
".mdx");
1046 if (loc != std::string::npos)
1047 camFile.replace(loc, 4,
".m2");
1048 camerafiles.push_back(std::string(camFile));
1052 path +=
"/Cameras/";
1063 for (std::string thisFile : camerafiles)
1065 std::string filename = path;
1066 filename += (thisFile.c_str() + strlen(
"Cameras\\"));
1068 if (boost::filesystem::exists(filename))
1074 printf(
"Extracted %u camera files\n", count);
1083 Trinity::Banner::Show(
"Map & DBC Extractor", [](
char const* text) { printf(
"%s\n", text); },
nullptr);
1087 int FirstLocale = -1;
1102 printf(
"Detected client build: %u\n\n", build);
1111 printf(
"Detected client build: %u\n\n", build);
1123 printf(
"No locales detected\n");
1156#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
#define STRING_VIEW_FMT_ARG(str)
float selectUInt8StepStore(float maxDiff)
float CONF_float_to_int8_limit
uint16 uint16_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
bool ConvertADT(std::string const &inputPath, std::string const &outputPath, int, int, uint32 build)
uint16 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS
bool CONF_allow_height_limit
std::vector< map_id > map_ids
#define MAP_LIQUID_TYPE_MAGMA
#define MAP_HEIGHT_AS_INT8
char input_path[MAX_PATH_LENGTH]
void HandleArgs(int argc, char *arg[])
bool CONF_allow_float_to_int
bool ExtractFile(char const *mpq_name, std::string const &filename)
static char const * MAP_AREA_MAGIC
void CreateDir(boost::filesystem::path const &path)
#define MAP_LIQUID_NO_TYPE
std::unordered_map< uint32, LiquidTypeEntry > LiquidTypes
#define MAP_LIQUID_NO_HEIGHT
uint16 uint16_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
#define MAP_LIQUID_TYPE_WATER
static char const * MAP_MAGIC
#define MAP_LIQUID_TYPE_DARK_WATER
float CONF_flat_liquid_delta_limit
#define MAP_LIQUID_TYPE_OCEAN
uint16 liquid_entry[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
char output_path[MAX_PATH_LENGTH]
static uint32 const MAP_VERSION_MAGIC
int16 flight_box_min[3][3]
float selectUInt16StepStore(float maxDiff)
uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
static char const * MAP_LIQUID_MAGIC
int16 flight_box_max[3][3]
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
#define MAP_LIQUID_TYPE_SLIME
#define MAP_HEIGHT_NO_HEIGHT
void ExtractMapsFromMpq(uint32 build)
void ExtractDBCFiles(int locale, bool basicLocale)
uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
uint8 uint8_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
int main(int argc, char *arg[])
static constexpr std::array< std::string_view, 12 > MpqLocaleNames
uint32 ReadBuild(int locale)
void ReadLiquidTypeTableDBC()
void Usage(char const *prg)
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
static char const * MAP_HEIGHT_MAGIC
float CONF_float_to_int16_limit
#define MAP_HEIGHT_AS_INT16
uint8 uint8_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]
void ExtractCameraFiles(int locale, bool basicLocale)
float CONF_flat_height_delta_limit
#define ADT_CELLS_PER_GRID
char const * getString(size_t field) const
unsigned int getUInt(size_t field) const
Record getRecord(size_t id)
size_t getRecordCount() const
Trivial.
bool loadFile(std::string const &fileName, bool log=true)
adt_MCNK * getMCNK(int x, int y)
struct adt_MCLQ::liquid_data liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1]
uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE]
float height_map[(ADT_CELL_SIZE+1) *(ADT_CELL_SIZE+1)+ADT_CELL_SIZE *ADT_CELL_SIZE]
adt_liquid_attributes GetLiquidAttributes(int32 x, int32 y) const
adt_liquid_instance const * GetLiquidInstance(int32 x, int32 y) const
float GetLiquidHeight(adt_liquid_instance const *h, int32 pos) const
uint64 GetLiquidExistsBitmap(adt_liquid_instance const *h) const
struct wdt_MAIN::adtData adt_list[64][64]
bool OpenArchives(std::string_view inputPath, std::string_view localeName)
TC_COMMON_API void Show(char const *applicationName, void(*log)(char const *text), void(*logExtraInfo)())
TC_COMMON_API void Init()
TC_COMMON_API void VerifyOsVersion()
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.