TrinityCore
Loading...
Searching...
No Matches
vmapexport.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 "vmapexport.h"
19#include "adtfile.h"
20#include "Banner.h"
21#include "Common.h"
22#include "DB2CascFileSource.h"
24#include "Locales.h"
25#include "MapDefines.h"
26#include "MapUtils.h"
27#include "Memory.h"
28#include "StringConvert.h"
29#include "StringFormat.h"
30#include "ThreadPool.h"
31#include "Util.h"
32#include "VMapDefinitions.h"
33#include "wdtfile.h"
34#include "wmo.h"
35#include <boost/filesystem/directory.hpp>
36#include <boost/filesystem/operations.hpp>
37#include <CascLib.h>
38#include <algorithm>
39#include <map>
40#include <mutex>
41#include <unordered_map>
42#include <vector>
43#include <cstdio>
44
45//-----------------------------------------------------------------------------
46
47std::shared_ptr<CASC::Storage> CascStorage;
48
50{
52};
53
54struct LiquidTypeEntry
55{
56 uint8 MaterialID = 0;
57};
58
59struct MapEntry
60{
61 uint32 Id = 0;
64 std::string Name;
65 std::string Directory;
66
68 bool IsParent = false;
69};
70
71std::unordered_map<uint32, LiquidMaterialEntry> LiquidMaterials;
72std::unordered_map<uint32, LiquidTypeEntry> LiquidTypes;
73std::vector<MapEntry> map_ids;
74boost::filesystem::path input_path;
75bool preciseVectorData = false;
76char const* CascProduct = "wow";
77char const* CascRegion = "eu";
78bool UseRemoteCasc = false;
80uint32 Threads = std::thread::hardware_concurrency();
81
82// Constants
83
84char const* szWorkDirWmo = "./Buildings";
85
86#define CASC_LOCALES_COUNT 17
88{
89 "none", "enUS",
90 "koKR", "unknown",
91 "frFR", "deDE",
92 "zhCN", "esES",
93 "zhTW", "enGB",
94 "enCN", "enTW",
95 "esMX", "ruRU",
96 "ptBR", "itIT",
97 "ptPT"
98};
99
101{
102 CASC_LOCALE_ENUS | CASC_LOCALE_ENGB,
103 CASC_LOCALE_KOKR,
104 CASC_LOCALE_FRFR,
105 CASC_LOCALE_DEDE,
106 CASC_LOCALE_ZHCN,
107 CASC_LOCALE_ZHTW,
108 CASC_LOCALE_ESES,
109 CASC_LOCALE_ESMX,
110 CASC_LOCALE_RURU,
111 0,
112 CASC_LOCALE_PTBR | CASC_LOCALE_PTPT,
113 CASC_LOCALE_ITIT,
114};
115
116bool OpenCascStorage(int locale)
117{
118 try
119 {
120 if (UseRemoteCasc)
121 {
122 boost::filesystem::path const casc_cache_dir(boost::filesystem::canonical(input_path) / "CascCache");
124 if (CascStorage)
125 return true;
126
127 printf("Unable to open remote casc fallback to local casc\n");
128 }
129
130 boost::filesystem::path const storage_dir(boost::filesystem::canonical(input_path) / "Data");
132 if (!CascStorage)
133 {
134 printf("error opening casc storage '%s' locale %s\n", storage_dir.string().c_str(), localeNames[locale]);
135 return false;
136 }
137
138 return true;
139 }
140 catch (std::exception const& error)
141 {
142 printf("error opening casc storage : %s\n", error.what());
143 return false;
144 }
145}
146
148{
149 try
150 {
151 if (UseRemoteCasc)
152 {
153 boost::filesystem::path const casc_cache_dir(boost::filesystem::canonical(input_path) / "CascCache");
154
155 std::unique_ptr<CASC::Storage> storage(CASC::Storage::OpenRemote(casc_cache_dir, 0, CascProduct, CascRegion));
156 if (storage)
157 return CASC_LOCALE_ALL_WOW;
158
159 printf("Unable to open remote casc fallback to local casc\n");
160 }
161
162 boost::filesystem::path const storage_dir(boost::filesystem::canonical(input_path) / "Data");
163 std::unique_ptr<CASC::Storage> storage(CASC::Storage::Open(storage_dir, 0, CascProduct));
164 if (!storage)
165 return false;
166
167 return storage->GetInstalledLocalesMask();
168 }
169 catch (std::exception const& error)
170 {
171 printf("Unable to determine installed locales mask: %s\n", error.what());
172 }
173
174 return 0;
175}
176
177static std::atomic<uint32> UniqueObjectIdGenerator = std::numeric_limits<uint32>::max() - 1;
178static std::mutex UniqueObjectIdsMutex;
179static std::map<std::pair<uint32, uint16>, uint32> UniqueObjectIds;
180
181uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId, bool isWmo)
182{
183 // WMO client ids must be preserved, they are used in DB2 files
184 uint32 newId = isWmo ? clientId : UniqueObjectIdGenerator--;
185 std::scoped_lock lock(UniqueObjectIdsMutex);
186 return UniqueObjectIds.emplace(std::make_pair(clientId, clientDoodadId), newId).first->second;
187}
188
189static std::mutex ExtractedModelsMutex;
190std::unordered_map<std::string, ExtractedModelData> ExtractedModels;
191
192std::pair<ExtractedModelData*, bool> BeginModelExtraction(std::string const& outputName)
193{
194 std::scoped_lock lock(ExtractedModelsMutex);
195 auto [itr, isNew] = ExtractedModels.try_emplace(outputName);
196 return { &itr->second, isNew };
197}
198
199ExtractedModelData const* ExtractSingleWmo(std::string& fname)
200{
201 // Copy files from archive
202 std::string originalName = fname;
203
204 fname = GetPlainName(fname);
205 NormalizeFileName(fname);
206
207 auto [model, shouldExtract] = BeginModelExtraction(fname);
208 if (!shouldExtract)
209 {
210 model->Wait();
211 switch (model->State.load(std::memory_order::relaxed))
212 {
215 return model;
216 default:
217 return nullptr;
218 }
219 }
220
221 auto stateGuard = Trinity::make_unique_ptr_with_deleter<&ExtractedModelData::Fail>(model);
222
223 int p = 0;
224 // Select root wmo files
225 std::size_t rchr = fname.find_last_of('_');
226 if (rchr != std::string::npos)
227 for (std::size_t i = 0; i < 4 && rchr + i < fname.length(); ++i)
228 if (isdigit(fname[rchr + i]))
229 p++;
230
231 if (p == 3)
232 return nullptr;
233
234 bool file_ok = true;
235 WMORoot froot(originalName);
236 if (!froot.open())
237 {
238 printf("Couldn't open RootWmo!!!\n");
239 return nullptr;
240 }
241 std::string szLocalFile = Trinity::StringFormat("{}/{}", szWorkDirWmo, fname);
242 FILE* output = fopen(szLocalFile.c_str(), "wb");
243 if(!output)
244 {
245 printf("couldn't open %s for writing!\n", szLocalFile.c_str());
246 return nullptr;
247 }
248 froot.ConvertToVMAPRootWmo(output);
249 WMODoodadData& doodads = *(model->Doodads = std::make_unique<WMODoodadData>());
250 std::swap(doodads, froot.DoodadData);
251 int Wmo_nVertices = 0;
252 uint32 groupCount = 0;
253 //printf("root has %d groups\n", froot->nGroups);
254 std::vector<WMOGroup> groups;
255 groups.reserve(froot.groupFileDataIDs.size());
256 for (std::size_t i = 0; i < froot.groupFileDataIDs.size(); ++i)
257 {
258 std::string s = Trinity::StringFormat("FILE{:08X}.xxx", froot.groupFileDataIDs[i]);
259 WMOGroup& fgroup = groups.emplace_back(s);
260 if (!fgroup.open(&froot))
261 {
262 printf("Could not open all Group file for: %s\n", fname.c_str());
263 file_ok = false;
264 break;
265 }
266 }
267
268 for (WMOGroup& fgroup : groups)
269 {
270 if (fgroup.ShouldSkip(&froot))
271 continue;
272
273 if (fgroup.mogpFlags2 & 0x80
274 && fgroup.parentOrFirstChildSplitGroupIndex >= 0
275 && size_t(fgroup.parentOrFirstChildSplitGroupIndex) < groups.size())
276 fgroup.groupWMOID = groups[fgroup.parentOrFirstChildSplitGroupIndex].groupWMOID;
277
278 Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, preciseVectorData);
279 ++groupCount;
280 for (uint16 groupReference : fgroup.DoodadReferences)
281 {
282 if (groupReference >= doodads.Spawns.size())
283 continue;
284
285 uint32 doodadNameIndex = doodads.Spawns[groupReference].NameIndex;
286 if (!froot.ValidDoodadNames.contains(doodadNameIndex))
287 continue;
288
289 doodads.References.insert(groupReference);
290 }
291 }
292
293 fseek(output, 8, SEEK_SET); // store the correct no of vertices
294 fwrite(&Wmo_nVertices, sizeof(int), 1, output);
295 // store the correct no of groups
296 fwrite(&groupCount, sizeof(uint32), 1, output);
297 fclose(output);
298
299 if (!Wmo_nVertices && (doodads.Sets.empty() || doodads.References.empty()))
300 file_ok = false;
301
302 // Delete the extracted file in the case of an error or no collision
303 if (!file_ok || !Wmo_nVertices)
304 remove(szLocalFile.c_str());
305
306 if (!file_ok)
307 return nullptr;
308
309 stateGuard->Complete(Wmo_nVertices ? ExtractedModelData::Ok : ExtractedModelData::OkNoCollision);
310 return stateGuard.release();
311}
312
313bool IsLiquidIgnored(uint32 liquidTypeId)
314{
315 if (LiquidTypeEntry const* liquidType = Trinity::Containers::MapGetValuePtr(LiquidTypes, liquidTypeId))
316 if (LiquidMaterialEntry const* liquidMaterial = Trinity::Containers::MapGetValuePtr(LiquidMaterials, liquidType->MaterialID))
317 if (liquidMaterial->Flags.HasFlag(LiquidMaterialFlags::VisualOnly))
318 return true;
319
320 return false;
321}
322
324{
325 std::unordered_map<uint32, WDTFile> wdts;
326 std::map<uint32, std::vector<MapEntry const*>> steps;
327 for (MapEntry const& mapEntry : map_ids)
328 {
329 steps[mapEntry.ChildDepth].push_back(&mapEntry);
330
331 // preload WDTs
332 std::string description = Trinity::StringFormat("WDT for map {} - {} (FileDataID {})", mapEntry.Id, mapEntry.Name, mapEntry.WdtFileDataId);
333 auto itr = wdts.try_emplace(mapEntry.Id, mapEntry.WdtFileDataId, description, mapEntry.Directory, mapEntry.IsParent).first;
334 if (!itr->second.init(mapEntry.Id))
335 wdts.erase(itr);
336 }
337
338 for (auto const& [_, maps] : steps)
339 {
340 Trinity::ThreadPool threadPool(Threads);
341
342 for (MapEntry const* mapEntry : maps)
343 {
344 threadPool.PostWork([mapEntry, &wdts]
345 {
346 if (WDTFile* WDT = Trinity::Containers::MapGetValuePtr(wdts, mapEntry->Id))
347 {
348 int16 parentMapId = mapEntry->ParentMapID;
349 std::vector<WDTFile*> parentWDTs;
350 while (parentMapId >= 0)
351 {
352 parentWDTs.push_back(Trinity::Containers::MapGetValuePtr(wdts, mapEntry->ParentMapID));
353
354 auto parentMapItr = std::ranges::find(map_ids, uint32(parentMapId), &MapEntry::Id);
355 if (parentMapItr == map_ids.end())
356 break;
357
358 parentMapId = parentMapItr->ParentMapID;
359 }
360
361 printf("Processing Map %u\n", mapEntry->Id);
362 for (int32 x = 0; x < 64; ++x)
363 {
364 for (int32 y = 0; y < 64; ++y)
365 {
366 bool success = false;
367 if (ADTFile* ADT = WDT->GetMap(x, y, true))
368 {
369 success = ADT->init(mapEntry->Id, mapEntry->Id);
370 WDT->FreeADT(ADT);
371 }
372
373 if (!success)
374 {
375 for (WDTFile* parentWDT : parentWDTs)
376 {
377 if (ADTFile* ADT = parentWDT->GetMap(x, y, false))
378 {
379 success = ADT->init(mapEntry->Id, mapEntry->ParentMapID);
380 parentWDT->FreeADT(ADT);
381 }
382
383 if (success)
384 break;
385 }
386 }
387 }
388 }
389 printf("Processing Map %u Done\n", mapEntry->Id);
390 }
391 });
392 }
393
394 threadPool.Join();
395 }
396}
397
398void TryLoadDB2(char const* name, DB2CascFileSource* source, DB2FileLoader* db2, DB2FileLoadInfo const* loadInfo)
399{
400 try
401 {
402 db2->Load(source, loadInfo);
403 }
404 catch (std::exception const& e)
405 {
406 printf("Fatal error: Invalid %s file format! %s\n%s\n", name, CASC::HumanReadableCASCError(GetCascError()), e.what());
407 exit(1);
408 }
409}
410
412{
413 printf("Read Map.dbc file... ");
414
415 DB2CascFileSource source(CascStorage, MapLoadInfo::Instance.Meta->FileDataId);
416 DB2FileLoader db2;
417 TryLoadDB2("Map.db2", &source, &db2, &MapLoadInfo::Instance);
418
419 map_ids.reserve(db2.GetRecordCount() + db2.GetRecordCopyCount());
420 std::unordered_map<uint32, std::size_t> idToIndex;
421 for (uint32 x = 0; x < db2.GetRecordCount(); ++x)
422 {
423 DB2Record record = db2.GetRecord(x);
424 if (!record)
425 continue;
426
427 MapEntry& map = map_ids.emplace_back();
428 map.Id = record.GetId();
429 map.WdtFileDataId = record.GetInt32("WdtFileDataID");
430 map.ParentMapID = int16(record.GetUInt16("ParentMapID"));
431 map.Name = record.GetString("MapName");
432 map.Directory = record.GetString("Directory");
433
434 if (map.ParentMapID < 0)
435 map.ParentMapID = int16(record.GetUInt16("CosmeticParentMapID"));
436
437 idToIndex[map.Id] = map_ids.size() - 1;
438 }
439
440 for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x)
441 {
442 DB2RecordCopy copy = db2.GetRecordCopy(x);
443 auto itr = idToIndex.find(copy.SourceRowId);
444 if (itr != idToIndex.end())
445 {
446 MapEntry& map = map_ids.emplace_back(map_ids[itr->second]);
447 map.Id = copy.NewRowId;
448 }
449 }
450
451 // force parent maps to be extracted first
452 for (MapEntry& map : map_ids)
453 {
454 int16 parentMapId = map.ParentMapID;
455 while (parentMapId >= 0)
456 {
457 ++map.ChildDepth;
458
459 MapEntry& parent = map_ids[idToIndex[parentMapId]];
460 parent.IsParent = true;
461
462 parentMapId = parent.ParentMapID;
463 }
464 }
465
466 std::erase_if(map_ids, [](MapEntry const& map) { return !map.WdtFileDataId; });
467
468 printf("Done! (" SZFMTD " maps loaded)\n", map_ids.size());
469}
470
472{
473 printf("Read LiquidMaterial.db2 file...\n");
474
476 DB2FileLoader db2;
477 TryLoadDB2("LiquidMaterial.db2", &source, &db2, &LiquidMaterialLoadInfo::Instance);
478
479 for (uint32 x = 0; x < db2.GetRecordCount(); ++x)
480 {
481 DB2Record record = db2.GetRecord(x);
482 if (!record)
483 continue;
484
485 LiquidMaterialEntry& liquidType = LiquidMaterials[record.GetId()];
486 liquidType.Flags = static_cast<LiquidMaterialFlags>(record.GetUInt32("Flags"));
487 }
488
489 for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x)
491
492 printf("Done! (" SZFMTD " LiquidMaterials loaded)\n", LiquidMaterials.size());
493}
494
496{
497 printf("Read LiquidType.db2 file...\n");
498
500 DB2FileLoader db2;
501 TryLoadDB2("LiquidType.db2", &source, &db2, &LiquidTypeLoadInfo::Instance);
502
503 for (uint32 x = 0; x < db2.GetRecordCount(); ++x)
504 {
505 DB2Record record = db2.GetRecord(x);
506 if (!record)
507 continue;
508
509 LiquidTypeEntry& liquidType = LiquidTypes[record.GetId()];
510 liquidType.MaterialID = record.GetUInt8("MaterialID");
511 }
512
513 for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x)
515
516 printf("Done! (" SZFMTD " LiquidTypes loaded)\n", LiquidTypes.size());
517}
518
519bool processArgv(int argc, char ** argv, const char *versionString)
520{
521 bool result = true;
522 preciseVectorData = false;
523
524 for (int i = 1; i < argc; ++i)
525 {
526 if (strcmp("-s", argv[i]) == 0)
527 {
528 preciseVectorData = false;
529 }
530 else if (strcmp("-d", argv[i]) == 0)
531 {
532 if ((i + 1) < argc)
533 {
534 input_path = boost::filesystem::path(argv[i + 1]);
535 ++i;
536 }
537 else
538 {
539 result = false;
540 }
541 }
542 else if (strcmp("-?", argv[1]) == 0)
543 {
544 result = false;
545 }
546 else if (strcmp("-l", argv[i]) == 0)
547 {
548 preciseVectorData = true;
549 }
550 else if (strcmp("-p", argv[i]) == 0)
551 {
552 if (i + 1 < argc && strlen(argv[i + 1]))
553 CascProduct = argv[++i];
554 else
555 result = false;
556 }
557 else if (strcmp("-c", argv[i]) == 0)
558 {
559 UseRemoteCasc = true;
560 }
561 else if (strcmp("-r", argv[i]) == 0)
562 {
563 if (i + 1 < argc && strlen(argv[i + 1]))
564 CascRegion = argv[++i];
565 else
566 result = false;
567 }
568 else if (strcmp("-dl", argv[i]) == 0)
569 {
570 if (i + 1 < argc && strlen(argv[i + 1]))
571 {
572 for (uint32 l = 0; l < TOTAL_LOCALES; ++l)
573 if (!strcmp(argv[i + 1], localeNames[l]))
574 DbcLocale = 1 << l;
575 i++;
576 }
577 else
578 result = false;
579 }
580 else if (strcmp("--threads", argv[i]) == 0)
581 {
582 if (i + 1 < argc && strlen(argv[i + 1]))
583 Threads = Trinity::StringTo<uint32>(argv[++i]).value_or(std::thread::hardware_concurrency());
584 else
585 result = false;
586 }
587 else
588 {
589 result = false;
590 break;
591 }
592 }
593
594 if (!result)
595 {
596 printf("Extract %s.\n",versionString);
597 printf("%s [-?][-s][-l][-d <path>][-p <product>]\n", argv[0]);
598 printf(" -s : (default) small size (data size optimization), ~500MB less vmap data.\n");
599 printf(" -l : large size, ~500MB more vmap data. (might contain more details)\n");
600 printf(" -d <path>: Path to the vector data source folder.\n");
601 printf(" -p <product>: which installed product to open (wow/wowt/wow_beta)\n");
602 printf(" -c use remote casc\n");
603 printf(" -r set remote casc region - standard: eu\n");
604 printf(" -dl dbc locale\n");
605 printf(" --threads <N> number of threads to use, default: all cpu cores\n");
606 printf(" -? : This message.\n");
607 }
608
609 return result;
610}
611
612static bool RetardCheck()
613{
614 try
615 {
616 if (UseRemoteCasc)
617 return true;
618
619 boost::filesystem::path storageDir(boost::filesystem::canonical(input_path) / "Data");
620 boost::filesystem::directory_iterator end;
621 for (boost::filesystem::directory_iterator itr(storageDir); itr != end; ++itr)
622 {
623 if (itr->path().extension() == ".MPQ")
624 {
625 printf("MPQ files found in Data directory!\n");
626 printf("This tool works only with World of Warcraft: Dragonflight\n");
627 printf("\n");
628 printf("To extract maps for Wrath of the Lich King, rebuild tools using 3.3.5 branch!\n");
629 printf("\n");
630 printf("Press ENTER to exit...\n");
631 getchar();
632 return false;
633 }
634 }
635 }
636 catch (std::exception const& error)
637 {
638 printf("Error checking client version: %s\n", error.what());
639 }
640
641 return true;
642}
643
644int main(int argc, char ** argv)
645{
647
649
650 Trinity::Banner::Show("VMAP data extractor", [](char const* text) { printf("%s\n", text); }, nullptr);
651
652 bool success = true;
653
654 // Use command line arguments, when some
655 if (!processArgv(argc, argv, VMAP::VMAP_MAGIC))
656 return 1;
657
658 if (!RetardCheck())
659 return 1;
660
661 // some simple check if working dir is dirty
662 boost::filesystem::path sdir_bin = boost::filesystem::path(szWorkDirWmo) / "dir_bin";
663 {
664 boost::system::error_code ec;
665 if (boost::filesystem::exists(sdir_bin, ec) && !boost::filesystem::is_empty(sdir_bin, ec))
666 {
667 printf("Your output directory seems to be polluted, please use an empty directory!\n");
668 printf("<press return to exit>");
669 char garbage[2];
670 return scanf("%c", garbage);
671 }
672 }
673
674 printf("Extract %s. Beginning work ....\n", VMAP::VMAP_MAGIC);
675 //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
676 // Create the working directory
677 success = boost::filesystem::create_directories(sdir_bin) || boost::filesystem::is_directory(sdir_bin);
678
679 uint32 installedLocalesMask = GetInstalledLocalesMask();
680 int32 FirstLocale = -1;
681 for (int i = 0; i < TOTAL_LOCALES; ++i)
682 {
683 if (DbcLocale && !(DbcLocale & (1 << i)))
684 continue;
685
686 if (i == LOCALE_none)
687 continue;
688
689 if (!(installedLocalesMask & WowLocaleToCascLocaleFlags[i]))
690 continue;
691
692 if (!OpenCascStorage(i))
693 continue;
694
695 FirstLocale = i;
696 uint32 build = CascStorage->GetBuildNumber();
697 if (!build)
698 {
699 CascStorage.reset();
700 continue;
701 }
702
703 printf("Detected client build %u for locale %s\n\n", build, localeNames[i]);
704 break;
705 }
706
707 if (FirstLocale == -1)
708 {
709 printf("FATAL ERROR: No locales defined, unable to continue.\n");
710 return 1;
711 }
712
713 // Extract models, listed in GameObjectDisplayInfo.dbc
715
716 //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
717 //map.dbc
718 if (success)
719 {
720 ReadMapTable();
723 ParsMapFiles();
724 }
725
726 CascStorage.reset();
727
728 printf("\n");
729 if (!success)
730 {
731 printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n", VMAP::VMAP_MAGIC, preciseVectorData);
732 getchar();
733 }
734
735 printf("Extract %s. Work complete. No errors.\n", VMAP::VMAP_MAGIC);
736 return 0;
737}
738
739#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
741// must be at end of file because of init_seg pragma
743#endif
char const * localeNames[TOTAL_LOCALES]
Definition Common.cpp:20
@ LOCALE_none
Definition Common.h:61
@ TOTAL_LOCALES
Definition Common.h:65
uint8_t uint8
Definition Define.h:156
int16_t int16
Definition Define.h:151
int32_t int32
Definition Define.h:150
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
#define SZFMTD
Definition Define.h:144
LiquidMaterialFlags
Definition MapDefines.h:112
void NormalizeFileName(std::string &name)
Definition adtfile.cpp:39
std::string_view GetPlainName(std::string_view fileName)
Definition adtfile.cpp:29
static Storage * Open(boost::filesystem::path const &path, uint32 localeMask, char const *product)
static Storage * OpenRemote(boost::filesystem::path const &path, uint32 localeMask, char const *product, char const *region)
void Load(DB2FileSource *source, DB2FileLoadInfo const *loadInfo)
DB2Record GetRecord(uint32 recordNumber) const
DB2RecordCopy GetRecordCopy(uint32 copyNumber) const
uint32 GetRecordCopyCount() const
uint32 GetRecordCount() const
int32 GetInt32(uint32 field, uint32 arrayIndex) const
uint32 GetUInt32(uint32 field, uint32 arrayIndex) const
uint16 GetUInt16(uint32 field, uint32 arrayIndex) const
uint8 GetUInt8(uint32 field, uint32 arrayIndex) const
uint32 GetId() const
char const * GetString(uint32 field, uint32 arrayIndex) const
decltype(auto) PostWork(T &&work)
Definition ThreadPool.h:35
bool open(WMORoot *rootWMO)
Definition wmo.cpp:216
Definition wmo.h:80
WMODoodadData DoodadData
Definition wmo.h:91
std::vector< uint32 > groupFileDataIDs
Definition wmo.h:93
bool open()
Definition wmo.cpp:40
std::unordered_set< uint32 > ValidDoodadNames
Definition wmo.h:92
bool ConvertToVMAPRootWmo(FILE *output)
Definition wmo.cpp:189
void ExtractGameobjectModels()
Definition adtfile.h:27
char const * HumanReadableCASCError(uint32 error)
TC_COMMON_API void Show(char const *applicationName, void(*log)(char const *text), void(*logExtraInfo)())
Definition Banner.cpp:22
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
TC_COMMON_API void Init()
Definition Locales.cpp:28
TC_COMMON_API void VerifyOsVersion()
Definition Util.cpp:35
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
const char VMAP_MAGIC[]
Definition wdtfile.h:30
EnumFlag< LiquidMaterialFlags > Flags
Definition System.cpp:63
static constexpr DB2FileLoadInfo Instance
static constexpr DB2LoadInfo Instance
uint32 Id
Definition System.cpp:55
uint32 ChildDepth
bool IsParent
char const * Directory
int32 WdtFileDataId
Definition System.cpp:56
std::string Name
Definition System.cpp:57
int16 ParentMapID
static constexpr DB2LoadInfo Instance
std::unordered_set< uint16 > References
Definition wmo.h:76
std::vector< WMO::MODS > Sets
Definition wmo.h:72
std::vector< WMO::MODD > Spawns
Definition wmo.h:75
uint32 GetInstalledLocalesMask()
static std::mutex ExtractedModelsMutex
static bool RetardCheck()
bool preciseVectorData
bool UseRemoteCasc
static std::map< std::pair< uint32, uint16 >, uint32 > UniqueObjectIds
static std::atomic< uint32 > UniqueObjectIdGenerator
int main(int argc, char **argv)
std::shared_ptr< CASC::Storage > CascStorage
bool IsLiquidIgnored(uint32 liquidTypeId)
static std::mutex UniqueObjectIdsMutex
char const * CascLocaleNames[CASC_LOCALES_COUNT]
void ParsMapFiles()
std::unordered_map< uint32, LiquidTypeEntry > LiquidTypes
char const * CascProduct
uint32 DbcLocale
uint32 WowLocaleToCascLocaleFlags[12]
boost::filesystem::path input_path
void ReadLiquidMaterialTable()
bool processArgv(int argc, char **argv, const char *versionString)
void ReadMapTable()
std::unordered_map< std::string, ExtractedModelData > ExtractedModels
std::unordered_map< uint32, LiquidMaterialEntry > LiquidMaterials
uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId, bool isWmo)
char const * CascRegion
bool OpenCascStorage(int locale)
std::vector< MapEntry > map_ids
void TryLoadDB2(char const *name, DB2CascFileSource *source, DB2FileLoader *db2, DB2FileLoadInfo const *loadInfo)
ExtractedModelData const * ExtractSingleWmo(std::string &fname)
void ReadLiquidTypeTable()
#define CASC_LOCALES_COUNT
char const * szWorkDirWmo
uint32 Threads
std::pair< ExtractedModelData *, bool > BeginModelExtraction(std::string const &outputName)
INIT_CRASH_HANDLER()