Legends-of-Azeroth-Pandaria-5.4.8

Форк
0
1520 строк · 45.2 Кб
1
/*
2
 * Copyright (C) 2011-2016 Project SkyFire <http://www.projectskyfire.org/>
3
 * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
4
 * Copyright (C) 2005-2016 MaNGOS <http://getmangos.com/>
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 3 of the License, or (at your
9
 * option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
 * more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * with this program. If not, see <http://www.gnu.org/licenses/>.
18
 */
19

20
#define _CRT_SECURE_NO_DEPRECATE
21

22
#include <stdio.h>
23
#include <deque>
24
#include <list>
25
#include <cstdlib>
26
#include <vector>
27
#include <algorithm>
28
#include <cctype>
29
#include <string>
30

31
#ifdef _WIN32
32
#include "direct.h"
33
#else
34
#include <sys/stat.h>
35
#include <unistd.h>
36
#define ERROR_PATH_NOT_FOUND ERROR_FILE_NOT_FOUND
37
#endif
38

39
#include "StormLib.h"
40
#include "dbcfile.h"
41

42
#include "adt.h"
43
#include "wdt.h"
44
#include <fcntl.h>
45
#include <filesystem>
46

47
#if defined( __GNUC__ )
48
    #define _open   open
49
    #define _close close
50
    #ifndef O_BINARY
51
        #define O_BINARY 0
52
    #endif
53
#else
54
    #include <io.h>
55
#endif
56

57
#ifdef O_LARGEFILE
58
    #define OPEN_FLAGS (O_RDONLY | O_BINARY | O_LARGEFILE)
59
#else
60
    #define OPEN_FLAGS (O_RDONLY | O_BINARY)
61
#endif
62

63
HANDLE WorldMpq = NULL;
64
HANDLE LocaleMpq = NULL;
65

66
typedef struct
67
{
68
    char name[64];
69
    uint32 id;
70
} map_id;
71

72
map_id *map_ids;
73
uint16 *LiqType;
74
char output_path[128] = ".";
75
char input_path[128] = ".";
76

77
// **************************************************
78
// Extractor options
79
// **************************************************
80
enum Extract
81
{
82
    EXTRACT_MAP    = 1,
83
    EXTRACT_DBC    = 2,
84
    EXTRACT_CAMERA = 4
85
};
86

87
// Select data for extract
88
int   CONF_extract = EXTRACT_MAP | EXTRACT_DBC | EXTRACT_CAMERA;
89

90
// This option allow limit minimum height to some value (Allow save some memory)
91
bool  CONF_allow_height_limit = true;
92
float CONF_use_minHeight = -500.0f;
93

94
// This option allow use float to int conversion
95
bool  CONF_allow_float_to_int   = false;
96
float CONF_float_to_int8_limit  = 2.0f;      // Max accuracy = val/256
97
float CONF_float_to_int16_limit = 2048.0f;   // Max accuracy = val/65536
98
float CONF_flat_height_delta_limit = 0.005f; // If max - min less this value - surface is flat
99
float CONF_flat_liquid_delta_limit = 0.001f; // If max - min less this value - liquid surface is flat
100

101
uint32 CONF_TargetBuild = 18273;              // 5.4.8 18273 -- current build is 18414, but Blizz didnt rename the MPQ files
102

103
// List MPQ for extract maps from
104
char const* CONF_mpq_list[] =
105
{
106
    "world.MPQ",
107
    "model.MPQ",
108
    "misc.MPQ",
109
    "expansion1.MPQ",
110
    "expansion2.MPQ",
111
    "expansion3.MPQ",
112
    "expansion4.MPQ"
113
};
114

115
uint32 const Builds[] = {16016, 16048, 16057, 16309, 16357, 16516, 16650, 16844, 16965, 17116, 17266, 17325, 17345, 17538, 17645, 17688, 17898, 18273};
116
//#define LAST_DBC_IN_DATA_BUILD 13623    // after this build mpqs with dbc are back to locale folder
117
#define NEW_BASE_SET_BUILD  15211
118

119
char const* Locales[] =
120
{
121
    "enGB", "enUS",
122
    "deDE", "esES",
123
    "frFR", "koKR",
124
    "zhCN", "zhTW",
125
    "enCN", "enTW",
126
    "esMX", "ruRU",
127
    "ptBR", "ptPT",
128
    "itIT",
129
};
130

131
TCHAR const* LocalesT[] =
132
{
133
    _T("enGB"), _T("enUS"),
134
    _T("deDE"), _T("esES"),
135
    _T("frFR"), _T("koKR"),
136
    _T("zhCN"), _T("zhTW"),
137
    _T("enCN"), _T("enTW"),
138
    _T("esMX"), _T("ruRU"),
139
    _T("ptBR"), _T("ptPT"),
140
    _T("itIT"),
141
};
142

143
#define LOCALES_COUNT 15
144

145
void CreateDir(std::filesystem::path const& path)
146
{
147
    namespace fs = std::filesystem;
148
    if (fs::exists(path))
149
        return;
150

151
    if (!fs::create_directory(path))
152
        throw std::runtime_error("Unable to create directory" + path.string());
153
}
154

155
bool FileExists(TCHAR const* fileName)
156
{
157
    int fp = _open(fileName, OPEN_FLAGS);
158
    if(fp != -1)
159
    {
160
        _close(fp);
161
        return true;
162
    }
163

164
    return false;
165
}
166

167
void Usage(char const* prg)
168
{
169
    printf(
170
        "Usage:\n"\
171
        "%s -[var] [value]\n"\
172
        "-i set input path\n"\
173
        "-o set output path\n"\
174
        "-e extract only MAP(1)/DBC(2) - standard: both(3)\n"\
175
        "-f height stored as int (less map size but lost some accuracy) 1 by default\n"\
176
        "-b target build (default %u)\n"\
177
        "Example: %s -f 0 -i \"c:\\games\\game\"", prg, CONF_TargetBuild, prg);
178
    exit(1);
179
}
180

181
void HandleArgs(int argc, char* arg[])
182
{
183
    for (int c = 1; c < argc; ++c)
184
    {
185
        // i - input path
186
        // o - output path
187
        // e - extract only MAP(1)/DBC(2) - standard both(3)
188
        // f - use float to int conversion
189
        // h - limit minimum height
190
        // b - target client build
191
        if (arg[c][0] != '-')
192
            Usage(arg[0]);
193

194
        switch (arg[c][1])
195
        {
196
            case 'i':
197
                if (c + 1 < argc)                            // all ok
198
                    strcpy(input_path, arg[c++ + 1]);
199
                else
200
                    Usage(arg[0]);
201
                break;
202
            case 'o':
203
                if (c + 1 < argc)                            // all ok
204
                    strcpy(output_path, arg[c++ + 1]);
205
                else
206
                    Usage(arg[0]);
207
                break;
208
            case 'f':
209
                if (c + 1 < argc)                            // all ok
210
                    CONF_allow_float_to_int = atoi(arg[c++ + 1])!=0;
211
                else
212
                    Usage(arg[0]);
213
                break;
214
            case 'e':
215
                if (c + 1 < argc)                            // all ok
216
                {
217
                    CONF_extract = atoi(arg[c++ + 1]);
218
                    if (!(CONF_extract > 0 && CONF_extract < 4))
219
                        Usage(arg[0]);
220
                }
221
                else
222
                    Usage(arg[0]);
223
                break;
224
            case 'b':
225
                if (c + 1 < argc)                            // all ok
226
                    CONF_TargetBuild = atoi(arg[c++ + 1]);
227
                else
228
                    Usage(arg[0]);
229
                break;
230
            default:
231
                break;
232
        }
233
    }
234
}
235

236
uint32 ReadBuild(int locale)
237
{
238
    // include build info file also
239
    std::string filename  = std::string("component.wow-") + Locales[locale] + ".txt";
240
    //printf("Read %s file... ", filename.c_str());
241

242
    HANDLE dbcFile;
243
    if (!SFileOpenFileEx(LocaleMpq, filename.c_str(), SFILE_OPEN_PATCHED_FILE, &dbcFile))
244
    {
245
        printf("Fatal error: Not found %s file!\n", filename.c_str());
246
        exit(1);
247
    }
248

249
    char buff[512];
250
    DWORD readBytes = 0;
251
    SFileReadFile(dbcFile, buff, 512, &readBytes, NULL);
252
    if (!readBytes)
253
    {
254
        printf("Fatal error: Not found %s file!\n", filename.c_str());
255
        exit(1);
256
    }
257

258
    std::string text = buff;
259
    SFileCloseFile(dbcFile);
260

261
    size_t pos = text.find("version=\"");
262
    size_t pos1 = pos + strlen("version=\"");
263
    size_t pos2 = text.find("\"", pos1);
264
    if (pos == text.npos || pos2 == text.npos || pos1 >= pos2)
265
    {
266
        printf("Fatal error: Invalid  %s file format!\n", filename.c_str());
267
        exit(1);
268
    }
269

270
    std::string build_str = text.substr(pos1,pos2-pos1);
271

272
    int build = atoi(build_str.c_str());
273
    if (build <= 0)
274
    {
275
        printf("Fatal error: Invalid  %s file format!\n", filename.c_str());
276
        exit(1);
277
    }
278

279
    return build;
280
}
281

282
uint32 ReadMapDBC()
283
{
284
    printf("Read Map.dbc file... ");
285

286
    HANDLE dbcFile;
287
    if (!SFileOpenFileEx(LocaleMpq, "DBFilesClient\\Map.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile))
288
    {
289
        printf("Fatal error: Cannot find Map.dbc in archive!\n");
290
        exit(1);
291
    }
292

293
    DBCFile dbc(dbcFile);
294
    if (!dbc.open())
295
    {
296
        printf("Fatal error: Invalid Map.dbc file format!\n");
297
        exit(1);
298
    }
299

300
    size_t map_count = dbc.getRecordCount();
301
    map_ids = new map_id[map_count];
302
    for(uint32 x = 0; x < map_count; ++x)
303
    {
304
        map_ids[x].id = dbc.getRecord(x).getUInt(0);
305
        strcpy(map_ids[x].name, dbc.getRecord(x).getString(1));
306
    }
307

308
    SFileCloseFile(dbcFile);
309
    printf("Done! (%u maps loaded)\n", uint32(map_count));
310
    return map_count;
311
}
312

313
void ReadLiquidTypeTableDBC()
314
{
315
    printf("Read LiquidType.dbc file...");
316

317
    HANDLE dbcFile;
318
    if (!SFileOpenFileEx(LocaleMpq, "DBFilesClient\\LiquidType.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile))
319
    {
320
        printf("Fatal error: Cannot find LiquidType.dbc in archive!\n");
321
        exit(1);
322
    }
323

324
    DBCFile dbc(dbcFile);
325
    if (!dbc.open())
326
    {
327
        printf("Fatal error: Invalid LiquidType.dbc file format!\n");
328
        exit(1);
329
    }
330

331
    size_t LiqType_count = dbc.getRecordCount();
332
    size_t LiqType_maxid = dbc.getMaxId();
333
    LiqType = new uint16[LiqType_maxid + 1];
334
    memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16));
335

336
    for (uint32 x = 0; x < LiqType_count; ++x)
337
        LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
338

339
    SFileCloseFile(dbcFile);
340
    printf("Done! (%zu LiqTypes loaded)\n", LiqType_count);
341
}
342

343
//
344
// Adt file convertor function and data
345
//
346

347
// Map file format data
348
static char const* MAP_MAGIC         = "MAPS";
349
static uint32 const MAP_VERSION_MAGIC = 10;
350
static char const* MAP_AREA_MAGIC    = "AREA";
351
static char const* MAP_HEIGHT_MAGIC  = "MHGT";
352
static char const* MAP_LIQUID_MAGIC  = "MLIQ";
353

354
struct map_fileheader
355
{
356
    uint32 mapMagic;
357
    uint32 versionMagic;
358
    uint32 buildMagic;
359
    uint32 areaMapOffset;
360
    uint32 areaMapSize;
361
    uint32 heightMapOffset;
362
    uint32 heightMapSize;
363
    uint32 liquidMapOffset;
364
    uint32 liquidMapSize;
365
    uint32 holesOffset;
366
    uint32 holesSize;
367
};
368

369
#define MAP_AREA_NO_AREA      0x0001
370

371
struct map_areaHeader
372
{
373
    uint32 fourcc;
374
    uint16 flags;
375
    uint16 gridArea;
376
};
377

378
#define MAP_HEIGHT_NO_HEIGHT            0x0001
379
#define MAP_HEIGHT_AS_INT16             0x0002
380
#define MAP_HEIGHT_AS_INT8              0x0004
381
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS    0x0008
382

383
struct map_heightHeader
384
{
385
    uint32 fourcc;
386
    uint32 flags;
387
    float  gridHeight;
388
    float  gridMaxHeight;
389
};
390

391
#define MAP_LIQUID_TYPE_NO_WATER    0x00
392
#define MAP_LIQUID_TYPE_WATER       0x01
393
#define MAP_LIQUID_TYPE_OCEAN       0x02
394
#define MAP_LIQUID_TYPE_MAGMA       0x04
395
#define MAP_LIQUID_TYPE_SLIME       0x08
396

397
#define MAP_LIQUID_TYPE_DARK_WATER  0x10
398
#define MAP_LIQUID_TYPE_WMO_WATER   0x20
399

400

401
#define MAP_LIQUID_NO_TYPE    0x0001
402
#define MAP_LIQUID_NO_HEIGHT  0x0002
403

404
struct map_liquidHeader
405
{
406
    uint32 fourcc;
407
    uint16 flags;
408
    uint16 liquidType;
409
    uint8  offsetX;
410
    uint8  offsetY;
411
    uint8  width;
412
    uint8  height;
413
    float  liquidLevel;
414
};
415

416
float selectUInt8StepStore(float maxDiff)
417
{
418
    return 255 / maxDiff;
419
}
420

421
float selectUInt16StepStore(float maxDiff)
422
{
423
    return 65535 / maxDiff;
424
}
425
// Temporary grid data store
426
uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
427

428
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE];
429
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
430
uint16 uint16_V8[ADT_GRID_SIZE][ADT_GRID_SIZE];
431
uint16 uint16_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
432
uint8  uint8_V8[ADT_GRID_SIZE][ADT_GRID_SIZE];
433
uint8  uint8_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
434

435
uint16 liquid_entry[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
436
uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
437
bool  liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE];
438
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1];
439

440
int16 flight_box_max[3][3];
441
int16 flight_box_min[3][3];
442

443
bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, uint32 build)
444
{
445
    ADT_file adt;
446

447
    if (!adt.loadFile(WorldMpq, filename))
448
        return false;
449

450
    memset(liquid_show, 0, sizeof(liquid_show));
451
    memset(liquid_flags, 0, sizeof(liquid_flags));
452
    memset(liquid_entry, 0, sizeof(liquid_entry));
453

454
    // Prepare map header
455
    map_fileheader map;
456
    map.mapMagic = *reinterpret_cast<uint32 const*>(MAP_MAGIC);
457
    map.versionMagic = MAP_VERSION_MAGIC;
458
    map.buildMagic = build;
459

460
    // Get area flags data
461
    for (int i = 0; i < ADT_CELLS_PER_GRID; ++i)
462
        for (int j = 0; j < ADT_CELLS_PER_GRID; ++j)
463
            area_ids[i][j] = adt.cells[i][j]->areaid;
464

465
    //============================================
466
    // Try pack area data
467
    //============================================
468
    bool fullAreaData = false;
469
    uint32 areaId = area_ids[0][0];
470
    for (int y = 0; y < ADT_CELLS_PER_GRID; y++)
471
    {
472
        for (int x = 0; x < ADT_CELLS_PER_GRID; x++)
473
        {
474
            if (area_ids[y][x] != areaId)
475
            {
476
                fullAreaData = true;
477
                break;
478
            }
479
        }
480
    }
481

482
    map.areaMapOffset = sizeof(map);
483
    map.areaMapSize   = sizeof(map_areaHeader);
484

485
    map_areaHeader areaHeader;
486
    areaHeader.fourcc = *(uint32 const*)MAP_AREA_MAGIC;
487
    areaHeader.flags = 0;
488
    if (fullAreaData)
489
    {
490
        areaHeader.gridArea = 0;
491
        map.areaMapSize += sizeof(area_ids);
492
    }
493
    else
494
    {
495
        areaHeader.flags |= MAP_AREA_NO_AREA;
496
        areaHeader.gridArea = static_cast<uint16>(areaId);
497
    }
498

499
    //
500
    // Get Height map from grid
501
    //
502
    for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
503
    {
504
        for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
505
        {
506
            adt_MCNK * cell = adt.cells[i][j];
507
            if (!cell)
508
                continue;
509
            // Height values for triangles stored in order:
510
            // 1     2     3     4     5     6     7     8     9
511
            //    10    11    12    13    14    15    16    17
512
            // 18    19    20    21    22    23    24    25    26
513
            //    27    28    29    30    31    32    33    34
514
            // . . . . . . . .
515
            // For better get height values merge it to V9 and V8 map
516
            // V9 height map:
517
            // 1     2     3     4     5     6     7     8     9
518
            // 18    19    20    21    22    23    24    25    26
519
            // . . . . . . . .
520
            // V8 height map:
521
            //    10    11    12    13    14    15    16    17
522
            //    27    28    29    30    31    32    33    34
523
            // . . . . . . . .
524

525
            // Set map height as grid height
526
            for (int y = 0; y <= ADT_CELL_SIZE; y++)
527
            {
528
                int cy = i * ADT_CELL_SIZE + y;
529
                for (int x = 0; x <= ADT_CELL_SIZE; x++)
530
                {
531
                    int cx = j * ADT_CELL_SIZE + x;
532
                    V9[cy][cx] = cell->ypos;
533
                }
534
            }
535
            for (int y = 0; y < ADT_CELL_SIZE; y++)
536
            {
537
                int cy = i * ADT_CELL_SIZE + y;
538
                for (int x = 0; x < ADT_CELL_SIZE; x++)
539
                {
540
                    int cx = j * ADT_CELL_SIZE + x;
541
                    V8[cy][cx]=cell->ypos;
542
                }
543
            }
544

545
            // Get custom height
546
            adt_MCVT *v = adt.cellsMcvt[i][j];
547
            if (!v)
548
                continue;
549

550
            // get V9 height map
551
            for (int y = 0; y <= ADT_CELL_SIZE; y++)
552
            {
553
                int cy = i * ADT_CELL_SIZE + y;
554
                for (int x = 0; x <= ADT_CELL_SIZE; x++)
555
                {
556
                    int cx = j * ADT_CELL_SIZE + x;
557
                    V9[cy][cx] += v->height_map[y * (ADT_CELL_SIZE * 2 + 1) + x];
558
                }
559
            }
560
            // get V8 height map
561
            for (int y = 0; y < ADT_CELL_SIZE; y++)
562
            {
563
                int cy = i * ADT_CELL_SIZE + y;
564
                for (int x = 0; x < ADT_CELL_SIZE; x++)
565
                {
566
                    int cx = j * ADT_CELL_SIZE + x;
567
                    V8[cy][cx] += v->height_map[y * (ADT_CELL_SIZE * 2 + 1) + ADT_CELL_SIZE + 1 + x];
568
                }
569
            }
570
        }
571
    }
572
    //============================================
573
    // Try pack height data
574
    //============================================
575
    float maxHeight = -20000;
576
    float minHeight =  20000;
577
    for (int y = 0; y < ADT_GRID_SIZE; y++)
578
    {
579
        for(int x = 0; x < ADT_GRID_SIZE; x++)
580
        {
581
            float h = V8[y][x];
582
            if (maxHeight < h) maxHeight = h;
583
            if (minHeight > h) minHeight = h;
584
        }
585
    }
586
    for (int y = 0; y <= ADT_GRID_SIZE; y++)
587
    {
588
        for (int x = 0; x <= ADT_GRID_SIZE; x++)
589
        {
590
            float h = V9[y][x];
591
            if (maxHeight < h) maxHeight = h;
592
            if (minHeight > h) minHeight = h;
593
        }
594
    }
595

596
    // Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
597
    if (CONF_allow_height_limit && minHeight < CONF_use_minHeight)
598
    {
599
        for (int y = 0; y < ADT_GRID_SIZE; y++)
600
            for (int x = 0; x < ADT_GRID_SIZE; x++)
601
                if (V8[y][x] < CONF_use_minHeight)
602
                    V8[y][x] = CONF_use_minHeight;
603
        for (int y = 0; y <= ADT_GRID_SIZE; y++)
604
            for (int x = 0; x <= ADT_GRID_SIZE; x++)
605
                if (V9[y][x] < CONF_use_minHeight)
606
                    V9[y][x] = CONF_use_minHeight;
607
        if (minHeight < CONF_use_minHeight)
608
            minHeight = CONF_use_minHeight;
609
        if (maxHeight < CONF_use_minHeight)
610
            maxHeight = CONF_use_minHeight;
611
    }
612

613
    bool hasFlightBox = false;
614
    if (adt_MFBO* mfbo = adt.a_grid->getMFBO())
615
    {
616
        memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max));
617
        memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min));
618
        hasFlightBox = true;
619
    }
620

621
    map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
622
    map.heightMapSize = sizeof(map_heightHeader);
623

624
    map_heightHeader heightHeader;
625
    heightHeader.fourcc = *(uint32 const*)MAP_HEIGHT_MAGIC;
626
    heightHeader.flags = 0;
627
    heightHeader.gridHeight    = minHeight;
628
    heightHeader.gridMaxHeight = maxHeight;
629

630
    if (maxHeight == minHeight)
631
        heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
632

633
    // Not need store if flat surface
634
    if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
635
        heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
636

637
    if (hasFlightBox)
638
    {
639
        heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS;
640
        map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min);
641
    }
642

643
    // Try store as packed in uint16 or uint8 values
644
    if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
645
    {
646
        float step = 0;
647
        // Try Store as uint values
648
        if (CONF_allow_float_to_int)
649
        {
650
            float diff = maxHeight - minHeight;
651
            if (diff < CONF_float_to_int8_limit)      // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
652
            {
653
                heightHeader.flags |= MAP_HEIGHT_AS_INT8;
654
                step = selectUInt8StepStore(diff);
655
            }
656
            else if (diff < CONF_float_to_int16_limit)  // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
657
            {
658
                heightHeader.flags |= MAP_HEIGHT_AS_INT16;
659
                step = selectUInt16StepStore(diff);
660
            }
661
        }
662

663
        // Pack it to int values if need
664
        if (heightHeader.flags & MAP_HEIGHT_AS_INT8)
665
        {
666
            for (int y = 0; y < ADT_GRID_SIZE; y++)
667
                for(int x = 0; x < ADT_GRID_SIZE; x++)
668
                    uint8_V8[y][x] = uint8((V8[y][x] - minHeight) * step + 0.5f);
669
            for (int y = 0; y <= ADT_GRID_SIZE; y++)
670
                for(int x = 0; x <= ADT_GRID_SIZE; x++)
671
                    uint8_V9[y][x] = uint8((V9[y][x] - minHeight) * step + 0.5f);
672
            map.heightMapSize += sizeof(uint8_V9) + sizeof(uint8_V8);
673
        }
674
        else if (heightHeader.flags & MAP_HEIGHT_AS_INT16)
675
        {
676
            for (int y = 0; y < ADT_GRID_SIZE; y++)
677
                for(int x = 0; x < ADT_GRID_SIZE; x++)
678
                    uint16_V8[y][x] = uint16((V8[y][x] - minHeight) * step + 0.5f);
679
            for (int y = 0; y <= ADT_GRID_SIZE; y++)
680
                for(int x = 0; x <= ADT_GRID_SIZE; x++)
681
                    uint16_V9[y][x] = uint16((V9[y][x] - minHeight) * step + 0.5f);
682
            map.heightMapSize += sizeof(uint16_V9) + sizeof(uint16_V8);
683
        }
684
        else
685
            map.heightMapSize += sizeof(V9) + sizeof(V8);
686
    }
687

688
    // Get from MCLQ chunk (old)
689
    for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
690
    {
691
        for(int j = 0; j < ADT_CELLS_PER_GRID; j++)
692
        {
693
            adt_MCNK *cell = adt.cells[i][j];
694
            if (!cell)
695
                continue;
696

697
            adt_MCLQ *liquid = cell->getMCLQ();
698
            int count = 0;
699
            if (!liquid || cell->sizeMCLQ <= 8)
700
                continue;
701

702
            for (int y = 0; y < ADT_CELL_SIZE; y++)
703
            {
704
                int cy = i * ADT_CELL_SIZE + y;
705
                for (int x = 0; x < ADT_CELL_SIZE; x++)
706
                {
707
                    int cx = j * ADT_CELL_SIZE + x;
708
                    if (liquid->flags[y][x] != 0x0F)
709
                    {
710
                        liquid_show[cy][cx] = true;
711
                        if (liquid->flags[y][x] & (1 << 7))
712
                            liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER;
713
                        ++count;
714
                    }
715
                }
716
            }
717

718
            uint32 c_flag = cell->flags;
719
            if (c_flag & (1 << 2))
720
            {
721
                liquid_entry[i][j] = 1;
722
                liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER;            // water
723
            }
724
            if (c_flag & (1 << 3))
725
            {
726
                liquid_entry[i][j] = 2;
727
                liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN;            // ocean
728
            }
729
            if (c_flag & (1 << 4))
730
            {
731
                liquid_entry[i][j] = 3;
732
                liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA;            // magma/slime
733
            }
734

735
            if (!count && liquid_flags[i][j])
736
                fprintf(stderr, "Wrong liquid detect in MCLQ chunk");
737

738
            for (int y = 0; y <= ADT_CELL_SIZE; y++)
739
            {
740
                int cy = i * ADT_CELL_SIZE + y;
741
                for (int x = 0; x <= ADT_CELL_SIZE; x++)
742
                {
743
                    int cx = j * ADT_CELL_SIZE + x;
744
                    liquid_height[cy][cx] = liquid->liquid[y][x].height;
745
                }
746
            }
747
        }
748
    }
749

750
    // Get liquid map for grid (in WOTLK used MH2O chunk)
751
    adt_MH2O * h2o = adt.a_grid->getMH2O();
752
    if (h2o)
753
    {
754
        for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
755
        {
756
            for(int j = 0; j < ADT_CELLS_PER_GRID; j++)
757
            {
758
                adt_liquid_header *h = h2o->getLiquidData(i,j);
759
                if (!h)
760
                    continue;
761

762
                int count = 0;
763
                uint64 show = h2o->getLiquidShowMap(h);
764
                for (int y = 0; y < h->height; y++)
765
                {
766
                    int cy = i * ADT_CELL_SIZE + y + h->yOffset;
767
                    for (int x = 0; x < h->width; x++)
768
                    {
769
                        int cx = j * ADT_CELL_SIZE + x + h->xOffset;
770
                        if (show & 1)
771
                        {
772
                            liquid_show[cy][cx] = true;
773
                            ++count;
774
                        }
775
                        show >>= 1;
776
                    }
777
                }
778

779
                liquid_entry[i][j] = h->liquidType;
780
                switch (LiqType[h->liquidType])
781
                {
782
                    case LIQUID_TYPE_WATER: liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; break;
783
                    case LIQUID_TYPE_OCEAN: liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; break;
784
                    case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break;
785
                    case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break;
786
                    default:
787
                        printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, filename, i, j);
788
                        break;
789
                }
790
                // Dark water detect
791
                if (LiqType[h->liquidType] == LIQUID_TYPE_OCEAN)
792
                {
793
                    uint8* lm = h2o->getLiquidLightMap(h);
794
                    if (!lm)
795
                        liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER;
796
                }
797

798
                if (!count && liquid_flags[i][j])
799
                    printf("Wrong liquid detect in MH2O chunk");
800

801
                float* height = h2o->getLiquidHeightMap(h);
802
                int pos = 0;
803
                for (int y = 0; y <= h->height; y++)
804
                {
805
                    int cy = i * ADT_CELL_SIZE + y + h->yOffset;
806
                    for (int x = 0; x <= h->width; x++)
807
                    {
808
                        int cx = j * ADT_CELL_SIZE + x + h->xOffset;
809

810
                        if (height)
811
                            liquid_height[cy][cx] = height[pos];
812
                        else
813
                            liquid_height[cy][cx] = h->heightLevel1;
814

815
                        pos++;
816
                    }
817
                }
818
            }
819
        }
820
    }
821

822
    //============================================
823
    // Pack liquid data
824
    //============================================
825
    uint8 type = liquid_flags[0][0];
826
    bool fullType = false;
827
    for (int y = 0; y < ADT_CELLS_PER_GRID; y++)
828
    {
829
        for (int x = 0; x < ADT_CELLS_PER_GRID; x++)
830
        {
831
            if (liquid_flags[y][x] != type)
832
            {
833
                fullType = true;
834
                y = ADT_CELLS_PER_GRID;
835
                break;
836
            }
837
        }
838
    }
839

840
    map_liquidHeader liquidHeader;
841

842
    // no water data (if all grid have 0 liquid type)
843
    if (type == 0 && !fullType)
844
    {
845
        // No liquid data
846
        map.liquidMapOffset = 0;
847
        map.liquidMapSize   = 0;
848
    }
849
    else
850
    {
851
        int minX = 255, minY = 255;
852
        int maxX = 0, maxY = 0;
853
        maxHeight = -20000;
854
        minHeight = 20000;
855
        for (int y = 0; y < ADT_GRID_SIZE; y++)
856
        {
857
            for (int x = 0; x < ADT_GRID_SIZE; x++)
858
            {
859
                if (liquid_show[y][x])
860
                {
861
                    if (minX > x) minX = x;
862
                    if (maxX < x) maxX = x;
863
                    if (minY > y) minY = y;
864
                    if (maxY < y) maxY = y;
865
                    float h = liquid_height[y][x];
866
                    if (maxHeight < h) maxHeight = h;
867
                    if (minHeight > h) minHeight = h;
868
                }
869
                else
870
                    liquid_height[y][x] = CONF_use_minHeight;
871
            }
872
        }
873

874
        bool liquidHasHoles = false;
875
        for (int y = minY; y <= maxY && !liquidHasHoles; ++y)
876
            for (int x = minX; x <= maxX && !liquidHasHoles; ++x)
877
                if (!liquid_show[y][x])
878
                    liquidHasHoles = true;
879

880
        map.liquidMapOffset = map.heightMapOffset + map.heightMapSize;
881
        map.liquidMapSize = sizeof(map_liquidHeader);
882
        liquidHeader.fourcc = *(uint32 const*)MAP_LIQUID_MAGIC;
883
        liquidHeader.flags = 0;
884
        liquidHeader.liquidType = 0;
885
        liquidHeader.offsetX = minX;
886
        liquidHeader.offsetY = minY;
887
        liquidHeader.width   = maxX - minX + 1 + 1;
888
        liquidHeader.height  = maxY - minY + 1 + 1;
889
        liquidHeader.liquidLevel = minHeight;
890

891
        if (maxHeight == minHeight && !liquidHasHoles)
892
            liquidHeader.flags |= MAP_LIQUID_NO_HEIGHT;
893

894
        // Not need store if flat surface
895
        if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_liquid_delta_limit)
896
            liquidHeader.flags |= MAP_LIQUID_NO_HEIGHT;
897

898
        if (!fullType)
899
            liquidHeader.flags |= MAP_LIQUID_NO_TYPE;
900

901
        if (liquidHeader.flags & MAP_LIQUID_NO_TYPE)
902
            liquidHeader.liquidType = type;
903
        else
904
            map.liquidMapSize += sizeof(liquid_entry) + sizeof(liquid_flags);
905

906
        if (!(liquidHeader.flags & MAP_LIQUID_NO_HEIGHT))
907
            map.liquidMapSize += sizeof(float) * liquidHeader.width * liquidHeader.height;
908
    }
909

910
    // map hole info
911
    uint16 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
912

913
    if (map.liquidMapOffset)
914
        map.holesOffset = map.liquidMapOffset + map.liquidMapSize;
915
    else
916
        map.holesOffset = map.heightMapOffset + map.heightMapSize;
917

918
    memset(holes, 0, sizeof(holes));
919
    bool hasHoles = false;
920

921
    for (int i = 0; i < ADT_CELLS_PER_GRID; ++i)
922
    {
923
        for (int j = 0; j < ADT_CELLS_PER_GRID; ++j)
924
        {
925
            adt_MCNK * cell = adt.cells[i][j];
926
            if (!cell)
927
                continue;
928
            holes[i][j] = cell->holes;
929
            if (!hasHoles && cell->holes != 0)
930
                hasHoles = true;
931
        }
932
    }
933

934
    if (hasHoles)
935
        map.holesSize = sizeof(holes);
936
    else
937
        map.holesSize = 0;
938

939
    // Ok all data prepared - store it
940
    FILE* output = fopen(filename2, "wb");
941
    if (!output)
942
    {
943
        printf("Can't create the output file '%s'\n", filename2);
944
        return false;
945
    }
946
    fwrite(&map, sizeof(map), 1, output);
947
    // Store area data
948
    fwrite(&areaHeader, sizeof(areaHeader), 1, output);
949
    if (!(areaHeader.flags & MAP_AREA_NO_AREA))
950
        fwrite(reinterpret_cast<const char*>(area_ids), sizeof(area_ids), 1, output);
951

952
    // Store height data
953
    fwrite(&heightHeader, sizeof(heightHeader), 1, output);
954
    if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
955
    {
956
        if (heightHeader.flags & MAP_HEIGHT_AS_INT16)
957
        {
958
            fwrite(uint16_V9, sizeof(uint16_V9), 1, output);
959
            fwrite(uint16_V8, sizeof(uint16_V8), 1, output);
960
        }
961
        else if (heightHeader.flags & MAP_HEIGHT_AS_INT8)
962
        {
963
            fwrite(uint8_V9, sizeof(uint8_V9), 1, output);
964
            fwrite(uint8_V8, sizeof(uint8_V8), 1, output);
965
        }
966
        else
967
        {
968
            fwrite(V9, sizeof(V9), 1, output);
969
            fwrite(V8, sizeof(V8), 1, output);
970
        }
971
    }
972

973
    if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
974
    {
975
        fwrite(reinterpret_cast<char*>(flight_box_max), sizeof(flight_box_max), 1, output);
976
        fwrite(reinterpret_cast<char*>(flight_box_min), sizeof(flight_box_min), 1, output);
977
    }
978

979
    // Store liquid data if need
980
    if (map.liquidMapOffset)
981
    {
982
        fwrite(&liquidHeader, sizeof(liquidHeader), 1, output);
983
        if (!(liquidHeader.flags & MAP_LIQUID_NO_TYPE))
984
        {
985
            fwrite(liquid_entry, sizeof(liquid_entry), 1, output);
986
            fwrite(liquid_flags, sizeof(liquid_flags), 1, output);
987
        }
988

989
        if (!(liquidHeader.flags & MAP_LIQUID_NO_HEIGHT))
990
        {
991
            for (int y = 0; y < liquidHeader.height; y++)
992
                fwrite(&liquid_height[y + liquidHeader.offsetY][liquidHeader.offsetX], sizeof(float), liquidHeader.width, output);
993
        }
994
    }
995

996
    // store hole data
997
    if (hasHoles)
998
        fwrite(holes, map.holesSize, 1, output);
999

1000
    fclose(output);
1001

1002
    return true;
1003
}
1004

1005
void ExtractMapsFromMpq(uint32 build)
1006
{
1007
    char mpq_filename[1024];
1008
    char output_filename[1024];
1009
    char mpq_map_name[1024];
1010

1011
    printf("Extracting maps...\n");
1012

1013
    uint32 map_count = ReadMapDBC();
1014

1015
    ReadLiquidTypeTableDBC();
1016

1017
    std::string path = output_path;
1018
    path += "/maps/";
1019
    CreateDir(path);
1020

1021
    printf("Convert map files\n");
1022
    for (uint32 z = 0; z < map_count; ++z)
1023
    {
1024
        printf("Extract %s (%d/%u)                  \n", map_ids[z].name, z+1, map_count);
1025
        // Loadup map grid data
1026
        sprintf(mpq_map_name, "World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name);
1027
        WDT_file wdt;
1028
        if (!wdt.loadFile(WorldMpq, mpq_map_name, false))
1029
            continue;
1030

1031
        for (uint32 y = 0; y < WDT_MAP_SIZE; ++y)
1032
        {
1033
            for (uint32 x = 0; x < WDT_MAP_SIZE; ++x)
1034
            {
1035
                if (!(wdt.main->adt_list[y][x].flag & 0x1))
1036
                    continue;
1037

1038
                sprintf(mpq_filename, "World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
1039
                sprintf(output_filename, "%s/maps/%04u_%02u_%02u.map", output_path, map_ids[z].id, y, x);
1040
                ConvertADT(mpq_filename, output_filename, y, x, build);
1041
            }
1042

1043
            // draw progress bar
1044
            printf("Processing........................%d%%\r", (100 * (y+1)) / WDT_MAP_SIZE);
1045
        }
1046
    }
1047

1048
    printf("\n");
1049
    delete [] map_ids;
1050
}
1051

1052
bool ExtractFile(HANDLE fileInArchive, char const* filename)
1053
{
1054
    FILE* output = fopen(filename, "wb");
1055
    if(!output)
1056
    {
1057
        printf("Can't create the output file '%s'\n", filename);
1058
        return false;
1059
    }
1060

1061
    char  buffer[0x10000];
1062
    DWORD readBytes = 1;
1063

1064
    while (readBytes > 0)
1065
    {
1066
        SFileReadFile(fileInArchive, buffer, sizeof(buffer), &readBytes, NULL);
1067
        if (readBytes > 0)
1068
            fwrite(buffer, 1, readBytes, output);
1069
    }
1070

1071
    fclose(output);
1072
    return true;
1073
}
1074

1075
void ExtractDBCFiles(int l, bool basicLocale)
1076
{
1077
    printf("Extracting dbc files...\n");
1078

1079
    SFILE_FIND_DATA foundFile;
1080
    memset(&foundFile, 0, sizeof(foundFile));
1081
    HANDLE listFile = SFileFindFirstFile(LocaleMpq, "DBFilesClient\\*dbc", &foundFile, NULL);
1082
    HANDLE dbcFile = NULL;
1083
    uint32 count = 0;
1084
    if (listFile)
1085
    {
1086
        std::string outputPath = output_path;
1087
        outputPath += "/dbc/";
1088

1089
        CreateDir(outputPath);
1090
        if (!basicLocale)
1091
        {
1092
            outputPath += Locales[l];
1093
            outputPath += "/";
1094
            CreateDir(outputPath);
1095
        }
1096

1097
        std::string filename;
1098

1099
        do
1100
        {
1101
            if (!SFileOpenFileEx(LocaleMpq, foundFile.cFileName, SFILE_OPEN_PATCHED_FILE, &dbcFile))
1102
            {
1103
                printf("Unable to open file %s in the archive\n", foundFile.cFileName);
1104
                continue;
1105
            }
1106

1107
            filename = foundFile.cFileName;
1108
            size_t path_sper_pos_found = filename.rfind('\\');
1109
            if (path_sper_pos_found != std::string::npos)
1110
            {
1111
                filename = outputPath + filename.substr(path_sper_pos_found + 1);
1112
                if (ExtractFile(dbcFile, filename.c_str()))
1113
                    ++count;
1114
            }
1115

1116
            SFileCloseFile(dbcFile);
1117
        } while (SFileFindNextFile(listFile, &foundFile));
1118

1119
        SFileFindClose(listFile);
1120
    }
1121

1122
    printf("Extracted %u DBC files\n\n", count);
1123
}
1124

1125
void ExtractCameraFiles(int locale, bool basicLocale)
1126
{
1127
    printf("Extracting camera files...\n");
1128
    HANDLE dbcFile;
1129
    if (!SFileOpenFileEx(LocaleMpq, "DBFilesClient\\CinematicCamera.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile))
1130
    {
1131
        printf("Fatal error: Cannot find CinematicCamera.dbc in archive!\n");
1132
        exit(1);
1133
    }
1134

1135
    DBCFile camdbc(dbcFile);
1136

1137
    if (!camdbc.open())
1138
    {
1139
        printf("Unable to open CinematicCamera.dbc. Camera extract aborted.\n");
1140
        return;
1141
    }
1142

1143
    // get camera file list from DBC
1144
    std::vector<std::string> camerafiles;
1145
    size_t cam_count = camdbc.getRecordCount();
1146

1147
    for (size_t i = 0; i < cam_count; ++i)
1148
    {
1149
        std::string camFile(camdbc.getRecord(i).getString(1));
1150
        size_t loc = camFile.find(".mdx");
1151
        if (loc != std::string::npos)
1152
            camFile.replace(loc, 4, ".m2");
1153
        camerafiles.push_back(std::string(camFile));
1154
    }
1155
    SFileCloseFile(dbcFile);
1156

1157
    std::string path = output_path;
1158
    path += "/cameras/";
1159
    CreateDir(path);
1160
    if (!basicLocale)
1161
    {
1162
        path += Locales[locale];
1163
        path += "/";
1164
        CreateDir(path);
1165
    }
1166

1167
    // extract M2s
1168
    uint32 count = 0;
1169
    for (std::string thisFile : camerafiles)
1170
    {
1171
        std::string filename = path;
1172
        std::string camerasFolder = "Cameras\\";
1173
        HANDLE dbcFile = NULL;
1174
        filename += (thisFile.c_str() + camerasFolder.length());
1175

1176
        if (FileExists(filename.c_str()))
1177
            continue;
1178

1179
        if (!SFileOpenFileEx(WorldMpq, thisFile.c_str(), SFILE_OPEN_PATCHED_FILE, &dbcFile))
1180
        {
1181
            printf("Unable to open file %s in the archive\n", thisFile.c_str());
1182
            continue;
1183
        }
1184

1185
        // dbc has mixed case names, standardize on lower case
1186
        std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower);
1187

1188
        if (ExtractFile(dbcFile, filename.c_str()))
1189
            ++count;
1190

1191
        SFileCloseFile(dbcFile);
1192
    }
1193
    printf("Extracted %u camera files\n", count);
1194
}
1195

1196
void ExtractDB2Files(int l, bool basicLocale)
1197
{
1198
    printf("Extracting db2 files...\n");
1199

1200
    SFILE_FIND_DATA foundFile;
1201
    memset(&foundFile, 0, sizeof(foundFile));
1202
    HANDLE listFile = SFileFindFirstFile(LocaleMpq, "DBFilesClient\\*db2", &foundFile, NULL);
1203
    HANDLE dbcFile = NULL;
1204
    uint32 count = 0;
1205
    if (listFile)
1206
    {
1207
        std::string outputPath = output_path;
1208
        outputPath += "/dbc/";
1209
        if (!basicLocale)
1210
        {
1211
            outputPath += Locales[l];
1212
            outputPath += "/";
1213
        }
1214

1215
        std::string filename;
1216

1217
        do
1218
        {
1219
            if (!SFileOpenFileEx(LocaleMpq, foundFile.cFileName, SFILE_OPEN_PATCHED_FILE, &dbcFile))
1220
            {
1221
                printf("Unable to open file %s in the archive\n", foundFile.cFileName);
1222
                continue;
1223
            }
1224

1225
            filename = foundFile.cFileName;
1226
            size_t path_sper_pos_found = filename.rfind('\\');
1227
            if (path_sper_pos_found != std::string::npos)
1228
            {
1229
                filename = outputPath + filename.substr(path_sper_pos_found + 1);
1230
                if (ExtractFile(dbcFile, filename.c_str()))
1231
                    ++count;
1232
            }
1233

1234
            SFileCloseFile(dbcFile);
1235
        } while (SFileFindNextFile(listFile, &foundFile));
1236

1237
        SFileFindClose(listFile);
1238
    }
1239

1240
    printf("Extracted %u DB2 files\n\n", count);
1241
}
1242

1243
bool LoadLocaleMPQFile(int locale)
1244
{
1245
    TCHAR buff[512];
1246
    char const* prefix = "";
1247

1248
    memset(buff, 0, sizeof(buff));
1249
    _stprintf(buff, _T("%s/Data/misc.MPQ"), input_path);
1250
    if (!SFileOpenArchive(buff, 0, MPQ_OPEN_READ_ONLY, &LocaleMpq))
1251
    {
1252
        if (GetLastError() != ERROR_PATH_NOT_FOUND)
1253
        {
1254
            _tprintf(_T("\nLoading %s locale MPQs\n"), LocalesT[locale]);
1255
            _tprintf(_T("Cannot open archive %s\n"), buff);
1256
        }
1257
        return false;
1258
    }
1259

1260
    memset(buff, 0, sizeof(buff));
1261
    _stprintf(buff, _T("%s/Data/%s/locale-%s.MPQ"), input_path, LocalesT[locale], LocalesT[locale]);
1262
    if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0))
1263
    {
1264
        if (GetLastError() != ERROR_FILE_NOT_FOUND)
1265
            _tprintf(_T("Cannot open patch archive %s\n"), buff);
1266
        if (GetLastError() != ERROR_PATH_NOT_FOUND)
1267
        {
1268
            _tprintf(_T("\nLoading %s locale MPQs\n"), LocalesT[locale]);
1269
            _tprintf(_T("Cannot open archive %s\n"), buff);
1270
        }
1271
        return false;
1272
    }
1273

1274
    _tprintf(_T("\nLoading %s locale MPQs\n"), LocalesT[locale]);
1275

1276
    for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i)
1277
    {
1278
        memset(buff, 0, sizeof(buff));
1279
        prefix = "";
1280
        _stprintf(buff, _T("%s/Data/wow-update-base-%u.MPQ"), input_path, Builds[i]);
1281

1282
        if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0))
1283
        {
1284
            if (GetLastError() != ERROR_PATH_NOT_FOUND)
1285
                _tprintf(_T("Cannot open patch archive %s\n"), buff);
1286
            else
1287
                _tprintf(_T("Not found %s\n"), buff);
1288
            continue;
1289
        }
1290
        else
1291
            _tprintf(_T("Loaded %s\n"), buff);
1292
    }
1293

1294
    for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i)
1295
    {
1296
        memset(buff, 0, sizeof(buff));
1297
        prefix = "";
1298
        _stprintf(buff, _T("%s/Data/%s/wow-update-%s-%u.MPQ"), input_path, LocalesT[locale], LocalesT[locale], Builds[i]);
1299

1300
        if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0))
1301
        {
1302
            if (GetLastError() != ERROR_FILE_NOT_FOUND)
1303
                _tprintf(_T("Cannot open patch archive %s\n"), buff);
1304
            continue;
1305
        }
1306
        else
1307
            _tprintf(_T("Loaded %s\n"), buff);
1308
    }
1309

1310
    for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i)
1311
    {
1312
        memset(buff, 0, sizeof(buff));
1313
        prefix = "";
1314
        _stprintf(buff, _T("%s/Data/Cache/patch-base-%u.MPQ"), input_path, Builds[i]);
1315

1316
        if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0))
1317
        {
1318
            if (GetLastError() != ERROR_FILE_NOT_FOUND)
1319
                _tprintf(_T("Cannot open patch archive %s\n"), buff);
1320
            continue;
1321
        }
1322
        else
1323
            _tprintf(_T("Loaded %s\n"), buff);
1324
    }
1325

1326
    for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i)
1327
    {
1328
        // Load cached locales
1329
        memset(buff, 0, sizeof(buff));
1330
        prefix = "";
1331
        _stprintf(buff, _T("%s/Data/Cache/%s/patch-%s-%u.MPQ"), input_path, LocalesT[locale], LocalesT[locale], Builds[i]);
1332

1333
        if (!SFileOpenPatchArchive(LocaleMpq, buff, prefix, 0))
1334
        {
1335
            if (GetLastError() != ERROR_FILE_NOT_FOUND)
1336
                _tprintf(_T("Cannot open patch archive %s\n"), buff);
1337
            continue;
1338
        }
1339
        else
1340
            _tprintf(_T("Loaded %s\n"), buff);
1341
    }
1342

1343
    printf("\n");
1344
    return true;
1345
}
1346

1347
void LoadCommonMPQFiles(uint32 build)
1348
{
1349
    TCHAR filename[512];
1350
    _stprintf(filename, _T("%s/Data/world.MPQ"), input_path);
1351
    _tprintf(_T("Loading common MPQ files\n"));
1352
    if (!SFileOpenArchive(filename, 0, MPQ_OPEN_READ_ONLY, &WorldMpq))
1353
    {
1354
        if (GetLastError() != ERROR_PATH_NOT_FOUND)
1355
            _tprintf(_T("Cannot open archive %s\n"), filename);
1356
        return;
1357
    }
1358
    else
1359
        _tprintf(_T("Loaded %s\n"), filename);
1360

1361
    int count = sizeof(CONF_mpq_list) / sizeof(char*);
1362
    for (int i = 1; i < count; ++i)
1363
    {
1364
        if (build < NEW_BASE_SET_BUILD)   // 4.3.2 and higher MPQ
1365
            continue;
1366

1367
        _stprintf(filename, _T("%s/Data/%s"), input_path, CONF_mpq_list[i]);
1368
        if (!SFileOpenPatchArchive(WorldMpq, filename, "", 0))
1369
        {
1370
            if (GetLastError() != ERROR_PATH_NOT_FOUND)
1371
                _tprintf(_T("Cannot open archive %s\n"), filename);
1372
            else
1373
                _tprintf(_T("Not found %s\n"), filename);
1374
        }
1375
        else
1376
            _tprintf(_T("Loaded %s\n"), filename);
1377

1378
    }
1379

1380
    char const* prefix = NULL;
1381
    for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i)
1382
    {
1383
        memset(filename, 0, sizeof(filename));
1384
        prefix = "";
1385
        _stprintf(filename, _T("%s/Data/wow-update-base-%u.MPQ"), input_path, Builds[i]);
1386

1387
        if (!SFileOpenPatchArchive(WorldMpq, filename, prefix, 0))
1388
        {
1389
            if (GetLastError() != ERROR_PATH_NOT_FOUND)
1390
                _tprintf(_T("Cannot open patch archive %s\n"), filename);
1391
            else
1392
                _tprintf(_T("Not found %s\n"), filename);
1393
            continue;
1394
        }
1395
        else
1396
            _tprintf(_T("Loaded %s\n"), filename);
1397

1398
    }
1399

1400
    for (int i = 0; Builds[i] && Builds[i] <= CONF_TargetBuild; ++i)
1401
    {
1402
        memset(filename, 0, sizeof(filename));
1403
        prefix = "";
1404
        _stprintf(filename, _T("%s/Data/Cache/patch-base-%u.MPQ"), input_path, Builds[i]);
1405

1406
        if (!SFileOpenPatchArchive(WorldMpq, filename, prefix, 0))
1407
        {
1408
            if (GetLastError() != ERROR_PATH_NOT_FOUND)
1409
                _tprintf(_T("Cannot open patch archive %s\n"), filename);
1410
            else
1411
                _tprintf(_T("Not found %s\n"), filename);
1412
            continue;
1413
        }
1414
        else
1415
            _tprintf(_T("Loaded %s\n"), filename);
1416
    }
1417

1418
    printf("\n");
1419
}
1420

1421
int main(int argc, char * arg[])
1422
{
1423
    printf("Map & DBC Extractor\n");
1424
    printf("===================\n");
1425

1426
    HandleArgs(argc, arg);
1427

1428
    int FirstLocale = -1;
1429
    uint32 build = 0;
1430

1431
    for (int i = 0; i < LOCALES_COUNT; ++i)
1432
    {
1433
        //Open MPQs
1434
        if (!LoadLocaleMPQFile(i))
1435
        {
1436
            if (GetLastError() != ERROR_PATH_NOT_FOUND)
1437
                printf("Unable to load %s locale archives!\n", Locales[i]);
1438
            continue;
1439
        }
1440

1441
        printf("Detected locale: %s\n", Locales[i]);
1442
        if ((CONF_extract & EXTRACT_DBC) == 0)
1443
        {
1444
            FirstLocale = i;
1445
            build = ReadBuild(i);
1446
            if (build > CONF_TargetBuild)
1447
            {
1448
                printf("Base locale-%s.MPQ has build higher than target build (%u > %u), nothing extracted!\n", Locales[i], build, CONF_TargetBuild);
1449
                return 0;
1450
            }
1451

1452
            printf("Detected client build: %u\n", build);
1453
            printf("\n");
1454
            break;
1455
        }
1456

1457
        //Extract DBC files
1458
        uint32 tempBuild = ReadBuild(i);
1459
        printf("Detected client build %u for locale %s\n", tempBuild, Locales[i]);
1460
        if (tempBuild > CONF_TargetBuild)
1461
        {
1462
            SFileCloseArchive(LocaleMpq);
1463
            printf("Base locale-%s.MPQ has build higher than target build (%u > %u), nothing extracted!\n", Locales[i], tempBuild, CONF_TargetBuild);
1464
            continue;
1465
        }
1466

1467
        printf("\n");
1468
        ExtractDBCFiles(i, FirstLocale < 0);
1469
        ExtractDB2Files(i, FirstLocale < 0);
1470

1471
        if (FirstLocale < 0)
1472
        {
1473
            FirstLocale = i;
1474
            build = tempBuild;
1475
        }
1476

1477
        //Close MPQs
1478
        SFileCloseArchive(LocaleMpq);
1479
    }
1480

1481
    if (FirstLocale < 0)
1482
    {
1483
        printf("No locales detected\n");
1484
        return 0;
1485
    }
1486

1487
    if (CONF_extract & EXTRACT_CAMERA)
1488
    {
1489
        printf("Using locale: %s\n", Locales[FirstLocale]);
1490

1491
        // Open MPQs
1492
        LoadLocaleMPQFile(FirstLocale);
1493
        LoadCommonMPQFiles(build);
1494

1495
        // Extract cameras
1496
        ExtractCameraFiles(FirstLocale, true);
1497

1498
        // Close MPQs
1499
        SFileCloseArchive(WorldMpq);
1500
        SFileCloseArchive(LocaleMpq);
1501
    }
1502

1503
    if (CONF_extract & EXTRACT_MAP)
1504
    {
1505
        printf("Using locale: %s\n", Locales[FirstLocale]);
1506

1507
        // Open MPQs
1508
        LoadLocaleMPQFile(FirstLocale);
1509
        LoadCommonMPQFiles(build);
1510

1511
        // Extract maps
1512
        ExtractMapsFromMpq(build);
1513

1514
        // Close MPQs
1515
        SFileCloseArchive(WorldMpq);
1516
        SFileCloseArchive(LocaleMpq);
1517
    }
1518

1519
    return 0;
1520
}
1521

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.