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 "adtfile.h"
19#include "Banner.h"
20#include "dbcfile.h"
21#include "StringFormat.h"
22#include "vmapexport.h"
23#include "Locales.h"
24#include "Util.h"
25#include "wdtfile.h"
26#include "wmo.h"
27#include "mpq_libmpq.h"
28#include <boost/filesystem/directory.hpp>
29#include <boost/filesystem/operations.hpp>
30#include <list>
31#include <map>
32#include <unordered_map>
33#include <vector>
34#include <cstdio>
35
36//-----------------------------------------------------------------------------
37
38typedef struct
39{
40 char name[64];
41 unsigned int id;
42}map_id;
43
44std::vector<map_id> map_ids;
46char output_path[128]=".";
47char input_path[1024]=".";
48bool hasInputPathParam = false;
49bool preciseVectorData = false;
50std::unordered_map<std::string, WMODoodadData> WmoDoodads;
51
52// Constants
53static constexpr std::array<std::string_view, 12> MpqLocaleNames = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
54
55char const* szWorkDirWmo = "./Buildings";
56
57std::map<std::pair<uint32, uint16>, uint32> uniqueObjectIds;
58
59uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId)
60{
61 return uniqueObjectIds.emplace(std::make_pair(clientId, clientDoodadId), uniqueObjectIds.size() + 1).first->second;
62}
63
64// Local testing functions
65
66bool FileExists(char const* file)
67{
68 if (FILE* n = fopen(file, "rb"))
69 {
70 fclose(n);
71 return true;
72 }
73 return false;
74}
75
76void strToLower(char* str)
77{
78 while (*str)
79 {
80 *str = tolower(*str);
81 ++str;
82 }
83}
84
85bool ExtractSingleWmo(std::string& fname)
86{
87 // Copy files from archive
88 std::string originalName = fname;
89
90 char* plain_name = GetPlainName(&fname[0]);
91 FixNameCase(plain_name, strlen(plain_name));
92 FixNameSpaces(plain_name, strlen(plain_name));
93 std::string szLocalFile = Trinity::StringFormat("{}/{}", szWorkDirWmo, plain_name);
94
95 if (FileExists(szLocalFile.c_str()))
96 return true;
97
98 int p = 0;
99 // Select root wmo files
100 char const* rchr = strrchr(plain_name, '_');
101 if (rchr != nullptr)
102 {
103 char cpy[4];
104 memcpy(cpy, rchr, 4);
105 for (int i = 0; i < 4; ++i)
106 {
107 int m = cpy[i];
108 if (isdigit(m))
109 p++;
110 }
111 }
112
113 if (p == 3)
114 return true;
115
116 bool file_ok = true;
117 printf("Extracting %s\n", originalName.c_str());
118 WMORoot froot(originalName);
119 if (!froot.open())
120 {
121 printf("Couldn't open RootWmo!!!\n");
122 return true;
123 }
124 FILE *output = fopen(szLocalFile.c_str(),"wb");
125 if(!output)
126 {
127 printf("couldn't open %s for writing!\n", szLocalFile.c_str());
128 return false;
129 }
130 froot.ConvertToVMAPRootWmo(output);
131 WMODoodadData& doodads = WmoDoodads[plain_name];
132 std::swap(doodads, froot.DoodadData);
133 int Wmo_nVertices = 0;
134 uint32 groupCount = 0;
135 //printf("root has %d groups\n", froot->nGroups);
136 if (froot.nGroups !=0)
137 {
138 for (uint32 i = 0; i < froot.nGroups; ++i)
139 {
140 char temp[1024];
141 strncpy(temp, fname.c_str(), 1024);
142 temp[fname.length()-4] = 0;
143
144 WMOGroup fgroup(Trinity::StringFormat("{}_{:03}.wmo", temp, i));
145 if (!fgroup.open(&froot))
146 {
147 printf("Could not open all Group file for: %s\n", plain_name);
148 file_ok = false;
149 break;
150 }
151
152 if (fgroup.ShouldSkip(&froot))
153 continue;
154
155 Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, preciseVectorData);
156 ++groupCount;
157 for (uint16 groupReference : fgroup.DoodadReferences)
158 {
159 if (groupReference >= doodads.Spawns.size())
160 continue;
161
162 uint32 doodadNameIndex = doodads.Spawns[groupReference].NameIndex;
163 if (froot.ValidDoodadNames.find(doodadNameIndex) == froot.ValidDoodadNames.end())
164 continue;
165
166 doodads.References.insert(groupReference);
167 }
168 }
169 }
170
171 fseek(output, 8, SEEK_SET); // store the correct no of vertices
172 fwrite(&Wmo_nVertices,sizeof(int),1,output);
173 // store the correct no of groups
174 fwrite(&groupCount, sizeof(uint32), 1, output);
175 fclose(output);
176
177 // Delete the extracted file in the case of an error
178 if (!file_ok)
179 remove(szLocalFile.c_str());
180 return true;
181}
182
184{
185 //char id_filename[64];
186 for (unsigned int i=0; i<map_count; ++i)
187 {
188 WDTFile WDT(Trinity::StringFormat("World\\Maps\\{}\\{}.wdt", map_ids[i].name, map_ids[i].name).c_str(), map_ids[i].name);
189 if (WDT.init(map_ids[i].id))
190 {
191 printf("Processing Map %u\n[", map_ids[i].id);
192 for (int x=0; x<64; ++x)
193 {
194 for (int y=0; y<64; ++y)
195 {
196 if (ADTFile *ADT = WDT.GetMap(x,y))
197 {
198 //sprintf(id_filename,"%02u %02u %03u",x,y,map_ids[i].id);//!!!!!!!!!
199 ADT->init(map_ids[i].id, x, y);
200 delete ADT;
201 }
202 }
203 printf("#");
204 fflush(stdout);
205 }
206 printf("]\n");
207 }
208 }
209}
210
211bool processArgv(int argc, char ** argv, const char *versionString)
212{
213 bool result = true;
214 hasInputPathParam = false;
215 preciseVectorData = false;
216
217 for(int i = 1; i < argc; ++i)
218 {
219 if(strcmp("-s",argv[i]) == 0)
220 {
221 preciseVectorData = false;
222 }
223 else if(strcmp("-d",argv[i]) == 0)
224 {
225 if((i+1)<argc)
226 {
227 hasInputPathParam = true;
228 strncpy(input_path, argv[i + 1], sizeof(input_path));
229 input_path[sizeof(input_path) - 1] = '\0';
230
231 if (input_path[strlen(input_path) - 1] != '\\' && input_path[strlen(input_path) - 1] != '/')
232 strcat(input_path, "/");
233 ++i;
234 }
235 else
236 {
237 result = false;
238 }
239 }
240 else if(strcmp("-?",argv[1]) == 0)
241 {
242 result = false;
243 }
244 else if(strcmp("-l",argv[i]) == 0)
245 {
246 preciseVectorData = true;
247 }
248 else
249 {
250 result = false;
251 break;
252 }
253 }
254 if(!result)
255 {
256 printf("Extract %s.\n",versionString);
257 printf("%s [-?][-s][-l][-d <path>]\n", argv[0]);
258 printf(" -s : (default) small size (data size optimization), ~500MB less vmap data.\n");
259 printf(" -l : large size, ~500MB more vmap data. (might contain more details)\n");
260 printf(" -d <path>: Path to the vector data source folder.\n");
261 printf(" -? : This message.\n");
262 }
263 return result;
264}
265
266//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
267// Main
268//
269// The program must be run with two command line arguments
270//
271// Arg1 - The source MPQ name (for testing reading and file find)
272// Arg2 - Listfile name
273//
274
275int main(int argc, char ** argv)
276{
278
280
281 Trinity::Banner::Show("VMAP data extractor", [](char const* text) { printf("%s\n", text); }, nullptr);
282
283 bool success = true;
284 const char *versionString = "V4.00 2012_02";
285
286 // Use command line arguments, when some
287 if (!processArgv(argc, argv, versionString))
288 return 1;
289
290 // some simple check if working dir is dirty
291 boost::filesystem::path sdir_bin = boost::filesystem::path(szWorkDirWmo) / "dir_bin";
292 {
293 boost::system::error_code ec;
294 if (boost::filesystem::exists(sdir_bin, ec))
295 {
296 printf("Your output directory seems to be polluted, please use an empty directory!\n");
297 printf("<press return to exit>");
298 char garbage[2];
299 return scanf("%c", garbage);
300 }
301 }
302
303 printf("Extract %s. Beginning work ....\n\n", versionString);
304 //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
305 // Create the working directory
306 success = boost::filesystem::create_directories(szWorkDirWmo) || boost::filesystem::is_directory(szWorkDirWmo);
307
308 auto foundLocale = std::ranges::find_if(MpqLocaleNames, [](std::string_view localeName)
309 {
310 return MPQ::OpenArchives(input_path, localeName);
311 });
312
313 if (foundLocale == MpqLocaleNames.end())
314 {
315 printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n", input_path);
316 return 1;
317 }
318
319 //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
320 //map.dbc
321 if (success)
322 {
323 DBCFile * dbc = new DBCFile("DBFilesClient\\Map.dbc");
324 if (!dbc->open())
325 {
326 delete dbc;
327 printf("FATAL ERROR: Map.dbc not found in data file.\n");
328 return 1;
329 }
330 map_count = dbc->getRecordCount();
331 map_ids.resize(map_count);
332 for (unsigned int x = 0; x < map_count; ++x)
333 {
334 map_ids[x].id = dbc->getRecord(x).getUInt(0);
335
336 char const* map_name = dbc->getRecord(x).getString(1);
337 size_t max_map_name_length = sizeof(map_ids[x].name);
338 if (strlen(map_name) >= max_map_name_length)
339 {
340 delete dbc;
341 printf("FATAL ERROR: Map name too long.\n");
342 return 1;
343 }
344
345 strncpy(map_ids[x].name, map_name, max_map_name_length);
346 map_ids[x].name[max_map_name_length - 1] = '\0';
347 printf("Map - %s\n", map_ids[x].name);
348 }
349
350 delete dbc;
351 ParsMapFiles();
352 //nError = ERROR_SUCCESS;
353 // Extract models, listed in GameObjectDisplayInfo.dbc
355 }
356
357 printf("\n");
358 if (!success)
359 {
360 printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n", versionString, preciseVectorData);
361 getchar();
362 }
363
364 printf("Extract %s. Work complete. No errors.\n", versionString);
365 return 0;
366}
367
368#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
370// must be at end of file because of init_seg pragma
372#endif
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
char const * GetPlainName(char const *FileName)
Definition adtfile.cpp:25
void FixNameCase(char *name, size_t len)
Definition adtfile.cpp:43
void FixNameSpaces(char *name, size_t len)
Definition adtfile.cpp:60
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 init(uint32 mapId)
Definition wdtfile.cpp:39
ADTFile * GetMap(int x, int z)
Definition wdtfile.cpp:123
std::vector< uint16 > DoodadReferences
Definition wmo.h:149
bool open(WMORoot *rootWMO)
Definition wmo.cpp:170
int ConvertToVMAPGroupWmo(FILE *output, bool preciseVectorData)
Definition wmo.cpp:291
bool ShouldSkip(WMORoot const *root) const
Definition wmo.cpp:498
Definition wmo.h:78
WMODoodadData DoodadData
Definition wmo.h:88
bool open()
Definition wmo.cpp:39
uint32 nGroups
Definition wmo.h:83
std::unordered_set< uint32 > ValidDoodadNames
Definition wmo.h:89
bool ConvertToVMAPRootWmo(FILE *output)
Definition wmo.cpp:147
void ExtractGameobjectModels()
Definition adtfile.h:27
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.
std::unordered_set< uint16 > References
Definition wmo.h:74
std::vector< WMO::MODD > Spawns
Definition wmo.h:73
unsigned int id
std::vector< map_id > map_ids
std::unordered_map< std::string, WMODoodadData > WmoDoodads
bool preciseVectorData
int main(int argc, char **argv)
void ParsMapFiles()
bool hasInputPathParam
uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId)
uint32 map_count
char input_path[1024]
std::map< std::pair< uint32, uint16 >, uint32 > uniqueObjectIds
bool FileExists(char const *file)
bool processArgv(int argc, char **argv, const char *versionString)
void strToLower(char *str)
static constexpr std::array< std::string_view, 12 > MpqLocaleNames
char const * szWorkDirWmo
char output_path[128]
INIT_CRASH_HANDLER()
bool ExtractSingleWmo(std::string &fname)