TrinityCore
Loading...
Searching...
No Matches
PathGenerator.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 "Banner.h"
19#include "DBCFileLoader.h"
20#include "Locales.h"
21#include "MapBuilder.h"
22#include "PathCommon.h"
23#include "Timer.h"
24#include "Util.h"
25#include <boost/filesystem.hpp>
26#include <unordered_map>
27
28constexpr char Readme[] =
29{
30#include "Info/readme.txt"
31};
32
33using namespace MMAP;
34
35namespace
36{
37 std::unordered_map<uint32, uint8> _liquidTypes;
38}
39
41{
42 auto itr = _liquidTypes.find(liquidId);
43 return itr != _liquidTypes.end() ? (1 << itr->second) : 0;
44}
45
46bool checkDirectories(bool debugOutput)
47{
48 std::vector<std::string> dirFiles;
49
50 if (getDirContents(dirFiles, "maps") == LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
51 {
52 printf("'maps' directory is empty or does not exist\n");
53 return false;
54 }
55
56 dirFiles.clear();
57 if (getDirContents(dirFiles, "vmaps", "*.vmtree") == LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
58 {
59 printf("'vmaps' directory is empty or does not exist\n");
60 return false;
61 }
62
63 dirFiles.clear();
64 if (getDirContents(dirFiles, "mmaps") == LISTFILE_DIRECTORY_NOT_FOUND)
65 return boost::filesystem::create_directory("mmaps");
66
67 dirFiles.clear();
68 if (debugOutput)
69 {
70 if (getDirContents(dirFiles, "meshes") == LISTFILE_DIRECTORY_NOT_FOUND)
71 {
72 printf("'meshes' directory does not exist (no place to put debugOutput files)\n");
73 return false;
74 }
75 }
76
77 return true;
78}
79
80int finish(char const* message, int returnValue)
81{
82 printf("%s", message);
83 getchar(); // Wait for user input
84 return returnValue;
85}
86
87bool handleArgs(int argc, char** argv,
88 int &mapnum,
89 int &tileX,
90 int &tileY,
91 Optional<float>& maxAngle,
92 Optional<float>& maxAngleNotSteep,
93 bool &skipLiquid,
94 bool &skipContinents,
95 bool &skipJunkMaps,
96 bool &skipBattlegrounds,
97 bool &debugOutput,
98 bool &silent,
99 bool &bigBaseUnit,
100 char* &offMeshInputPath,
101 char* &file,
102 unsigned int& threads)
103{
104 char* param = nullptr;
105 [[maybe_unused]] bool allowDebug = false;
106 for (int i = 1; i < argc; ++i)
107 {
108 if (strcmp(argv[i], "--maxAngle") == 0)
109 {
110 param = argv[++i];
111 if (!param)
112 return false;
113
114 float maxangle = atof(param);
115 if (maxangle <= 90.f && maxangle >= 0.f)
116 maxAngle = maxangle;
117 else
118 printf("invalid option for '--maxAngle', using default\n");
119 }
120 else if (strcmp(argv[i], "--maxAngleNotSteep") == 0)
121 {
122 param = argv[++i];
123 if (!param)
124 return false;
125
126 float maxangle = atof(param);
127 if (maxangle <= 90.f && maxangle >= 0.f)
128 maxAngleNotSteep = maxangle;
129 else
130 printf("invalid option for '--maxAngleNotSteep', using default\n");
131 }
132 else if (strcmp(argv[i], "--threads") == 0)
133 {
134 param = argv[++i];
135 if (!param)
136 return false;
137 threads = static_cast<unsigned int>(std::max(0, atoi(param)));
138 }
139 else if (strcmp(argv[i], "--file") == 0)
140 {
141 param = argv[++i];
142 if (!param)
143 return false;
144 file = param;
145 }
146 else if (strcmp(argv[i], "--tile") == 0)
147 {
148 param = argv[++i];
149 if (!param)
150 return false;
151
152 char* stileX = strtok(param, ",");
153 char* stileY = strtok(nullptr, ",");
154 int tilex = atoi(stileX);
155 int tiley = atoi(stileY);
156
157 if ((tilex > 0 && tilex < 64) || (tilex == 0 && strcmp(stileX, "0") == 0))
158 tileX = tilex;
159 if ((tiley > 0 && tiley < 64) || (tiley == 0 && strcmp(stileY, "0") == 0))
160 tileY = tiley;
161
162 if (tileX < 0 || tileY < 0)
163 {
164 printf("invalid tile coords.\n");
165 return false;
166 }
167 }
168 else if (strcmp(argv[i], "--skipLiquid") == 0)
169 {
170 param = argv[++i];
171 if (!param)
172 return false;
173
174 if (strcmp(param, "true") == 0)
175 skipLiquid = true;
176 else if (strcmp(param, "false") == 0)
177 skipLiquid = false;
178 else
179 printf("invalid option for '--skipLiquid', using default\n");
180 }
181 else if (strcmp(argv[i], "--skipContinents") == 0)
182 {
183 param = argv[++i];
184 if (!param)
185 return false;
186
187 if (strcmp(param, "true") == 0)
188 skipContinents = true;
189 else if (strcmp(param, "false") == 0)
190 skipContinents = false;
191 else
192 printf("invalid option for '--skipContinents', using default\n");
193 }
194 else if (strcmp(argv[i], "--skipJunkMaps") == 0)
195 {
196 param = argv[++i];
197 if (!param)
198 return false;
199
200 if (strcmp(param, "true") == 0)
201 skipJunkMaps = true;
202 else if (strcmp(param, "false") == 0)
203 skipJunkMaps = false;
204 else
205 printf("invalid option for '--skipJunkMaps', using default\n");
206 }
207 else if (strcmp(argv[i], "--skipBattlegrounds") == 0)
208 {
209 param = argv[++i];
210 if (!param)
211 return false;
212
213 if (strcmp(param, "true") == 0)
214 skipBattlegrounds = true;
215 else if (strcmp(param, "false") == 0)
216 skipBattlegrounds = false;
217 else
218 printf("invalid option for '--skipBattlegrounds', using default\n");
219 }
220 else if (strcmp(argv[i], "--debugOutput") == 0)
221 {
222 param = argv[++i];
223 if (!param)
224 return false;
225
226 if (strcmp(param, "true") == 0)
227 debugOutput = true;
228 else if (strcmp(param, "false") == 0)
229 debugOutput = false;
230 else
231 printf("invalid option for '--debugOutput', using default true\n");
232 }
233 else if (strcmp(argv[i], "--silent") == 0)
234 {
235 silent = true;
236 }
237 else if (strcmp(argv[i], "--bigBaseUnit") == 0)
238 {
239 param = argv[++i];
240 if (!param)
241 return false;
242
243 if (strcmp(param, "true") == 0)
244 bigBaseUnit = true;
245 else if (strcmp(param, "false") == 0)
246 bigBaseUnit = false;
247 else
248 printf("invalid option for '--bigBaseUnit', using default false\n");
249 }
250 else if (strcmp(argv[i], "--offMeshInput") == 0)
251 {
252 param = argv[++i];
253 if (!param)
254 return false;
255
256 offMeshInputPath = param;
257 }
258 else if (strcmp(argv[i], "--allowDebug") == 0)
259 {
260 allowDebug = true;
261 }
262 else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-?"))
263 {
264 printf("%s\n", Readme);
265 silent = true;
266 return false;
267 }
268 else
269 {
270 int map = atoi(argv[i]);
271 if (map > 0 || (map == 0 && (strcmp(argv[i], "0") == 0)))
272 mapnum = map;
273 else
274 {
275 printf("invalid map id\n");
276 return false;
277 }
278 }
279 }
280
281#ifndef NDEBUG
282 if (!allowDebug)
283 {
284 finish("Build mmaps_generator in RelWithDebInfo or Release mode or it will take hours to complete!!!\nUse '--allowDebug' argument if you really want to run this tool in Debug.\n", -2);
285 silent = true;
286 return false;
287 }
288#endif
289
290 return true;
291}
292
293std::unordered_map<uint32, uint8> LoadLiquid()
294{
295 DBCFileLoader liquidDbc;
296 std::unordered_map<uint32, uint8> liquidData;
297 // format string doesnt matter as long as it has correct length (only used for mapping to structures in worldserver)
298 if (liquidDbc.Load((boost::filesystem::path("dbc") / "LiquidType.dbc").string().c_str(), "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
299 {
300 for (uint32 x = 0; x < liquidDbc.GetNumRows(); ++x)
301 {
302 DBCFileLoader::Record record = liquidDbc.getRecord(x);
303 liquidData[record.getUInt(0)] = record.getUInt(3);
304 }
305 }
306
307 return liquidData;
308}
309
310int main(int argc, char** argv)
311{
313
315
316 Trinity::Banner::Show("MMAP generator", [](char const* text) { printf("%s\n", text); }, nullptr);
317
318 unsigned int threads = std::thread::hardware_concurrency();
319 int mapnum = -1;
320 int tileX = -1, tileY = -1;
321 Optional<float> maxAngle, maxAngleNotSteep;
322 bool skipLiquid = false,
323 skipContinents = false,
324 skipJunkMaps = true,
325 skipBattlegrounds = false,
326 debugOutput = false,
327 silent = false,
328 bigBaseUnit = false;
329 char* offMeshInputPath = nullptr;
330 char* file = nullptr;
331
332 bool validParam = handleArgs(argc, argv, mapnum,
333 tileX, tileY, maxAngle, maxAngleNotSteep,
334 skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
335 debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
336
337 if (!validParam)
338 return silent ? -1 : finish("You have specified invalid parameters", -1);
339
340 if (mapnum == -1 && debugOutput)
341 {
342 if (silent)
343 return -2;
344
345 printf("You have specifed debug output, but didn't specify a map to generate.\n");
346 printf("This will generate debug output for ALL maps.\n");
347 printf("Are you sure you want to continue? (y/n) ");
348 if (getchar() != 'y')
349 return 0;
350 }
351
352 if (!checkDirectories(debugOutput))
353 return silent ? -3 : finish("Press ENTER to close...", -3);
354
355 _liquidTypes = LoadLiquid();
356 if (_liquidTypes.empty())
357 return silent ? -5 : finish("Failed to load LiquidType.dbc", -5);
358
359 MapBuilder builder(maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps,
360 skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath, threads);
361
362 uint32 start = getMSTime();
363 if (file)
364 builder.buildMeshFromFile(file);
365 else if (tileX > -1 && tileY > -1 && mapnum >= 0)
366 builder.buildSingleTile(mapnum, tileX, tileY);
367 else if (mapnum >= 0)
368 builder.buildMaps(uint32(mapnum));
369 else
370 builder.buildMaps({});
371
372 if (!silent)
373 printf("Finished. MMAPS were built in %s\n", secsToTimeString(GetMSTimeDiffToNow(start) / 1000).c_str());
374 return 0;
375}
376
377#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
379// must be at end of file because of init_seg pragma
381#endif
uint32_t uint32
Definition Define.h:133
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
std::string secsToTimeString(uint64 timeInSecs, TimeFormat timeFormat, bool hoursOnly)
Definition Util.cpp:115
uint32 getUInt(size_t field) const
Record getRecord(size_t id)
bool Load(const char *filename, const char *fmt)
uint32 GetNumRows() const
Get begin iterator over records.
void buildMaps(Optional< uint32 > mapID)
void buildMeshFromFile(char *name)
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY)
@ LISTFILE_DIRECTORY_NOT_FOUND
Definition PathCommon.h:74
ListFilesResult getDirContents(std::vector< std::string > &fileList, std::string dirpath=".", std::string filter="*")
Definition PathCommon.h:78
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
int main(int argc, char **argv)
int finish(char const *message, int returnValue)
constexpr char Readme[]
std::unordered_map< uint32, uint8 > LoadLiquid()
uint32 GetLiquidFlags(uint32 liquidId)
bool handleArgs(int argc, char **argv, int &mapnum, int &tileX, int &tileY, Optional< float > &maxAngle, Optional< float > &maxAngleNotSteep, bool &skipLiquid, bool &skipContinents, bool &skipJunkMaps, bool &skipBattlegrounds, bool &debugOutput, bool &silent, bool &bigBaseUnit, char *&offMeshInputPath, char *&file, unsigned int &threads)
bool checkDirectories(bool debugOutput)
INIT_CRASH_HANDLER()