TrinityCore
Loading...
Searching...
No Matches
gameobject_extract.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 "DB2CascFileSource.h"
20#include "Errors.h"
22#include "Memory.h"
23#include "StringConvert.h"
24#include "model.h"
25#include "StringFormat.h"
26#include "vmapexport.h"
27#include "VMapDefinitions.h"
28#include <CascLib.h>
29#include <algorithm>
30#include <cstdio>
31#include "advstd.h"
32
33ExtractedModelData const* ExtractSingleModel(std::string& fname)
34{
35 if (fname.length() < 4)
36 return nullptr;
37
38 std::string_view extension = std::string_view(fname).substr(fname.length() - 4, 4);
39 if (StringEqualI(extension, ".mdx"sv) || StringEqualI(extension, ".mdl"sv))
40 fname.replace(fname.length() - 2, 2, "2");
41
42 std::string originalName = fname;
43
44 fname = GetPlainName(fname);
45 NormalizeFileName(fname);
46
47 auto [model, shouldExtract] = BeginModelExtraction(fname);
48 if (!shouldExtract)
49 {
50 model->Wait();
51 return model->State.load(std::memory_order::relaxed) == ExtractedModelData::Ok ? model : nullptr;
52 }
53
54 auto stateGuard = Trinity::make_unique_ptr_with_deleter<&ExtractedModelData::Fail>(model);
55
56 Model mdl(originalName);
57 if (!mdl.open())
58 return nullptr;
59
60 std::string output(szWorkDirWmo);
61 output += "/";
62 output += fname;
63
64 if (!mdl.ConvertToVMAPModel(output.c_str()))
65 return nullptr;
66
67 stateGuard->Complete();
68 return stateGuard.release();
69}
70
71extern std::shared_ptr<CASC::Storage> CascStorage;
72
73bool GetHeaderMagic(std::string const& fileName, std::array<char, 4>* magic)
74{
75 *magic = { };
76 std::unique_ptr<CASC::File> file(CascStorage->OpenFile(fileName.c_str(), CASC_LOCALE_ALL_WOW));
77 if (!file)
78 return false;
79
80 uint32 bytesToRead = uint32(magic->size() * sizeof(std::remove_pointer_t<decltype(magic)>::value_type));
81 uint32 bytesRead = 0;
82 if (!file->ReadFile(magic->data(), bytesToRead, &bytesRead) || bytesRead != bytesToRead)
83 return false;
84
85 return true;
86}
87
89{
90 printf("Extracting GameObject models...\n");
91
93 DB2FileLoader db2;
94 try
95 {
97 }
98 catch (std::exception const& e)
99 {
100 printf("Fatal error: Invalid GameObjectDisplayInfo.db2 file format!\n%s\n", e.what());
101 exit(1);
102 }
103
104 std::string basepath = szWorkDirWmo;
105 basepath += "/";
106
107 std::string modelListPath = basepath + "temp_gameobject_models";
108 FILE* model_list = fopen(modelListPath.c_str(), "wb");
109 if (!model_list)
110 {
111 printf("Fatal error: Could not open file %s\n", modelListPath.c_str());
112 return;
113 }
114
115 fwrite(VMAP::RAW_VMAP_MAGIC, 1, 8, model_list);
116
117 for (uint32 rec = 0; rec < db2.GetRecordCount(); ++rec)
118 {
119 DB2Record record = db2.GetRecord(rec);
120 if (!record)
121 continue;
122
123 uint32 fileId = record.GetUInt32("FileDataID");
124 if (!fileId)
125 continue;
126
127 std::string fileName = Trinity::StringFormat("FILE{:08X}.xxx", fileId);
128 bool result = false;
129 std::array<char, 4> headerRaw;
130 if (!GetHeaderMagic(fileName, &headerRaw))
131 continue;
132
133 std::string_view header(headerRaw.data(), headerRaw.size());
134 if (header == "REVM")
135 {
136 ExtractedModelData const* wmo = ExtractSingleWmo(fileName);
137 result = wmo && wmo->HasCollision();
138 }
139 else if (header == "MD20" || header == "MD21")
140 result = ExtractSingleModel(fileName) != nullptr;
141 else if (header == "BLP2")
142 continue; // broken db2 data
143 else
144 ABORT_MSG("%s header: 0x%X%X%X%X - " STRING_VIEW_FMT, fileName.c_str(),
145 uint32(headerRaw[3]), uint32(headerRaw[2]), uint32(headerRaw[1]), uint32(headerRaw[0]),
146 STRING_VIEW_FMT_ARG(header));
147
148 if (result)
149 {
150 uint32 displayId = record.GetId();
151 uint32 path_length = fileName.length();
152 fwrite(&displayId, sizeof(uint32), 1, model_list);
153 fwrite(&path_length, sizeof(uint32), 1, model_list);
154 fwrite(fileName.c_str(), sizeof(char), path_length, model_list);
155 }
156 }
157
158 fclose(model_list);
159
160 printf("Done!\n");
161}
#define STRING_VIEW_FMT_ARG(str)
Definition Define.h:147
#define STRING_VIEW_FMT
Definition Define.h:146
uint32_t uint32
Definition Define.h:154
#define ABORT_MSG
Definition Errors.h:88
ModelList model_list
TC_COMMON_API bool StringEqualI(std::string_view str1, std::string_view str2)
Definition Util.cpp:849
void NormalizeFileName(std::string &name)
Definition adtfile.cpp:39
std::string_view GetPlainName(std::string_view fileName)
Definition adtfile.cpp:29
void Load(DB2FileSource *source, DB2FileLoadInfo const *loadInfo)
DB2Record GetRecord(uint32 recordNumber) const
uint32 GetRecordCount() const
uint32 GetUInt32(uint32 field, uint32 arrayIndex) const
uint32 GetId() const
Definition model.h:34
bool open()
Definition model.cpp:37
bool ConvertToVMAPModel(char const *outfilename)
Definition model.cpp:88
std::shared_ptr< CASC::Storage > CascStorage
Definition System.cpp:51
ExtractedModelData const * ExtractSingleModel(std::string &fname)
void ExtractGameobjectModels()
bool GetHeaderMagic(std::string const &fileName, std::array< char, 4 > *magic)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
const char RAW_VMAP_MAGIC[]
bool HasCollision() const
Definition vmapexport.h:77
static constexpr DB2LoadInfo Instance
ExtractedModelData const * ExtractSingleWmo(std::string &fname)
char const * szWorkDirWmo
std::pair< ExtractedModelData *, bool > BeginModelExtraction(std::string const &outputName)