TrinityCore
Loading...
Searching...
No Matches
System.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "dbcfile.h"
19#include "Banner.h"
20#include "Locales.h"
21#include "mpq_libmpq.h"
22#include "StringFormat.h"
23#include "Util.h"
24
25#include "adt.h"
26#include "wdt.h"
27#include <boost/filesystem/directory.hpp>
28#include <boost/filesystem/operations.hpp>
29#include <boost/filesystem/path.hpp>
30#include <deque>
31#include <fstream>
32#include <set>
33#include <unordered_map>
34#include <cstdio>
35#include <cstdlib>
36#include <cstring>
37
38#include <G3D/Plane.h>
39#include <boost/filesystem.hpp>
40
41typedef struct
42{
43 char name[64];
45} map_id;
46
47struct LiquidTypeEntry
48{
50};
51
52std::vector<map_id> map_ids;
53std::unordered_map<uint32, LiquidTypeEntry> LiquidTypes;
54#define MAX_PATH_LENGTH 128
57
58// **************************************************
59// Extractor options
60// **************************************************
67
68// Select data for extract
70// This option allow limit minimum height to some value (Allow save some memory)
72float CONF_use_minHeight = -500.0f;
73
74// This option allow use float to int conversion
76float CONF_float_to_int8_limit = 2.0f; // Max accuracy = val/256
77float CONF_float_to_int16_limit = 2048.0f; // Max accuracy = val/65536
78float CONF_flat_height_delta_limit = 0.005f; // If max - min less this value - surface is flat
79float CONF_flat_liquid_delta_limit = 0.001f; // If max - min less this value - liquid surface is flat
80
81static constexpr std::array<std::string_view, 12> MpqLocaleNames = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
82
83void CreateDir(boost::filesystem::path const& path)
84{
85 namespace fs = boost::filesystem;
86 if (fs::exists(path))
87 return;
88
89 if (!fs::create_directory(path))
90 throw std::runtime_error("Unable to create directory" + path.string());
91}
92
93void Usage(char const* prg)
94{
95 printf(
96 "Usage:\n"\
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"\
102 "Example: %s -f 0 -i \"c:\\games\\game\"\n", prg, MAX_PATH_LENGTH - 1, MAX_PATH_LENGTH - 1, prg);
103 exit(1);
104}
105
106void HandleArgs(int argc, char* arg[])
107{
108 for(int c = 1; c < argc; ++c)
109 {
110 // i - input path
111 // o - output path
112 // e - extract only MAP(1)/DBC(2) - standard both(3)
113 // f - use float to int conversion
114 // h - limit minimum height
115 if(arg[c][0] != '-')
116 Usage(arg[0]);
117
118 switch (arg[c][1])
119 {
120 case 'i':
121 if (c + 1 < argc && strlen(arg[c + 1]) < MAX_PATH_LENGTH) // all ok
122 {
123 strncpy(input_path, arg[c++ + 1], MAX_PATH_LENGTH);
124 input_path[MAX_PATH_LENGTH - 1] = '\0';
125 }
126 else
127 Usage(arg[0]);
128 break;
129 case 'o':
130 if (c + 1 < argc && strlen(arg[c + 1]) < MAX_PATH_LENGTH) // all ok
131 {
132 strncpy(output_path, arg[c++ + 1], MAX_PATH_LENGTH);
133 output_path[MAX_PATH_LENGTH - 1] = '\0';
134 }
135 else
136 Usage(arg[0]);
137 break;
138 case 'f':
139 if (c + 1 < argc) // all ok
140 CONF_allow_float_to_int = atoi(arg[(c++) + 1]) != 0;
141 else
142 Usage(arg[0]);
143 break;
144 case 'e':
145 if (c + 1 < argc) // all ok
146 {
147 CONF_extract = atoi(arg[(c++) + 1]);
148 if (!(CONF_extract > 0 && CONF_extract < 8))
149 Usage(arg[0]);
150 }
151 else
152 Usage(arg[0]);
153 break;
154 case 'h':
155 Usage(arg[0]);
156 break;
157 default:
158 break;
159 }
160 }
161}
162
163uint32 ReadBuild(int locale)
164{
165 // include build info file also
166 std::string filename = Trinity::StringFormat("component.wow-{}.txt", MpqLocaleNames[locale]);
167 //printf("Read %s file... ", filename.c_str());
168
169 MPQFile m(filename.c_str());
170 if(m.isEof())
171 {
172 printf("Fatal error: Not found %s file!\n", filename.c_str());
173 exit(1);
174 }
175
176 std::string text = std::string(m.getPointer(), m.getSize());
177 m.close();
178
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)
183 {
184 printf("Fatal error: Invalid %s file format!\n", filename.c_str());
185 exit(1);
186 }
187
188 std::string build_str = text.substr(pos1,pos2-pos1);
189
190 int build = atoi(build_str.c_str());
191 if (build <= 0)
192 {
193 printf("Fatal error: Invalid %s file format!\n", filename.c_str());
194 exit(1);
195 }
196
197 return build;
198}
199
201{
202 printf("Read Map.dbc file... ");
203 DBCFile dbc("DBFilesClient\\Map.dbc");
204
205 if(!dbc.open())
206 {
207 printf("Fatal error: Invalid Map.dbc file format!\n");
208 exit(1);
209 }
210
211 size_t map_count = dbc.getRecordCount();
212 map_ids.resize(map_count);
213 for(uint32 x = 0; x < map_count; ++x)
214 {
215 map_ids[x].id = dbc.getRecord(x).getUInt(0);
216
217 char const* map_name = dbc.getRecord(x).getString(1);
218 size_t max_map_name_length = sizeof(map_ids[x].name);
219 if (strlen(map_name) >= max_map_name_length)
220 {
221 printf("Fatal error: Map name too long!\n");
222 exit(1);
223 }
224
225 strncpy(map_ids[x].name, map_name, max_map_name_length);
226 map_ids[x].name[max_map_name_length - 1] = '\0';
227 }
228 printf("Done! (" SZFMTD "maps loaded)\n", map_count);
229 return map_count;
230}
231
233{
234 printf("Read LiquidType.dbc file...");
235 DBCFile dbc("DBFilesClient\\LiquidType.dbc");
236 if(!dbc.open())
237 {
238 printf("Fatal error: Invalid LiquidType.dbc file format!\n");
239 exit(1);
240 }
241
242 for (uint32 x = 0; x < dbc.getRecordCount(); ++x)
243 {
244 LiquidTypeEntry& liquidType = LiquidTypes[dbc.getRecord(x).getUInt(0)];
245 liquidType.SoundBank = dbc.getRecord(x).getUInt(3);
246 }
247
248 printf("Done! (" SZFMTD " LiquidTypes loaded)\n", LiquidTypes.size());
249}
250
251//
252// Adt file convertor function and data
253//
254
255// Map file format data
256static char const* MAP_MAGIC = "MAPS";
257static uint32 const MAP_VERSION_MAGIC = 10;
258static char const* MAP_AREA_MAGIC = "AREA";
259static char const* MAP_HEIGHT_MAGIC = "MHGT";
260static char const* MAP_LIQUID_MAGIC = "MLIQ";
261
262struct map_fileheader
263{
275};
276
277#define MAP_AREA_NO_AREA 0x0001
278
279struct map_areaHeader
280{
284};
285
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
290
291struct map_heightHeader
292{
295 float gridHeight;
296 float gridMaxHeight;
297};
298
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
304
305#define MAP_LIQUID_TYPE_DARK_WATER 0x10
306
307#define MAP_LIQUID_NO_TYPE 0x0001
308#define MAP_LIQUID_NO_HEIGHT 0x0002
309
310struct map_liquidHeader
311{
313 uint8 flags;
318 uint8 width;
320 float liquidLevel;
321};
322
323float selectUInt8StepStore(float maxDiff)
324{
325 return 255 / maxDiff;
326}
327
328float selectUInt16StepStore(float maxDiff)
329{
330 return 65535 / maxDiff;
331}
332// Temporary grid data store
334
341
347
350
351bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int /*cell_y*/, int /*cell_x*/, uint32 build)
352{
353 ADT_file adt;
354
355 if (!adt.loadFile(inputPath))
356 return false;
357
358 adt_MCIN *cells = adt.a_grid->getMCIN();
359 if (!cells)
360 {
361 printf("Can't find cells in '%s'\n", inputPath.c_str());
362 return false;
363 }
364
365 memset(liquid_show, 0, sizeof(liquid_show));
366 memset(liquid_flags, 0, sizeof(liquid_flags));
367 memset(liquid_entry, 0, sizeof(liquid_entry));
368
369 memset(holes, 0, sizeof(holes));
370
371 // Prepare map header
372 map_fileheader map;
373 map.mapMagic = *reinterpret_cast<uint32 const*>(MAP_MAGIC);
375 map.buildMagic = build;
376
377 // Get area flags data
378 for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
379 for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
380 area_ids[i][j] = cells->getMCNK(i, j)->areaid;
381
382 //============================================
383 // Try pack area data
384 //============================================
385 bool fullAreaData = false;
386 uint32 areaId = area_ids[0][0];
387 for (int y = 0; y < ADT_CELLS_PER_GRID; ++y)
388 {
389 for (int x = 0; x < ADT_CELLS_PER_GRID; ++x)
390 {
391 if (area_ids[y][x] != areaId)
392 {
393 fullAreaData = true;
394 break;
395 }
396 }
397 }
398
399 map.areaMapOffset = sizeof(map);
400 map.areaMapSize = sizeof(map_areaHeader);
401
402 map_areaHeader areaHeader;
403 areaHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_AREA_MAGIC);
404 areaHeader.flags = 0;
405 if (fullAreaData)
406 {
407 areaHeader.gridArea = 0;
408 map.areaMapSize += sizeof(area_ids);
409 }
410 else
411 {
412 areaHeader.flags |= MAP_AREA_NO_AREA;
413 areaHeader.gridArea = static_cast<uint16>(areaId);
414 }
415
416 //
417 // Get Height map from grid
418 //
419 for (int i=0;i<ADT_CELLS_PER_GRID;i++)
420 {
421 for(int j=0;j<ADT_CELLS_PER_GRID;j++)
422 {
423 adt_MCNK * cell = cells->getMCNK(i,j);
424 if (!cell)
425 continue;
426 // Height values for triangles stored in order:
427 // 1 2 3 4 5 6 7 8 9
428 // 10 11 12 13 14 15 16 17
429 // 18 19 20 21 22 23 24 25 26
430 // 27 28 29 30 31 32 33 34
431 // . . . . . . . .
432 // For better get height values merge it to V9 and V8 map
433 // V9 height map:
434 // 1 2 3 4 5 6 7 8 9
435 // 18 19 20 21 22 23 24 25 26
436 // . . . . . . . .
437 // V8 height map:
438 // 10 11 12 13 14 15 16 17
439 // 27 28 29 30 31 32 33 34
440 // . . . . . . . .
441
442 // Set map height as grid height
443 for (int y=0; y <= ADT_CELL_SIZE; y++)
444 {
445 // edge V9s are overlapping between cells (i * ADT_CELL_SIZE is correct, otherwise we would be missing a row/column of V8s between)
446 int cy = i*ADT_CELL_SIZE + y;
447 for (int x=0; x <= ADT_CELL_SIZE; x++)
448 {
449 int cx = j*ADT_CELL_SIZE + x;
450 V9[cy][cx]=cell->ypos;
451 }
452 }
453 for (int y=0; y < ADT_CELL_SIZE; y++)
454 {
455 int cy = i*ADT_CELL_SIZE + y;
456 for (int x=0; x < ADT_CELL_SIZE; x++)
457 {
458 int cx = j*ADT_CELL_SIZE + x;
459 V8[cy][cx]=cell->ypos;
460 }
461 }
462 // Get custom height
463 adt_MCVT *v = cell->getMCVT();
464 if (!v)
465 continue;
466 // get V9 height map
467 for (int y=0; y <= ADT_CELL_SIZE; y++)
468 {
469 // edge V9s are overlapping between cells (i * ADT_CELL_SIZE is correct, otherwise we would be missing a row/column of V8s between)
470 int cy = i*ADT_CELL_SIZE + y;
471 for (int x=0; x <= ADT_CELL_SIZE; x++)
472 {
473 int cx = j*ADT_CELL_SIZE + x;
474 V9[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+x];
475 }
476 }
477 // get V8 height map
478 for (int y=0; y < ADT_CELL_SIZE; y++)
479 {
480 int cy = i*ADT_CELL_SIZE + y;
481 for (int x=0; x < ADT_CELL_SIZE; x++)
482 {
483 int cx = j*ADT_CELL_SIZE + x;
484 V8[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+ADT_CELL_SIZE+1+x];
485 }
486 }
487 }
488 }
489 //============================================
490 // Try pack height data
491 //============================================
492 float maxHeight = -20000;
493 float minHeight = 20000;
494 for (int y=0; y<ADT_GRID_SIZE; y++)
495 {
496 for(int x=0;x<ADT_GRID_SIZE;x++)
497 {
498 float h = V8[y][x];
499 if (maxHeight < h) maxHeight = h;
500 if (minHeight > h) minHeight = h;
501 }
502 }
503 for (int y=0; y<=ADT_GRID_SIZE; y++)
504 {
505 for(int x=0;x<=ADT_GRID_SIZE;x++)
506 {
507 float h = V9[y][x];
508 if (maxHeight < h) maxHeight = h;
509 if (minHeight > h) minHeight = h;
510 }
511 }
512
513 // Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
515 {
516 for (int y=0; y<ADT_GRID_SIZE; y++)
517 for(int x=0;x<ADT_GRID_SIZE;x++)
518 if (V8[y][x] < CONF_use_minHeight)
519 V8[y][x] = CONF_use_minHeight;
520 for (int y=0; y<=ADT_GRID_SIZE; y++)
521 for(int x=0;x<=ADT_GRID_SIZE;x++)
522 if (V9[y][x] < CONF_use_minHeight)
523 V9[y][x] = CONF_use_minHeight;
524 if (minHeight < CONF_use_minHeight)
525 minHeight = CONF_use_minHeight;
526 if (maxHeight < CONF_use_minHeight)
527 maxHeight = CONF_use_minHeight;
528 }
529
530 bool hasFlightBox = false;
531 if (adt_MFBO* mfbo = adt.a_grid->getMFBO())
532 {
533 memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max));
534 memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min));
535 hasFlightBox = true;
536 }
537
539 map.heightMapSize = sizeof(map_heightHeader);
540
541 map_heightHeader heightHeader;
542 heightHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_HEIGHT_MAGIC);
543 heightHeader.flags = 0;
544 heightHeader.gridHeight = minHeight;
545 heightHeader.gridMaxHeight = maxHeight;
546
547 if (maxHeight == minHeight)
548 heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
549
550 // Not need store if flat surface
551 if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
552 heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
553
554 if (hasFlightBox)
555 {
556 heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS;
557 map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min);
558 }
559
560 // Try store as packed in uint16 or uint8 values
561 if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
562 {
563 float step = 0;
564 // Try Store as uint values
566 {
567 float diff = maxHeight - minHeight;
568 if (diff < CONF_float_to_int8_limit) // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
569 {
570 heightHeader.flags |= MAP_HEIGHT_AS_INT8;
571 step = selectUInt8StepStore(diff);
572 }
573 else if (diff < CONF_float_to_int16_limit) // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
574 {
575 heightHeader.flags |= MAP_HEIGHT_AS_INT16;
576 step = selectUInt16StepStore(diff);
577 }
578 }
579
580 // Pack it to int values if need
581 if (heightHeader.flags&MAP_HEIGHT_AS_INT8)
582 {
583 for (int y=0; y<ADT_GRID_SIZE; y++)
584 for(int x=0;x<ADT_GRID_SIZE;x++)
585 uint8_V8[y][x] = uint8((V8[y][x] - minHeight) * step + 0.5f);
586 for (int y=0; y<=ADT_GRID_SIZE; y++)
587 for(int x=0;x<=ADT_GRID_SIZE;x++)
588 uint8_V9[y][x] = uint8((V9[y][x] - minHeight) * step + 0.5f);
589 map.heightMapSize+= sizeof(uint8_V9) + sizeof(uint8_V8);
590 }
591 else if (heightHeader.flags&MAP_HEIGHT_AS_INT16)
592 {
593 for (int y=0; y<ADT_GRID_SIZE; y++)
594 for(int x=0;x<ADT_GRID_SIZE;x++)
595 uint16_V8[y][x] = uint16((V8[y][x] - minHeight) * step + 0.5f);
596 for (int y=0; y<=ADT_GRID_SIZE; y++)
597 for(int x=0;x<=ADT_GRID_SIZE;x++)
598 uint16_V9[y][x] = uint16((V9[y][x] - minHeight) * step + 0.5f);
599 map.heightMapSize+= sizeof(uint16_V9) + sizeof(uint16_V8);
600 }
601 else
602 map.heightMapSize+= sizeof(V9) + sizeof(V8);
603 }
604
605 // Get from MCLQ chunk (old)
606 for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
607 {
608 for(int j = 0; j < ADT_CELLS_PER_GRID; j++)
609 {
610 adt_MCNK *cell = cells->getMCNK(i, j);
611 if (!cell)
612 continue;
613
614 adt_MCLQ *liquid = cell->getMCLQ();
615 int count = 0;
616 if (!liquid || cell->sizeMCLQ <= 8)
617 continue;
618
619 for (int y = 0; y < ADT_CELL_SIZE; y++)
620 {
621 int cy = i * ADT_CELL_SIZE + y;
622 for (int x = 0; x < ADT_CELL_SIZE; x++)
623 {
624 int cx = j * ADT_CELL_SIZE + x;
625 if (liquid->flags[y][x] != 0x0F)
626 {
627 liquid_show[cy][cx] = true;
628 if (liquid->flags[y][x] & (1<<7))
630 ++count;
631 }
632 }
633 }
634
635 uint32 c_flag = cell->flags;
636 if (c_flag & (1<<2))
637 {
638 liquid_entry[i][j] = 1;
639 liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; // water
640 }
641 if (c_flag & (1<<3))
642 {
643 liquid_entry[i][j] = 2;
644 liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; // ocean
645 }
646 if (c_flag & (1<<4))
647 {
648 liquid_entry[i][j] = 3;
649 liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime
650 }
651
652 if (!count && liquid_flags[i][j])
653 fprintf(stderr, "Wrong liquid detect in MCLQ chunk");
654
655 for (int y = 0; y <= ADT_CELL_SIZE; y++)
656 {
657 int cy = i * ADT_CELL_SIZE + y;
658 for (int x = 0; x <= ADT_CELL_SIZE; x++)
659 {
660 int cx = j * ADT_CELL_SIZE + x;
661 liquid_height[cy][cx] = liquid->liquid[y][x].height;
662 }
663 }
664 }
665 }
666
667 // Get liquid map for grid (in WOTLK used MH2O chunk)
668 adt_MH2O * h2o = adt.a_grid->getMH2O();
669 if (h2o)
670 {
671 for (int32 i = 0; i < ADT_CELLS_PER_GRID; i++)
672 {
673 for (int32 j = 0; j < ADT_CELLS_PER_GRID; j++)
674 {
675 adt_liquid_instance const* h = h2o->GetLiquidInstance(i,j);
676 if (!h)
677 continue;
678
680
681 int32 count = 0;
682 uint64 existsMask = h2o->GetLiquidExistsBitmap(h);
683 for (int32 y = 0; y < h->GetHeight(); y++)
684 {
685 int32 cy = i * ADT_CELL_SIZE + y + h->GetOffsetY();
686 for (int32 x = 0; x < h->GetWidth(); x++)
687 {
688 int32 cx = j * ADT_CELL_SIZE + x + h->GetOffsetX();
689 if (existsMask & 1)
690 {
691 liquid_show[cy][cx] = true;
692 ++count;
693 }
694 existsMask >>= 1;
695 }
696 }
697
698 liquid_entry[i][j] = h->LiquidType;
699 switch (LiquidTypes.at(h->LiquidType).SoundBank)
700 {
705 default:
706 printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->LiquidType, inputPath.c_str(), i, j);
707 break;
708 }
709
710 if (!count && liquid_flags[i][j])
711 printf("Wrong liquid detect in MH2O chunk");
712
713 int32 pos = 0;
714 for (int32 y = 0; y <= h->GetHeight(); y++)
715 {
716 int cy = i * ADT_CELL_SIZE + y + h->GetOffsetY();
717 for (int32 x = 0; x <= h->GetWidth(); x++)
718 {
719 int32 cx = j * ADT_CELL_SIZE + x + h->GetOffsetX();
720 liquid_height[cy][cx] = h2o->GetLiquidHeight(h, pos);
721 pos++;
722 }
723 }
724 }
725 }
726 }
727 //============================================
728 // Pack liquid data
729 //============================================
730 uint16 firstLiquidType = liquid_entry[0][0];
731 uint8 firstLiquidFlag = liquid_flags[0][0];
732 bool fullType = false;
733 for (int y=0;y<ADT_CELLS_PER_GRID;y++)
734 {
735 for(int x=0;x<ADT_CELLS_PER_GRID;x++)
736 {
737 if (liquid_entry[y][x] != firstLiquidType || liquid_flags[y][x] != firstLiquidFlag)
738 {
739 fullType = true;
741 break;
742 }
743 }
744 }
745
746 map_liquidHeader liquidHeader;
747
748 // no water data (if all grid have 0 liquid type)
749 if (firstLiquidFlag == 0 && !fullType)
750 {
751 // No liquid data
752 map.liquidMapOffset = 0;
753 map.liquidMapSize = 0;
754 }
755 else
756 {
757 int minX = 255, minY = 255;
758 int maxX = 0, maxY = 0;
759 maxHeight = -20000;
760 minHeight = 20000;
761 for (int y=0; y<ADT_GRID_SIZE; y++)
762 {
763 for(int x=0; x<ADT_GRID_SIZE; x++)
764 {
765 if (liquid_show[y][x])
766 {
767 if (minX > x) minX = x;
768 if (maxX < x) maxX = x;
769 if (minY > y) minY = y;
770 if (maxY < y) maxY = y;
771 float h = liquid_height[y][x];
772 if (maxHeight < h) maxHeight = h;
773 if (minHeight > h) minHeight = h;
774 }
775 else
776 {
778 if (minHeight > CONF_use_minHeight) minHeight = CONF_use_minHeight;
779 }
780 }
781 }
783 map.liquidMapSize = sizeof(map_liquidHeader);
784 liquidHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_LIQUID_MAGIC);
785 liquidHeader.flags = 0;
786 liquidHeader.liquidType = 0;
787 liquidHeader.offsetX = minX;
788 liquidHeader.offsetY = minY;
789 liquidHeader.width = maxX - minX + 1 + 1;
790 liquidHeader.height = maxY - minY + 1 + 1;
791 liquidHeader.liquidLevel = minHeight;
792
793 if (maxHeight == minHeight)
794 liquidHeader.flags |= MAP_LIQUID_NO_HEIGHT;
795
796 // Not need store if flat surface
797 if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_liquid_delta_limit)
798 liquidHeader.flags |= MAP_LIQUID_NO_HEIGHT;
799
800 if (!fullType)
801 liquidHeader.flags |= MAP_LIQUID_NO_TYPE;
802
803 if (liquidHeader.flags & MAP_LIQUID_NO_TYPE)
804 {
805 liquidHeader.liquidFlags = firstLiquidFlag;
806 liquidHeader.liquidType = firstLiquidType;
807 }
808 else
809 map.liquidMapSize += sizeof(liquid_entry) + sizeof(liquid_flags);
810
811 if (!(liquidHeader.flags & MAP_LIQUID_NO_HEIGHT))
812 map.liquidMapSize += sizeof(float)*liquidHeader.width*liquidHeader.height;
813 }
814
815 bool hasHoles = false;
816
817 for (int i = 0; i < ADT_CELLS_PER_GRID; ++i)
818 {
819 for (int j = 0; j < ADT_CELLS_PER_GRID; ++j)
820 {
821 adt_MCNK * cell = cells->getMCNK(i,j);
822 if (!cell)
823 continue;
824 holes[i][j] = cell->holes;
825 if (!hasHoles && cell->holes != 0)
826 hasHoles = true;
827 }
828 }
829
830 if (hasHoles)
831 {
832 if (map.liquidMapOffset)
834 else
836
837 map.holesSize = sizeof(holes);
838 }
839 else
840 {
841 map.holesOffset = 0;
842 map.holesSize = 0;
843 }
844
845 // Ok all data prepared - store it
846
847 std::ofstream outFile(outputPath, std::ofstream::out | std::ofstream::binary);
848 if (!outFile)
849 {
850 printf("Can't create the output file '%s'\n", outputPath.c_str());
851 return false;
852 }
853
854 outFile.write(reinterpret_cast<char const*>(&map), sizeof(map));
855 // Store area data
856 outFile.write(reinterpret_cast<char const*>(&areaHeader), sizeof(areaHeader));
857 if (!(areaHeader.flags & MAP_AREA_NO_AREA))
858 outFile.write(reinterpret_cast<char const*>(area_ids), sizeof(area_ids));
859
860 // Store height data
861 outFile.write(reinterpret_cast<char const*>(&heightHeader), sizeof(heightHeader));
862 if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
863 {
864 if (heightHeader.flags & MAP_HEIGHT_AS_INT16)
865 {
866 outFile.write(reinterpret_cast<char const*>(uint16_V9), sizeof(uint16_V9));
867 outFile.write(reinterpret_cast<char const*>(uint16_V8), sizeof(uint16_V8));
868 }
869 else if (heightHeader.flags & MAP_HEIGHT_AS_INT8)
870 {
871 outFile.write(reinterpret_cast<char const*>(uint8_V9), sizeof(uint8_V9));
872 outFile.write(reinterpret_cast<char const*>(uint8_V8), sizeof(uint8_V8));
873 }
874 else
875 {
876 outFile.write(reinterpret_cast<char const*>(V9), sizeof(V9));
877 outFile.write(reinterpret_cast<char const*>(V8), sizeof(V8));
878 }
879 }
880
881 if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS)
882 {
883 outFile.write(reinterpret_cast<char*>(flight_box_max), sizeof(flight_box_max));
884 outFile.write(reinterpret_cast<char*>(flight_box_min), sizeof(flight_box_min));
885 }
886
887 // Store liquid data if need
888 if (map.liquidMapOffset)
889 {
890 outFile.write(reinterpret_cast<char const*>(&liquidHeader), sizeof(liquidHeader));
891
892 if (!(liquidHeader.flags&MAP_LIQUID_NO_TYPE))
893 {
894 outFile.write(reinterpret_cast<char const*>(liquid_entry), sizeof(liquid_entry));
895 outFile.write(reinterpret_cast<char const*>(liquid_flags), sizeof(liquid_flags));
896 }
897
898 if (!(liquidHeader.flags&MAP_LIQUID_NO_HEIGHT))
899 {
900 for (int y = 0; y < liquidHeader.height; y++)
901 outFile.write(reinterpret_cast<char const*>(&liquid_height[y + liquidHeader.offsetY][liquidHeader.offsetX]), sizeof(float) * liquidHeader.width);
902 }
903 }
904
905 // store hole data
906 if (hasHoles)
907 outFile.write(reinterpret_cast<char const*>(holes), map.holesSize);
908
909 outFile.close();
910 return true;
911}
912
914{
915 std::string mpqFileName;
916 std::string outputFileName;
917 std::string mpqMapName;
918
919 printf("Extracting maps...\n");
920
922
924
925 std::string path = output_path;
926 path += "/maps/";
927 CreateDir(path);
928
929 printf("Convert map files\n");
930 for(uint32 z = 0; z < map_count; ++z)
931 {
932 printf("Extract %s (%d/%u) \n", map_ids[z].name, z+1, map_count);
933 // Loadup map grid data
934
935 mpqMapName = Trinity::StringFormat("World\\Maps\\{}\\{}.wdt", map_ids[z].name, map_ids[z].name);
936 WDT_file wdt;
937 if (!wdt.loadFile(mpqMapName, false))
938 {
939// printf("Error loading %s map wdt data\n", map_ids[z].name);
940 continue;
941 }
942
943 for(uint32 y = 0; y < WDT_MAP_SIZE; ++y)
944 {
945 for(uint32 x = 0; x < WDT_MAP_SIZE; ++x)
946 {
947 if (!wdt.main->adt_list[y][x].exist)
948 continue;
949
950 mpqFileName = Trinity::StringFormat("World\\Maps\\{}\\{}_{}_{}.adt", map_ids[z].name, map_ids[z].name, x, y);
951 outputFileName = Trinity::StringFormat("{}/maps/{:03}{:02}{:02}.map", output_path, map_ids[z].id, y, x);
952 ConvertADT(mpqFileName, outputFileName, y, x, build);
953 }
954 // draw progress bar
955 printf("Processing........................%d%%\r", (100 * (y+1)) / WDT_MAP_SIZE);
956 }
957 }
958 printf("\n");
959}
960
961bool ExtractFile( char const* mpq_name, std::string const& filename )
962{
963 FILE *output = fopen(filename.c_str(), "wb");
964 if(!output)
965 {
966 printf("Can't create the output file '%s'\n", filename.c_str());
967 return false;
968 }
969 MPQFile m(mpq_name);
970 if(!m.isEof())
971 fwrite(m.getPointer(), 1, m.getSize(), output);
972
973 fclose(output);
974 return true;
975}
976
977void ExtractDBCFiles(int locale, bool basicLocale)
978{
979 printf("Extracting dbc files...\n");
980
981 std::set<std::string> dbcfiles;
982
983 // get DBC file list
984 for(ArchiveSet::iterator i = gOpenArchives.begin(); i != gOpenArchives.end();++i)
985 {
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);
991 }
992
993 std::string path = output_path;
994 path += "/dbc/";
995 CreateDir(path);
996 if(!basicLocale)
997 {
998 path += MpqLocaleNames[locale];
999 path += "/";
1000 CreateDir(path);
1001 }
1002
1003 // extract Build info file
1004 {
1005 std::string mpq_name = Trinity::StringFormat("component.wow-{}.txt", MpqLocaleNames[locale]);
1006 std::string filename = path + mpq_name;
1007
1008 ExtractFile(mpq_name.c_str(), filename);
1009 }
1010
1011 // extract DBCs
1012 uint32 count = 0;
1013 for (std::set<std::string>::iterator iter = dbcfiles.begin(); iter != dbcfiles.end(); ++iter)
1014 {
1015 std::string filename = path;
1016 filename += (iter->c_str() + strlen("DBFilesClient\\"));
1017
1018 if (boost::filesystem::exists(filename))
1019 continue;
1020
1021 if (ExtractFile(iter->c_str(), filename))
1022 ++count;
1023 }
1024 printf("Extracted %u DBC files\n\n", count);
1025}
1026
1027void ExtractCameraFiles(int locale, bool basicLocale)
1028{
1029 printf("Extracting camera files...\n");
1030 DBCFile camdbc("DBFilesClient\\CinematicCamera.dbc");
1031
1032 if (!camdbc.open())
1033 {
1034 printf("Unable to open CinematicCamera.dbc. Camera extract aborted.\n");
1035 return;
1036 }
1037
1038 // get camera file list from DBC
1039 std::vector<std::string> camerafiles;
1040 size_t cam_count = camdbc.getRecordCount();
1041
1042 for (size_t i = 0; i < cam_count; ++i)
1043 {
1044 std::string camFile(camdbc.getRecord(i).getString(1));
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));
1049 }
1050
1051 std::string path = output_path;
1052 path += "/Cameras/";
1053 CreateDir(path);
1054 if (!basicLocale)
1055 {
1056 path += MpqLocaleNames[locale];
1057 path += "/";
1058 CreateDir(path);
1059 }
1060
1061 // extract M2s
1062 uint32 count = 0;
1063 for (std::string thisFile : camerafiles)
1064 {
1065 std::string filename = path;
1066 filename += (thisFile.c_str() + strlen("Cameras\\"));
1067
1068 if (boost::filesystem::exists(filename))
1069 continue;
1070
1071 if (ExtractFile(thisFile.c_str(), filename))
1072 ++count;
1073 }
1074 printf("Extracted %u camera files\n", count);
1075}
1076
1077int main(int argc, char * arg[])
1078{
1080
1082
1083 Trinity::Banner::Show("Map & DBC Extractor", [](char const* text) { printf("%s\n", text); }, nullptr);
1084
1085 HandleArgs(argc, arg);
1086
1087 int FirstLocale = -1;
1088 uint32 build = 0;
1089
1090 for (std::size_t i = 0; i < MpqLocaleNames.size(); i++)
1091 {
1092 //Open MPQs
1094 continue;
1095
1096 printf("Detected locale: " STRING_VIEW_FMT "\n", STRING_VIEW_FMT_ARG(MpqLocaleNames[i]));
1097
1098 if((CONF_extract & EXTRACT_DBC) == 0)
1099 {
1100 FirstLocale = i;
1101 build = ReadBuild(FirstLocale);
1102 printf("Detected client build: %u\n\n", build);
1103 break;
1104 }
1105
1106 //Extract DBC files
1107 if(FirstLocale < 0)
1108 {
1109 FirstLocale = i;
1110 build = ReadBuild(FirstLocale);
1111 printf("Detected client build: %u\n\n", build);
1112 ExtractDBCFiles(i, true);
1113 }
1114 else
1115 ExtractDBCFiles(i, false);
1116
1117 //Close MPQs
1119 }
1120
1121 if(FirstLocale < 0)
1122 {
1123 printf("No locales detected\n");
1124 return 0;
1125 }
1126
1128 {
1129 printf("Using locale: " STRING_VIEW_FMT "\n", STRING_VIEW_FMT_ARG(MpqLocaleNames[FirstLocale]));
1130
1131 // Open MPQs
1133
1134 ExtractCameraFiles(FirstLocale, true);
1135 // Close MPQs
1137 }
1138
1140 {
1141 printf("Using locale: " STRING_VIEW_FMT "\n", STRING_VIEW_FMT_ARG(MpqLocaleNames[FirstLocale]));
1142
1143 // Open MPQs
1145
1146 // Extract maps
1147 ExtractMapsFromMpq(build);
1148
1149 // Close MPQs
1151 }
1152
1153 return 0;
1154}
1155
1156#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
1157#include "WheatyExceptionReport.h"
1158// must be at end of file because of init_seg pragma
1160#endif
uint8_t uint8
Definition Define.h:135
#define STRING_VIEW_FMT_ARG(str)
Definition Define.h:126
int16_t int16
Definition Define.h:130
#define STRING_VIEW_FMT
Definition Define.h:125
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#define SZFMTD
Definition Define.h:123
float selectUInt8StepStore(float maxDiff)
Definition System.cpp:323
float CONF_float_to_int8_limit
Definition System.cpp:76
uint16 uint16_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition System.cpp:337
bool ConvertADT(std::string const &inputPath, std::string const &outputPath, int, int, uint32 build)
Definition System.cpp:351
uint16 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition System.cpp:346
#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS
Definition System.cpp:289
bool CONF_allow_height_limit
Definition System.cpp:71
std::vector< map_id > map_ids
Definition System.cpp:52
#define MAP_LIQUID_TYPE_MAGMA
Definition System.cpp:302
#define MAP_HEIGHT_AS_INT8
Definition System.cpp:288
char input_path[MAX_PATH_LENGTH]
Definition System.cpp:56
void HandleArgs(int argc, char *arg[])
Definition System.cpp:106
#define MAP_AREA_NO_AREA
Definition System.cpp:277
bool CONF_allow_float_to_int
Definition System.cpp:75
bool ExtractFile(char const *mpq_name, std::string const &filename)
Definition System.cpp:961
static char const * MAP_AREA_MAGIC
Definition System.cpp:258
void CreateDir(boost::filesystem::path const &path)
Definition System.cpp:83
#define MAP_LIQUID_NO_TYPE
Definition System.cpp:307
std::unordered_map< uint32, LiquidTypeEntry > LiquidTypes
Definition System.cpp:53
#define MAP_LIQUID_NO_HEIGHT
Definition System.cpp:308
uint16 uint16_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition System.cpp:338
#define MAP_LIQUID_TYPE_WATER
Definition System.cpp:300
static char const * MAP_MAGIC
Definition System.cpp:256
#define MAP_LIQUID_TYPE_DARK_WATER
Definition System.cpp:305
float CONF_flat_liquid_delta_limit
Definition System.cpp:79
#define MAP_LIQUID_TYPE_OCEAN
Definition System.cpp:301
float CONF_use_minHeight
Definition System.cpp:72
uint16 liquid_entry[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition System.cpp:342
char output_path[MAX_PATH_LENGTH]
Definition System.cpp:55
static uint32 const MAP_VERSION_MAGIC
Definition System.cpp:257
int16 flight_box_min[3][3]
Definition System.cpp:349
float selectUInt16StepStore(float maxDiff)
Definition System.cpp:328
Extract
Definition System.cpp:62
@ EXTRACT_CAMERA
Definition System.cpp:65
@ EXTRACT_MAP
Definition System.cpp:63
@ EXTRACT_DBC
Definition System.cpp:64
uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition System.cpp:333
static char const * MAP_LIQUID_MAGIC
Definition System.cpp:260
int16 flight_box_max[3][3]
Definition System.cpp:348
#define MAX_PATH_LENGTH
Definition System.cpp:54
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition System.cpp:345
#define MAP_LIQUID_TYPE_SLIME
Definition System.cpp:303
#define MAP_HEIGHT_NO_HEIGHT
Definition System.cpp:286
void ExtractMapsFromMpq(uint32 build)
Definition System.cpp:913
void ExtractDBCFiles(int locale, bool basicLocale)
Definition System.cpp:977
uint32 ReadMapDBC()
Definition System.cpp:200
uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition System.cpp:343
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition System.cpp:335
int CONF_extract
Definition System.cpp:69
uint8 uint8_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition System.cpp:340
int main(int argc, char *arg[])
Definition System.cpp:1077
static constexpr std::array< std::string_view, 12 > MpqLocaleNames
Definition System.cpp:81
uint32 ReadBuild(int locale)
Definition System.cpp:163
void ReadLiquidTypeTableDBC()
Definition System.cpp:232
void Usage(char const *prg)
Definition System.cpp:93
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition System.cpp:336
static char const * MAP_HEIGHT_MAGIC
Definition System.cpp:259
float CONF_float_to_int16_limit
Definition System.cpp:77
#define MAP_HEIGHT_AS_INT16
Definition System.cpp:287
uint8 uint8_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition System.cpp:339
bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition System.cpp:344
INIT_CRASH_HANDLER()
void ExtractCameraFiles(int locale, bool basicLocale)
Definition System.cpp:1027
float CONF_flat_height_delta_limit
Definition System.cpp:78
#define ADT_CELL_SIZE
Definition adt.h:39
@ LIQUID_TYPE_WATER
Definition adt.h:29
@ LIQUID_TYPE_SLIME
Definition adt.h:32
@ LIQUID_TYPE_MAGMA
Definition adt.h:31
@ LIQUID_TYPE_OCEAN
Definition adt.h:30
#define ADT_GRID_SIZE
Definition adt.h:40
#define ADT_CELLS_PER_GRID
Definition adt.h:38
adt_MHDR * a_grid
Definition adt.h:395
char const * getString(size_t field) const
Definition dbcfile.h:70
unsigned int getUInt(size_t field) const
Definition dbcfile.h:60
Record getRecord(size_t id)
Definition dbcfile.cpp:69
bool open()
Definition dbcfile.cpp:27
size_t getRecordCount() const
Trivial.
Definition dbcfile.h:123
bool loadFile(std::string const &fileName, bool log=true)
Definition loadlib.cpp:40
size_t getSize()
Definition mpq_libmpq.h:87
char * getPointer()
Definition mpq_libmpq.h:90
bool isEof()
Definition mpq_libmpq.h:91
void close()
Definition wdt.h:64
wdt_MAIN * main
Definition wdt.h:73
adt_MCNK * getMCNK(int x, int y)
Definition adt.h:168
Definition adt.h:64
struct adt_MCLQ::liquid_data liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1]
uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE]
Definition adt.h:84
Definition adt.h:93
uint32 sizeMCLQ
Definition adt.h:125
adt_MCVT * getMCVT()
Definition adt.h:134
uint32 holes
Definition adt.h:115
adt_MCLQ * getMCLQ()
Definition adt.h:140
uint32 flags
Definition adt.h:100
uint32 areaid
Definition adt.h:113
float ypos
Definition adt.h:128
Definition adt.h:48
float height_map[(ADT_CELL_SIZE+1) *(ADT_CELL_SIZE+1)+ADT_CELL_SIZE *ADT_CELL_SIZE]
Definition adt.h:55
adt_liquid_attributes GetLiquidAttributes(int32 x, int32 y) const
Definition adt.h:235
adt_liquid_instance const * GetLiquidInstance(int32 x, int32 y) const
Definition adt.h:228
float GetLiquidHeight(adt_liquid_instance const *h, int32 pos) const
Definition adt.h:254
uint64 GetLiquidExistsBitmap(adt_liquid_instance const *h) const
Definition adt.h:310
adt_MFBO * getMFBO()
Definition adt.h:380
adt_MCIN * getMCIN()
Definition adt.h:370
adt_MH2O * getMH2O()
Definition adt.h:374
struct wdt_MAIN::adtData adt_list[64][64]
ArchiveSet gOpenArchives
void CloseArchives()
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)())
Definition Banner.cpp:22
TC_COMMON_API void Init()
Definition Locales.cpp:27
TC_COMMON_API void VerifyOsVersion()
Definition Util.cpp:34
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
uint8 SoundBank
Definition System.cpp:49
uint8 GetWidth() const
Definition adt.h:198
uint8 GetOffsetX() const
Definition adt.h:196
uint16 LiquidType
Definition adt.h:185
uint8 GetHeight() const
Definition adt.h:199
uint8 GetOffsetY() const
Definition adt.h:197
uint32 fourcc
Definition Map.h:110
uint16 gridArea
Definition Map.h:112
uint16 flags
Definition Map.h:111
uint32 mapMagic
Definition System.cpp:264
uint32 holesSize
Definition Map.h:103
uint32 liquidMapSize
Definition Map.h:101
uint32 areaMapOffset
Definition Map.h:96
uint32 heightMapSize
Definition Map.h:99
uint32 heightMapOffset
Definition Map.h:98
uint32 buildMagic
Definition System.cpp:266
uint32 holesOffset
Definition Map.h:102
uint32 versionMagic
Definition Map.h:94
uint32 liquidMapOffset
Definition Map.h:100
uint32 areaMapSize
Definition Map.h:97
float gridMaxHeight
Definition Map.h:125
uint32 flags
Definition Map.h:123
float gridHeight
Definition Map.h:124
uint32 fourcc
Definition Map.h:122
uint32 id
Definition System.cpp:44
uint8 offsetX
Definition Map.h:137
uint32 fourcc
Definition Map.h:133
uint8 liquidFlags
Definition Map.h:135
uint8 width
Definition Map.h:139
uint8 height
Definition Map.h:140
uint8 flags
Definition Map.h:134
uint16 liquidType
Definition Map.h:136
uint8 offsetY
Definition Map.h:138
float liquidLevel
Definition Map.h:141
uint32 exist
Definition wdt.h:57
uint32 map_count
#define WDT_MAP_SIZE
Definition wdt.h:25