TrinityCore
Loading...
Searching...
No Matches
M2Stores.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 "M2Stores.h"
19#include "Containers.h"
20#include "DBCStores.h"
21#include "Log.h"
22#include "M2Structure.h"
23#include "Timer.h"
24#include <boost/filesystem/path.hpp>
25#include <G3D/Vector4.h>
26#include <fstream>
27
28typedef std::vector<FlyByCamera> FlyByCameraCollection;
29std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
30
31// Convert the geomoetry from a spline value, to an actual WoW XYZ
32G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector)
33{
34 G3D::Vector3 work;
35 float x = basePosition->x + splineVector->x;
36 float y = basePosition->y + splineVector->y;
37 float z = basePosition->z + splineVector->z;
38 float const distance = sqrt((x * x) + (y * y));
39 float angle = std::atan2(x, y) - DBCPosition->w;
40
41 if (angle < 0)
42 angle += 2 * float(M_PI);
43
44 work.x = DBCPosition->x + (distance * sin(angle));
45 work.y = DBCPosition->y + (distance * cos(angle));
46 work.z = DBCPosition->z + z;
47 return work;
48}
49
50// Number of cameras not used. Multiple cameras never used in 3.3.5
51bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry)
52{
53 char const* buffer = reinterpret_cast<char const*>(header);
54
56 FlyByCameraCollection targetcam;
57
58 G3D::Vector4 DBCData;
59 DBCData.x = dbcentry->Origin.X;
60 DBCData.y = dbcentry->Origin.Y;
61 DBCData.z = dbcentry->Origin.Z;
62 DBCData.w = dbcentry->OriginFacing;
63
64 // Read target locations, only so that we can calculate orientation
65 for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k)
66 {
67 // Extract Target positions
68 if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
69 return false;
70 M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements);
71 if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize)
72 return false;
73 uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements);
74 M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements);
75
76 if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
77 return false;
78 M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements);
79
80 // Read the data for this set
81 uint32 currPos = targArray->offset_elements;
82 for (uint32 i = 0; i < targTsArray->number; ++i)
83 {
84 if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
85 return false;
86 // Translate co-ordinates
87 G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0);
88
89 // Add to vector
90 FlyByCamera thisCam;
91 thisCam.timeStamp = targTimestamps[i];
92 thisCam.locations.Relocate(newPos.x, newPos.y, newPos.z, 0.0f);
93 targetcam.push_back(thisCam);
94 targPositions++;
95 currPos += sizeof(M2SplineKey<G3D::Vector3>);
96 }
97 }
98
99 // Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline)
100 for (uint32 k = 0; k < cam->positions.timestamps.number; ++k)
101 {
102 // Extract Camera positions for this set
103 if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
104 return false;
105 M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements);
106 if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize)
107 return false;
108 uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements);
109 M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements);
110 if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
111 return false;
112 M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements);
113
114 // Read the data for this set
115 uint32 currPos = posArray->offset_elements;
116 for (uint32 i = 0; i < posTsArray->number; ++i)
117 {
118 if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
119 return false;
120 // Translate co-ordinates
121 G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0);
122
123 // Add to vector
124 FlyByCamera thisCam;
125 thisCam.timeStamp = posTimestamps[i];
126 thisCam.locations.Relocate(newPos.x, newPos.y, newPos.z);
127
128 if (targetcam.size() > 0)
129 {
130 // Find the target camera before and after this camera
131 FlyByCamera lastTarget;
132 FlyByCamera nextTarget;
133
134 // Pre-load first item
135 lastTarget = targetcam[0];
136 nextTarget = targetcam[0];
137 for (uint32 j = 0; j < targetcam.size(); ++j)
138 {
139 nextTarget = targetcam[j];
140 if (targetcam[j].timeStamp > posTimestamps[i])
141 break;
142
143 lastTarget = targetcam[j];
144 }
145
146 float x, y, z;
147 lastTarget.locations.GetPosition(x, y, z);
148
149 // Now, the timestamps for target cam and position can be different. So, if they differ we interpolate
150 if (lastTarget.timeStamp != posTimestamps[i])
151 {
152 uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp;
153 uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp;
154 float xDiff = nextTarget.locations.GetPositionX() - lastTarget.locations.GetPositionX();
155 float yDiff = nextTarget.locations.GetPositionY() - lastTarget.locations.GetPositionY();
156 x = lastTarget.locations.GetPositionX() + (xDiff * (float(timeDiffThis) / float(timeDiffTarget)));
157 y = lastTarget.locations.GetPositionY() + (yDiff * (float(timeDiffThis) / float(timeDiffTarget)));
158 }
159 float xDiff = x - thisCam.locations.GetPositionX();
160 float yDiff = y - thisCam.locations.GetPositionY();
161 thisCam.locations.SetOrientation(std::atan2(yDiff, xDiff));
162 }
163
164 cameras.push_back(thisCam);
165 positions++;
166 currPos += sizeof(M2SplineKey<G3D::Vector3>);
167 }
168 }
169
170 sFlyByCameraStore[dbcentry->ID] = cameras;
171 return true;
172}
173
174void LoadM2Cameras(std::string const& dataPath)
175{
176 sFlyByCameraStore.clear();
177 TC_LOG_INFO("server.loading", ">> Loading Cinematic Camera files");
178
179 uint32 oldMSTime = getMSTime();
180 for (CinematicCameraEntry const* dbcentry : sCinematicCameraStore)
181 {
182 std::string filenameWork = dataPath;
183 filenameWork.append(dbcentry->Model);
184
185 // Replace slashes (always to forward slash, because boost!)
186 std::replace(filenameWork.begin(), filenameWork.end(), '\\', '/');
187
188 boost::filesystem::path filename = filenameWork;
189
190 // Convert to native format
191 filename.make_preferred();
192
193 // Replace mdx to .m2
194 filename.replace_extension("m2");
195
196 std::ifstream m2file(filename.string().c_str(), std::ios::in | std::ios::binary);
197 if (!m2file.is_open())
198 continue;
199
200 // Get file size
201 m2file.seekg(0, std::ios::end);
202 std::streamoff fileSize = m2file.tellg();
203
204 // Reject if not at least the size of the header
205 if (static_cast<uint32>(fileSize) < sizeof(M2Header))
206 {
207 TC_LOG_ERROR("server.loading", "Camera file {} is damaged. File is smaller than header size", filename.string());
208 m2file.close();
209 continue;
210 }
211
212 // Read 4 bytes (signature)
213 m2file.seekg(0, std::ios::beg);
214 char fileCheck[5];
215 m2file.read(fileCheck, 4);
216 fileCheck[4] = 0;
217
218 // Check file has correct magic (MD20)
219 if (strcmp(fileCheck, "MD20"))
220 {
221 TC_LOG_ERROR("server.loading", "Camera file {} is damaged. File identifier not found", filename.string());
222 m2file.close();
223 continue;
224 }
225
226 // Now we have a good file, read it all into a vector of char's, then close the file.
227 std::vector<char> buffer(fileSize);
228 m2file.seekg(0, std::ios::beg);
229 if (!m2file.read(buffer.data(), fileSize))
230 {
231 m2file.close();
232 continue;
233 }
234 m2file.close();
235
236 // Read header
237 M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data());
238
239 if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32>(fileSize))
240 {
241 TC_LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string());
242 continue;
243 }
244
245 // Get camera(s) - Main header, then dump them.
246 M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
247 if (!readCamera(cam, fileSize, header, dbcentry))
248 TC_LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string());
249 }
250
251 TC_LOG_INFO("server.loading", ">> Loaded {} cinematic waypoint sets in {} ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
252}
253
254std::vector<FlyByCamera> const* GetFlyByCameras(uint32 cinematicCameraId)
255{
257}
#define M_PI
Definition Common.h:72
DBCStorage< CinematicCameraEntry > sCinematicCameraStore(CinematicCameraEntryfmt)
uint32_t uint32
Definition Define.h:133
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
void LoadM2Cameras(std::string const &dataPath)
Definition M2Stores.cpp:174
std::vector< FlyByCamera > FlyByCameraCollection
Definition M2Stores.cpp:28
std::unordered_map< uint32, FlyByCameraCollection > sFlyByCameraStore
Definition M2Stores.cpp:29
G3D::Vector3 TranslateLocation(G3D::Vector4 const *DBCPosition, G3D::Vector3 const *basePosition, G3D::Vector3 const *splineVector)
Definition M2Stores.cpp:32
bool readCamera(M2Camera const *cam, uint32 buffSize, M2Header const *header, CinematicCameraEntry const *dbcentry)
Definition M2Stores.cpp:51
std::vector< FlyByCamera > const * GetFlyByCameras(uint32 cinematicCameraId)
Definition M2Stores.cpp:254
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:29
DBCPosition3D Origin
uint32 timeStamp
Definition M2Stores.h:27
Position locations
Definition M2Stores.h:28
uint32 offset_elements
uint32_t number
M2Track target_positions
G3D::Vector3 target_position_base
M2Track positions
G3D::Vector3 position_base
uint32 ofsCameras
Definition M2Structure.h:95
M2Array timestamps
M2Array values
void SetOrientation(float orientation)
Definition Position.h:74
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
float GetPositionY() const
Definition Position.h:80
void Relocate(float x, float y)
Definition Position.h:66