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