feat(Core/Maps): Improvements to Cinematic function (#10765)
This commit is contained in:
committed by
GitHub
parent
f3e0d4e402
commit
7ad65752fa
@@ -25,8 +25,6 @@
|
|||||||
#include "SpellMgr.h"
|
#include "SpellMgr.h"
|
||||||
#include "TransportMgr.h"
|
#include "TransportMgr.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
typedef std::map<uint16, uint32> AreaFlagByAreaID;
|
typedef std::map<uint16, uint32> AreaFlagByAreaID;
|
||||||
@@ -190,8 +188,6 @@ DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTableEntryfmt);
|
|||||||
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
|
DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
|
||||||
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
|
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
|
||||||
|
|
||||||
std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
|
|
||||||
|
|
||||||
typedef std::list<std::string> StoreProblemList;
|
typedef std::list<std::string> StoreProblemList;
|
||||||
|
|
||||||
uint32 DBCFileCount = 0;
|
uint32 DBCFileCount = 0;
|
||||||
@@ -635,278 +631,10 @@ void LoadDBCStores(const std::string& dataPath)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadM2Cameras(dataPath);
|
|
||||||
|
|
||||||
LOG_INFO("server.loading", ">> Initialized {} data stores in {} ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));
|
LOG_INFO("server.loading", ">> Initialized {} data stores in {} ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime));
|
||||||
LOG_INFO("server.loading", " ");
|
LOG_INFO("server.loading", " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the geomoetry from a spline value, to an actual WoW XYZ
|
|
||||||
G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector)
|
|
||||||
{
|
|
||||||
G3D::Vector3 work;
|
|
||||||
float x = basePosition->x + splineVector->x;
|
|
||||||
float y = basePosition->y + splineVector->y;
|
|
||||||
float z = basePosition->z + splineVector->z;
|
|
||||||
float const distance = std::sqrt((x * x) + (y * y));
|
|
||||||
float angle = std::atan2(x, y) - DBCPosition->w;
|
|
||||||
|
|
||||||
if (angle < 0)
|
|
||||||
{
|
|
||||||
angle += 2 * float(M_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
work.x = DBCPosition->x + (distance * std::sin(angle));
|
|
||||||
work.y = DBCPosition->y + (distance * cos(angle));
|
|
||||||
work.z = DBCPosition->z + z;
|
|
||||||
return work;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number of cameras not used. Multiple cameras never used in 3.3.5
|
|
||||||
bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry)
|
|
||||||
{
|
|
||||||
char const* buffer = reinterpret_cast<char const*>(header);
|
|
||||||
|
|
||||||
FlyByCameraCollection cameras;
|
|
||||||
FlyByCameraCollection targetcam;
|
|
||||||
|
|
||||||
G3D::Vector4 DBCData;
|
|
||||||
DBCData.x = dbcentry->base_x;
|
|
||||||
DBCData.y = dbcentry->base_y;
|
|
||||||
DBCData.z = dbcentry->base_z;
|
|
||||||
DBCData.w = dbcentry->base_o;
|
|
||||||
|
|
||||||
// Read target locations, only so that we can calculate orientation
|
|
||||||
for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k)
|
|
||||||
{
|
|
||||||
// Extract Target positions
|
|
||||||
if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements);
|
|
||||||
if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements);
|
|
||||||
M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements);
|
|
||||||
|
|
||||||
if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements);
|
|
||||||
|
|
||||||
// Read the data for this set
|
|
||||||
uint32 currPos = targArray->offset_elements;
|
|
||||||
for (uint32 i = 0; i < targTsArray->number; ++i)
|
|
||||||
{
|
|
||||||
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Translate co-ordinates
|
|
||||||
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0);
|
|
||||||
|
|
||||||
// Add to vector
|
|
||||||
FlyByCamera thisCam;
|
|
||||||
thisCam.timeStamp = targTimestamps[i];
|
|
||||||
thisCam.locations.x = newPos.x;
|
|
||||||
thisCam.locations.y = newPos.y;
|
|
||||||
thisCam.locations.z = newPos.z;
|
|
||||||
thisCam.locations.w = 0.0f;
|
|
||||||
targetcam.push_back(thisCam);
|
|
||||||
targPositions++;
|
|
||||||
currPos += sizeof(M2SplineKey<G3D::Vector3>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline)
|
|
||||||
for (uint32 k = 0; k < cam->positions.timestamps.number; ++k)
|
|
||||||
{
|
|
||||||
// Extract Camera positions for this set
|
|
||||||
if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements);
|
|
||||||
if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements);
|
|
||||||
M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements);
|
|
||||||
if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements);
|
|
||||||
|
|
||||||
// Read the data for this set
|
|
||||||
uint32 currPos = posArray->offset_elements;
|
|
||||||
for (uint32 i = 0; i < posTsArray->number; ++i)
|
|
||||||
{
|
|
||||||
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Translate co-ordinates
|
|
||||||
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0);
|
|
||||||
|
|
||||||
// Add to vector
|
|
||||||
FlyByCamera thisCam;
|
|
||||||
thisCam.timeStamp = posTimestamps[i];
|
|
||||||
thisCam.locations.x = newPos.x;
|
|
||||||
thisCam.locations.y = newPos.y;
|
|
||||||
thisCam.locations.z = newPos.z;
|
|
||||||
|
|
||||||
if (targetcam.size() > 0)
|
|
||||||
{
|
|
||||||
// Find the target camera before and after this camera
|
|
||||||
FlyByCamera lastTarget;
|
|
||||||
FlyByCamera nextTarget;
|
|
||||||
|
|
||||||
// Pre-load first item
|
|
||||||
lastTarget = targetcam[0];
|
|
||||||
nextTarget = targetcam[0];
|
|
||||||
for (uint32 j = 0; j < targetcam.size(); ++j)
|
|
||||||
{
|
|
||||||
nextTarget = targetcam[j];
|
|
||||||
if (targetcam[j].timeStamp > posTimestamps[i])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTarget = targetcam[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
float x = lastTarget.locations.x;
|
|
||||||
float y = lastTarget.locations.y;
|
|
||||||
// float z = lastTarget.locations.z;
|
|
||||||
|
|
||||||
// Now, the timestamps for target cam and position can be different. So, if they differ we interpolate
|
|
||||||
if (lastTarget.timeStamp != posTimestamps[i])
|
|
||||||
{
|
|
||||||
uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp;
|
|
||||||
uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp;
|
|
||||||
float xDiff = nextTarget.locations.x - lastTarget.locations.x;
|
|
||||||
float yDiff = nextTarget.locations.y - lastTarget.locations.y;
|
|
||||||
// float zDiff = nextTarget.locations.z - lastTarget.locations.z;
|
|
||||||
x = lastTarget.locations.x + (xDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
|
||||||
y = lastTarget.locations.y + (yDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
|
||||||
// z = lastTarget.locations.z + (zDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
|
||||||
}
|
|
||||||
float xDiff = x - thisCam.locations.x;
|
|
||||||
float yDiff = y - thisCam.locations.y;
|
|
||||||
thisCam.locations.w = std::atan2(yDiff, xDiff);
|
|
||||||
|
|
||||||
if (thisCam.locations.w < 0)
|
|
||||||
{
|
|
||||||
thisCam.locations.w += 2 * float(M_PI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cameras.push_back(thisCam);
|
|
||||||
positions++;
|
|
||||||
currPos += sizeof(M2SplineKey<G3D::Vector3>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sFlyByCameraStore[dbcentry->id] = cameras;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadM2Cameras(const std::string& dataPath)
|
|
||||||
{
|
|
||||||
sFlyByCameraStore.clear();
|
|
||||||
LOG_INFO("server.loading", ">> Loading Cinematic Camera files");
|
|
||||||
|
|
||||||
uint32 oldMSTime = getMSTime();
|
|
||||||
for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i)
|
|
||||||
{
|
|
||||||
if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i))
|
|
||||||
{
|
|
||||||
std::string filename = dataPath.c_str();
|
|
||||||
filename.append(dbcentry->filename);
|
|
||||||
|
|
||||||
// Replace slashes
|
|
||||||
size_t loc = filename.find("\\");
|
|
||||||
while (loc != std::string::npos)
|
|
||||||
{
|
|
||||||
filename.replace(loc, 1, "/");
|
|
||||||
loc = filename.find("\\");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace mdx to .m2
|
|
||||||
loc = filename.find(".mdx");
|
|
||||||
if (loc != std::string::npos)
|
|
||||||
{
|
|
||||||
filename.replace(loc, 4, ".m2");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream m2file(filename.c_str(), std::ios::in | std::ios::binary);
|
|
||||||
if (!m2file.is_open())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get file size
|
|
||||||
m2file.seekg(0, std::ios::end);
|
|
||||||
std::streamoff const fileSize = m2file.tellg();
|
|
||||||
|
|
||||||
// Reject if not at least the size of the header
|
|
||||||
if (static_cast<uint32>(fileSize) < sizeof(M2Header))
|
|
||||||
{
|
|
||||||
LOG_ERROR("dbc", "Camera file {} is damaged. File is smaller than header size", filename);
|
|
||||||
m2file.close();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read 4 bytes (signature)
|
|
||||||
m2file.seekg(0, std::ios::beg);
|
|
||||||
char fileCheck[5];
|
|
||||||
m2file.read(fileCheck, 4);
|
|
||||||
fileCheck[4] = 0;
|
|
||||||
|
|
||||||
// Check file has correct magic (MD20)
|
|
||||||
if (strcmp(fileCheck, "MD20"))
|
|
||||||
{
|
|
||||||
LOG_ERROR("dbc", "Camera file {} is damaged. File identifier not found", filename);
|
|
||||||
m2file.close();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we have a good file, read it all into a vector of char's, then close the file.
|
|
||||||
std::vector<char> buffer(fileSize);
|
|
||||||
m2file.seekg(0, std::ios::beg);
|
|
||||||
if (!m2file.read(buffer.data(), fileSize))
|
|
||||||
{
|
|
||||||
m2file.close();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m2file.close();
|
|
||||||
|
|
||||||
// Read header
|
|
||||||
M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data());
|
|
||||||
|
|
||||||
if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32>(fileSize))
|
|
||||||
{
|
|
||||||
LOG_ERROR("dbc", "Camera file {} is damaged. Camera references position beyond file end", filename);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get camera(s) - Main header, then dump them.
|
|
||||||
M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
|
|
||||||
if (!readCamera(cam, fileSize, header, dbcentry))
|
|
||||||
{
|
|
||||||
LOG_ERROR("dbc", "Camera file {} is damaged. Camera references position beyond file end", filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_INFO("server.loading", ">> Loaded {} cinematic waypoint sets in {} ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleFactionsList const* GetFactionTeamList(uint32 faction)
|
SimpleFactionsList const* GetFactionTeamList(uint32 faction)
|
||||||
{
|
{
|
||||||
FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
|
FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction);
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
typedef std::list<uint32> SimpleFactionsList;
|
typedef std::list<uint32> SimpleFactionsList;
|
||||||
typedef std::vector<FlyByCamera> FlyByCameraCollection;
|
|
||||||
|
|
||||||
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
|
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
|
||||||
|
|
||||||
@@ -183,9 +182,7 @@ extern DBCStorage <VehicleSeatEntry> sVehicleSeatStore;
|
|||||||
extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore;
|
extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore;
|
||||||
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
|
//extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
|
||||||
extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
|
extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
|
||||||
extern std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
|
|
||||||
|
|
||||||
void LoadDBCStores(const std::string& dataPath);
|
void LoadDBCStores(const std::string& dataPath);
|
||||||
void LoadM2Cameras(const std::string& dataPath);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DBCStores.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Containers.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "M2Structure.h"
|
||||||
|
#include "M2Stores.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
typedef std::vector<FlyByCamera> FlyByCameraCollection;
|
||||||
|
std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
|
||||||
|
|
||||||
|
// Convert the geomoetry from a spline value, to an actual WoW XYZ
|
||||||
|
G3D::Vector3 TranslateLocation(G3D::Vector4 const* DBCPosition, G3D::Vector3 const* basePosition, G3D::Vector3 const* splineVector)
|
||||||
|
{
|
||||||
|
G3D::Vector3 work;
|
||||||
|
float x = basePosition->x + splineVector->x;
|
||||||
|
float y = basePosition->y + splineVector->y;
|
||||||
|
float z = basePosition->z + splineVector->z;
|
||||||
|
float const distance = std::sqrt((x * x) + (y * y));
|
||||||
|
float angle = std::atan2(x, y) - DBCPosition->w;
|
||||||
|
|
||||||
|
if (angle < 0)
|
||||||
|
angle += 2 * float(M_PI);
|
||||||
|
|
||||||
|
work.x = DBCPosition->x + (distance * sin(angle));
|
||||||
|
work.y = DBCPosition->y + (distance * cos(angle));
|
||||||
|
work.z = DBCPosition->z + z;
|
||||||
|
return work;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of cameras not used. Multiple cameras never used in 3.3.5
|
||||||
|
bool readCamera(M2Camera const* cam, uint32 buffSize, M2Header const* header, CinematicCameraEntry const* dbcentry)
|
||||||
|
{
|
||||||
|
char const* buffer = reinterpret_cast<char const*>(header);
|
||||||
|
|
||||||
|
FlyByCameraCollection cameras;
|
||||||
|
FlyByCameraCollection targetcam;
|
||||||
|
|
||||||
|
G3D::Vector4 DBCData;
|
||||||
|
DBCData.x = dbcentry->Origin.X;
|
||||||
|
DBCData.y = dbcentry->Origin.Y;
|
||||||
|
DBCData.z = dbcentry->Origin.Z;
|
||||||
|
DBCData.w = dbcentry->OriginFacing;
|
||||||
|
|
||||||
|
// Read target locations, only so that we can calculate orientation
|
||||||
|
for (uint32 k = 0; k < cam->target_positions.timestamps.number; ++k)
|
||||||
|
{
|
||||||
|
// Extract Target positions
|
||||||
|
if (cam->target_positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
|
||||||
|
return false;
|
||||||
|
M2Array const* targTsArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.timestamps.offset_elements);
|
||||||
|
if (targTsArray->offset_elements + sizeof(uint32) > buffSize || cam->target_positions.values.offset_elements + sizeof(M2Array) > buffSize)
|
||||||
|
return false;
|
||||||
|
uint32 const* targTimestamps = reinterpret_cast<uint32 const*>(buffer + targTsArray->offset_elements);
|
||||||
|
M2Array const* targArray = reinterpret_cast<M2Array const*>(buffer + cam->target_positions.values.offset_elements);
|
||||||
|
|
||||||
|
if (targArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||||
|
return false;
|
||||||
|
M2SplineKey<G3D::Vector3> const* targPositions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + targArray->offset_elements);
|
||||||
|
|
||||||
|
// Read the data for this set
|
||||||
|
uint32 currPos = targArray->offset_elements;
|
||||||
|
for (uint32 i = 0; i < targTsArray->number; ++i)
|
||||||
|
{
|
||||||
|
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||||
|
return false;
|
||||||
|
// Translate co-ordinates
|
||||||
|
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->target_position_base, &targPositions->p0);
|
||||||
|
|
||||||
|
// Add to vector
|
||||||
|
FlyByCamera thisCam;
|
||||||
|
thisCam.timeStamp = targTimestamps[i];
|
||||||
|
thisCam.locations.Relocate(newPos.x, newPos.y, newPos.z, 0.0f);
|
||||||
|
targetcam.push_back(thisCam);
|
||||||
|
targPositions++;
|
||||||
|
currPos += sizeof(M2SplineKey<G3D::Vector3>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read camera positions and timestamps (translating first position of 3 only, we don't need to translate the whole spline)
|
||||||
|
for (uint32 k = 0; k < cam->positions.timestamps.number; ++k)
|
||||||
|
{
|
||||||
|
// Extract Camera positions for this set
|
||||||
|
if (cam->positions.timestamps.offset_elements + sizeof(M2Array) > buffSize)
|
||||||
|
return false;
|
||||||
|
M2Array const* posTsArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.timestamps.offset_elements);
|
||||||
|
if (posTsArray->offset_elements + sizeof(uint32) > buffSize || cam->positions.values.offset_elements + sizeof(M2Array) > buffSize)
|
||||||
|
return false;
|
||||||
|
uint32 const* posTimestamps = reinterpret_cast<uint32 const*>(buffer + posTsArray->offset_elements);
|
||||||
|
M2Array const* posArray = reinterpret_cast<M2Array const*>(buffer + cam->positions.values.offset_elements);
|
||||||
|
if (posArray->offset_elements + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||||
|
return false;
|
||||||
|
M2SplineKey<G3D::Vector3> const* positions = reinterpret_cast<M2SplineKey<G3D::Vector3> const*>(buffer + posArray->offset_elements);
|
||||||
|
|
||||||
|
// Read the data for this set
|
||||||
|
uint32 currPos = posArray->offset_elements;
|
||||||
|
for (uint32 i = 0; i < posTsArray->number; ++i)
|
||||||
|
{
|
||||||
|
if (currPos + sizeof(M2SplineKey<G3D::Vector3>) > buffSize)
|
||||||
|
return false;
|
||||||
|
// Translate co-ordinates
|
||||||
|
G3D::Vector3 newPos = TranslateLocation(&DBCData, &cam->position_base, &positions->p0);
|
||||||
|
|
||||||
|
// Add to vector
|
||||||
|
FlyByCamera thisCam;
|
||||||
|
thisCam.timeStamp = posTimestamps[i];
|
||||||
|
thisCam.locations.Relocate(newPos.x, newPos.y, newPos.z);
|
||||||
|
|
||||||
|
if (targetcam.size() > 0)
|
||||||
|
{
|
||||||
|
// Find the target camera before and after this camera
|
||||||
|
FlyByCamera lastTarget;
|
||||||
|
FlyByCamera nextTarget;
|
||||||
|
|
||||||
|
// Pre-load first item
|
||||||
|
lastTarget = targetcam[0];
|
||||||
|
nextTarget = targetcam[0];
|
||||||
|
for (uint32 j = 0; j < targetcam.size(); ++j)
|
||||||
|
{
|
||||||
|
nextTarget = targetcam[j];
|
||||||
|
if (targetcam[j].timeStamp > posTimestamps[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
lastTarget = targetcam[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
lastTarget.locations.GetPosition(x, y, z);
|
||||||
|
|
||||||
|
// Now, the timestamps for target cam and position can be different. So, if they differ we interpolate
|
||||||
|
if (lastTarget.timeStamp != posTimestamps[i])
|
||||||
|
{
|
||||||
|
uint32 timeDiffTarget = nextTarget.timeStamp - lastTarget.timeStamp;
|
||||||
|
uint32 timeDiffThis = posTimestamps[i] - lastTarget.timeStamp;
|
||||||
|
float xDiff = nextTarget.locations.GetPositionX() - lastTarget.locations.GetPositionX();
|
||||||
|
float yDiff = nextTarget.locations.GetPositionY() - lastTarget.locations.GetPositionY();
|
||||||
|
x = lastTarget.locations.GetPositionX() + (xDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
||||||
|
y = lastTarget.locations.GetPositionY() + (yDiff * (float(timeDiffThis) / float(timeDiffTarget)));
|
||||||
|
}
|
||||||
|
float xDiff = x - thisCam.locations.GetPositionX();
|
||||||
|
float yDiff = y - thisCam.locations.GetPositionY();
|
||||||
|
thisCam.locations.SetOrientation(std::atan2(yDiff, xDiff));
|
||||||
|
}
|
||||||
|
|
||||||
|
cameras.push_back(thisCam);
|
||||||
|
positions++;
|
||||||
|
currPos += sizeof(M2SplineKey<G3D::Vector3>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sFlyByCameraStore[dbcentry->ID] = cameras;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadM2Cameras(std::string const& dataPath)
|
||||||
|
{
|
||||||
|
sFlyByCameraStore.clear();
|
||||||
|
LOG_INFO("server.loading", ">> Loading Cinematic Camera files");
|
||||||
|
|
||||||
|
uint32 oldMSTime = getMSTime();
|
||||||
|
for (CinematicCameraEntry const* dbcentry : sCinematicCameraStore)
|
||||||
|
{
|
||||||
|
std::string filenameWork = dataPath;
|
||||||
|
filenameWork.append(dbcentry->Model);
|
||||||
|
|
||||||
|
// Replace slashes (always to forward slash, because boost!)
|
||||||
|
std::replace(filenameWork.begin(), filenameWork.end(), '\\', '/');
|
||||||
|
|
||||||
|
boost::filesystem::path filename = filenameWork;
|
||||||
|
|
||||||
|
// Convert to native format
|
||||||
|
filename.make_preferred();
|
||||||
|
|
||||||
|
// Replace mdx to .m2
|
||||||
|
filename.replace_extension("m2");
|
||||||
|
|
||||||
|
std::ifstream m2file(filename.string().c_str(), std::ios::in | std::ios::binary);
|
||||||
|
if (!m2file.is_open())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get file size
|
||||||
|
m2file.seekg(0, std::ios::end);
|
||||||
|
std::streamoff fileSize = m2file.tellg();
|
||||||
|
|
||||||
|
// Reject if not at least the size of the header
|
||||||
|
if (static_cast<uint32>(fileSize) < sizeof(M2Header))
|
||||||
|
{
|
||||||
|
LOG_ERROR("server.loading", "Camera file %s is damaged. File is smaller than header size", filename.string().c_str());
|
||||||
|
m2file.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read 4 bytes (signature)
|
||||||
|
m2file.seekg(0, std::ios::beg);
|
||||||
|
char fileCheck[5];
|
||||||
|
m2file.read(fileCheck, 4);
|
||||||
|
fileCheck[4] = 0;
|
||||||
|
|
||||||
|
// Check file has correct magic (MD20)
|
||||||
|
if (strcmp(fileCheck, "MD20"))
|
||||||
|
{
|
||||||
|
LOG_ERROR("server.loading", "Camera file %s is damaged. File identifier not found", filename.string().c_str());
|
||||||
|
m2file.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have a good file, read it all into a vector of char's, then close the file.
|
||||||
|
std::vector<char> buffer(fileSize);
|
||||||
|
m2file.seekg(0, std::ios::beg);
|
||||||
|
if (!m2file.read(buffer.data(), fileSize))
|
||||||
|
{
|
||||||
|
m2file.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m2file.close();
|
||||||
|
|
||||||
|
// Read header
|
||||||
|
M2Header const* header = reinterpret_cast<M2Header const*>(buffer.data());
|
||||||
|
|
||||||
|
if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32>(fileSize))
|
||||||
|
{
|
||||||
|
LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.string().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get camera(s) - Main header, then dump them.
|
||||||
|
M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
|
||||||
|
if (!readCamera(cam, fileSize, header, dbcentry))
|
||||||
|
LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.string().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("server.loading", ">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<FlyByCamera> const* GetFlyByCameras(uint32 cinematicCameraId)
|
||||||
|
{
|
||||||
|
return Acore::Containers::MapGetValuePtr(sFlyByCameraStore, cinematicCameraId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ACORE_M2STORES_H
|
||||||
|
#define ACORE_M2STORES_H
|
||||||
|
|
||||||
|
#include "Define.h"
|
||||||
|
#include "Position.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct FlyByCamera
|
||||||
|
{
|
||||||
|
uint32 timeStamp;
|
||||||
|
Position locations;
|
||||||
|
};
|
||||||
|
|
||||||
|
AC_GAME_API void LoadM2Cameras(std::string const& dataPath);
|
||||||
|
|
||||||
|
AC_GAME_API std::vector<FlyByCamera> const* GetFlyByCameras(uint32 cinematicCameraId);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ACORE_M2STRUCTURE_H
|
||||||
|
#define ACORE_M2STRUCTURE_H
|
||||||
|
|
||||||
|
#include <G3D/Vector3.h>
|
||||||
|
#include <G3D/AABox.h>
|
||||||
|
|
||||||
|
// Structures for M2 file. Source: https://wowdev.wiki
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
template<typename T>
|
||||||
|
struct M2SplineKey
|
||||||
|
{
|
||||||
|
T p0;
|
||||||
|
T p1;
|
||||||
|
T p2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct M2Header
|
||||||
|
{
|
||||||
|
char Magic[4]; // "MD20"
|
||||||
|
uint32 Version; // The version of the format.
|
||||||
|
uint32 lName; // Length of the model's name including the trailing \0
|
||||||
|
uint32 ofsName; // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess.
|
||||||
|
uint32 GlobalModelFlags; // 0x0001: tilt x, 0x0002: tilt y, 0x0008: add 2 fields in header, 0x0020: load .phys data (MoP+), 0x0080: has _lod .skin files (MoP?+), 0x0100: is camera related.
|
||||||
|
uint32 nGlobalSequences;
|
||||||
|
uint32 ofsGlobalSequences; // A list of timestamps.
|
||||||
|
uint32 nAnimations;
|
||||||
|
uint32 ofsAnimations; // Information about the animations in the model.
|
||||||
|
uint32 nAnimationLookup;
|
||||||
|
uint32 ofsAnimationLookup; // Mapping of global IDs to the entries in the Animation sequences block.
|
||||||
|
uint32 nBones; // MAX_BONES = 0x100
|
||||||
|
uint32 ofsBones; // Information about the bones in this model.
|
||||||
|
uint32 nKeyBoneLookup;
|
||||||
|
uint32 ofsKeyBoneLookup; // Lookup table for key skeletal bones.
|
||||||
|
uint32 nVertices;
|
||||||
|
uint32 ofsVertices; // Vertices of the model.
|
||||||
|
uint32 nViews; // Views (LOD) are now in .skins.
|
||||||
|
uint32 nSubmeshAnimations;
|
||||||
|
uint32 ofsSubmeshAnimations; // Submesh color and alpha animations definitions.
|
||||||
|
uint32 nTextures;
|
||||||
|
uint32 ofsTextures; // Textures of this model.
|
||||||
|
uint32 nTransparency;
|
||||||
|
uint32 ofsTransparency; // Transparency of textures.
|
||||||
|
uint32 nUVAnimation;
|
||||||
|
uint32 ofsUVAnimation;
|
||||||
|
uint32 nTexReplace;
|
||||||
|
uint32 ofsTexReplace; // Replaceable Textures.
|
||||||
|
uint32 nRenderFlags;
|
||||||
|
uint32 ofsRenderFlags; // Blending modes / render flags.
|
||||||
|
uint32 nBoneLookupTable;
|
||||||
|
uint32 ofsBoneLookupTable; // A bone lookup table.
|
||||||
|
uint32 nTexLookup;
|
||||||
|
uint32 ofsTexLookup; // The same for textures.
|
||||||
|
uint32 nTexUnits; // possibly removed with cata?!
|
||||||
|
uint32 ofsTexUnits; // And texture units. Somewhere they have to be too.
|
||||||
|
uint32 nTransLookup;
|
||||||
|
uint32 ofsTransLookup; // Everything needs its lookup. Here are the transparencies.
|
||||||
|
uint32 nUVAnimLookup;
|
||||||
|
uint32 ofsUVAnimLookup;
|
||||||
|
G3D::AABox BoundingBox; // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height
|
||||||
|
float BoundingSphereRadius;
|
||||||
|
G3D::AABox CollisionBox;
|
||||||
|
float CollisionSphereRadius;
|
||||||
|
uint32 nBoundingTriangles;
|
||||||
|
uint32 ofsBoundingTriangles; // Our bounding volumes. Similar structure like in the old ofsViews.
|
||||||
|
uint32 nBoundingVertices;
|
||||||
|
uint32 ofsBoundingVertices;
|
||||||
|
uint32 nBoundingNormals;
|
||||||
|
uint32 ofsBoundingNormals;
|
||||||
|
uint32 nAttachments;
|
||||||
|
uint32 ofsAttachments; // Attachments are for weapons etc.
|
||||||
|
uint32 nAttachLookup;
|
||||||
|
uint32 ofsAttachLookup; // Of course with a lookup.
|
||||||
|
uint32 nEvents;
|
||||||
|
uint32 ofsEvents; // Used for playing sounds when dying and a lot else.
|
||||||
|
uint32 nLights;
|
||||||
|
uint32 ofsLights; // Lights are mainly used in loginscreens but in wands and some doodads too.
|
||||||
|
uint32 nCameras; // Format of Cameras changed with version 271!
|
||||||
|
uint32 ofsCameras; // The cameras are present in most models for having a model in the Character-Tab.
|
||||||
|
uint32 nCameraLookup;
|
||||||
|
uint32 ofsCameraLookup; // And lookup-time again.
|
||||||
|
uint32 nRibbonEmitters;
|
||||||
|
uint32 ofsRibbonEmitters; // Things swirling around. See the CoT-entrance for light-trails.
|
||||||
|
uint32 nParticleEmitters;
|
||||||
|
uint32 ofsParticleEmitters; // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles.
|
||||||
|
uint32 nBlendMaps; // This has to deal with blending. Exists IFF (flags & 0x8) != 0. When set, textures blending is overriden by the associated array. See M2/WotLK#Blend_mode_overrides
|
||||||
|
uint32 ofsBlendMaps; // Same as above. Points to an array of uint16 of nBlendMaps entries -- From WoD information.};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct M2Array
|
||||||
|
{
|
||||||
|
uint32_t number;
|
||||||
|
uint32 offset_elements;
|
||||||
|
};
|
||||||
|
struct M2Track
|
||||||
|
{
|
||||||
|
uint16_t interpolation_type;
|
||||||
|
uint16_t global_sequence;
|
||||||
|
M2Array timestamps;
|
||||||
|
M2Array values;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct M2Camera
|
||||||
|
{
|
||||||
|
uint32_t type; // 0: portrait, 1: characterinfo; -1: else (flyby etc.); referenced backwards in the lookup table.
|
||||||
|
float fov; // No radians, no degrees. Multiply by 35 to get degrees.
|
||||||
|
float far_clip;
|
||||||
|
float near_clip;
|
||||||
|
M2Track positions; // How the camera's position moves. Should be 3*3 floats.
|
||||||
|
G3D::Vector3 position_base;
|
||||||
|
M2Track target_positions; // How the target moves. Should be 3*3 floats.
|
||||||
|
G3D::Vector3 target_position_base;
|
||||||
|
M2Track rolldata; // The camera can have some roll-effect. Its 0 to 2*Pi.
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1621,7 +1621,7 @@ float WorldObject::GetGridActivationRange() const
|
|||||||
{
|
{
|
||||||
if (ToPlayer())
|
if (ToPlayer())
|
||||||
{
|
{
|
||||||
if (ToPlayer()->IsOnCinematic())
|
if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
|
||||||
{
|
{
|
||||||
return DEFAULT_VISIBILITY_INSTANCE;
|
return DEFAULT_VISIBILITY_INSTANCE;
|
||||||
}
|
}
|
||||||
@@ -1688,7 +1688,7 @@ float WorldObject::GetSightRange(WorldObject const* target) const
|
|||||||
{
|
{
|
||||||
return MAX_VISIBILITY_DISTANCE;
|
return MAX_VISIBILITY_DISTANCE;
|
||||||
}
|
}
|
||||||
else if (ToPlayer()->IsOnCinematic())
|
else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
|
||||||
{
|
{
|
||||||
return DEFAULT_VISIBILITY_INSTANCE;
|
return DEFAULT_VISIBILITY_INSTANCE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CinematicMgr.h"
|
||||||
|
#include "Map.h"
|
||||||
|
#include "M2Stores.h"
|
||||||
|
#include "MotionMaster.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "TemporarySummon.h"
|
||||||
|
|
||||||
|
CinematicMgr::CinematicMgr(Player* playerref)
|
||||||
|
{
|
||||||
|
player = playerref;
|
||||||
|
m_cinematicDiff = 0;
|
||||||
|
m_lastCinematicCheck = 0;
|
||||||
|
m_activeCinematicCameraId = 0;
|
||||||
|
m_cinematicLength = 0;
|
||||||
|
m_cinematicCamera = nullptr;
|
||||||
|
m_remoteSightPosition = Position(0.0f, 0.0f, 0.0f);
|
||||||
|
m_CinematicObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CinematicMgr::~CinematicMgr()
|
||||||
|
{
|
||||||
|
if (m_cinematicCamera && m_activeCinematicCameraId)
|
||||||
|
EndCinematic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CinematicMgr::BeginCinematic()
|
||||||
|
{
|
||||||
|
// Sanity check for active camera set
|
||||||
|
if (m_activeCinematicCameraId == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (std::vector<FlyByCamera> const* flyByCameras = GetFlyByCameras(m_activeCinematicCameraId))
|
||||||
|
{
|
||||||
|
// Initialize diff, and set camera
|
||||||
|
m_cinematicDiff = 0;
|
||||||
|
m_cinematicCamera = flyByCameras;
|
||||||
|
|
||||||
|
auto camitr = m_cinematicCamera->begin();
|
||||||
|
if (camitr != m_cinematicCamera->end())
|
||||||
|
{
|
||||||
|
Position const& pos = camitr->locations;
|
||||||
|
if (!pos.IsPositionValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->GetMap()->LoadGrid(pos.GetPositionX(), pos.GetPositionY());
|
||||||
|
m_CinematicObject = player->SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 120000);
|
||||||
|
if (m_CinematicObject)
|
||||||
|
{
|
||||||
|
m_CinematicObject->setActive(true);
|
||||||
|
player->SetViewpoint(m_CinematicObject, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get cinematic length
|
||||||
|
m_cinematicLength = flyByCameras->back().timeStamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CinematicMgr::EndCinematic()
|
||||||
|
{
|
||||||
|
if (m_activeCinematicCameraId == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_cinematicDiff = 0;
|
||||||
|
m_cinematicCamera = nullptr;
|
||||||
|
m_activeCinematicCameraId = 0;
|
||||||
|
if (m_CinematicObject)
|
||||||
|
{
|
||||||
|
if (WorldObject* vpObject = player->GetViewpoint())
|
||||||
|
if (vpObject == m_CinematicObject)
|
||||||
|
player->SetViewpoint(m_CinematicObject, false);
|
||||||
|
|
||||||
|
m_CinematicObject->AddObjectToRemoveList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CinematicMgr::UpdateCinematicLocation(uint32 /*diff*/)
|
||||||
|
{
|
||||||
|
if (m_activeCinematicCameraId == 0 || !m_cinematicCamera || m_cinematicCamera->size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Position lastPosition;
|
||||||
|
uint32 lastTimestamp = 0;
|
||||||
|
Position nextPosition;
|
||||||
|
uint32 nextTimestamp = 0;
|
||||||
|
|
||||||
|
// Obtain direction of travel
|
||||||
|
for (FlyByCamera cam : *m_cinematicCamera)
|
||||||
|
{
|
||||||
|
if (cam.timeStamp > m_cinematicDiff)
|
||||||
|
{
|
||||||
|
nextPosition.Relocate(cam.locations);
|
||||||
|
nextTimestamp = cam.timeStamp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastPosition.Relocate(cam.locations);
|
||||||
|
lastTimestamp = cam.timeStamp;
|
||||||
|
}
|
||||||
|
float angle = lastPosition.GetAbsoluteAngle(&nextPosition);
|
||||||
|
angle -= lastPosition.GetOrientation();
|
||||||
|
if (angle < 0)
|
||||||
|
angle += 2 * float(M_PI);
|
||||||
|
|
||||||
|
// Look for position around 2 second ahead of us.
|
||||||
|
int32 workDiff = m_cinematicDiff;
|
||||||
|
|
||||||
|
// Modify result based on camera direction (Humans for example, have the camera point behind)
|
||||||
|
workDiff += static_cast<int32>(float(CINEMATIC_LOOKAHEAD) * cos(angle));
|
||||||
|
|
||||||
|
// Get an iterator to the last entry in the cameras, to make sure we don't go beyond the end
|
||||||
|
auto endItr = m_cinematicCamera->rbegin();
|
||||||
|
if (endItr != m_cinematicCamera->rend() && workDiff > static_cast<int32>(endItr->timeStamp))
|
||||||
|
workDiff = endItr->timeStamp;
|
||||||
|
|
||||||
|
// Never try to go back in time before the start of cinematic!
|
||||||
|
if (workDiff < 0)
|
||||||
|
workDiff = m_cinematicDiff;
|
||||||
|
|
||||||
|
// Obtain the previous and next waypoint based on timestamp
|
||||||
|
for (FlyByCamera cam : *m_cinematicCamera)
|
||||||
|
{
|
||||||
|
if (static_cast<int32>(cam.timeStamp) >= workDiff)
|
||||||
|
{
|
||||||
|
nextPosition.Relocate(cam.locations);
|
||||||
|
nextTimestamp = cam.timeStamp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastPosition.Relocate(cam.locations);
|
||||||
|
lastTimestamp = cam.timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never try to go beyond the end of the cinematic
|
||||||
|
if (workDiff > static_cast<int32>(nextTimestamp))
|
||||||
|
workDiff = static_cast<int32>(nextTimestamp);
|
||||||
|
|
||||||
|
// Interpolate the position for this moment in time (or the adjusted moment in time)
|
||||||
|
uint32 timeDiff = nextTimestamp - lastTimestamp;
|
||||||
|
uint32 interDiff = workDiff - lastTimestamp;
|
||||||
|
float xDiff = nextPosition.m_positionX - lastPosition.m_positionX;
|
||||||
|
float yDiff = nextPosition.m_positionY - lastPosition.m_positionY;
|
||||||
|
float zDiff = nextPosition.m_positionZ - lastPosition.m_positionZ;
|
||||||
|
Position interPosition(lastPosition.m_positionX + (xDiff * (float(interDiff) / float(timeDiff))), lastPosition.m_positionY +
|
||||||
|
(yDiff * (float(interDiff) / float(timeDiff))), lastPosition.m_positionZ + (zDiff * (float(interDiff) / float(timeDiff))));
|
||||||
|
|
||||||
|
// Advance (at speed) to this position. The remote sight object is used
|
||||||
|
// to send update information to player in cinematic
|
||||||
|
if (m_CinematicObject && interPosition.IsPositionValid())
|
||||||
|
m_CinematicObject->MonsterMoveWithSpeed(interPosition.m_positionX, interPosition.m_positionY, interPosition.m_positionZ, 500.0f);
|
||||||
|
|
||||||
|
// If we never received an end packet 10 seconds after the final timestamp then force an end
|
||||||
|
if (m_cinematicDiff > m_cinematicLength + 10 * IN_MILLISECONDS)
|
||||||
|
EndCinematic();
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CinematicMgr_h__
|
||||||
|
#define CinematicMgr_h__
|
||||||
|
|
||||||
|
#include "Define.h"
|
||||||
|
#include "Object.h"
|
||||||
|
|
||||||
|
constexpr auto CINEMATIC_UPDATEDIFF = 500;
|
||||||
|
constexpr auto CINEMATIC_LOOKAHEAD = 2000;
|
||||||
|
|
||||||
|
class Player;
|
||||||
|
struct FlyByCamera;
|
||||||
|
|
||||||
|
class AC_GAME_API CinematicMgr
|
||||||
|
{
|
||||||
|
friend class Player;
|
||||||
|
public:
|
||||||
|
explicit CinematicMgr(Player* playerref);
|
||||||
|
~CinematicMgr();
|
||||||
|
|
||||||
|
// Cinematic camera data and remote sight functions
|
||||||
|
uint32 GetActiveCinematicCamera() const { return m_activeCinematicCameraId; }
|
||||||
|
void SetActiveCinematicCamera(uint32 cinematicCameraId = 0) { m_activeCinematicCameraId = cinematicCameraId; }
|
||||||
|
bool IsOnCinematic() const { return (m_cinematicCamera != nullptr); }
|
||||||
|
void BeginCinematic();
|
||||||
|
void EndCinematic();
|
||||||
|
void UpdateCinematicLocation(uint32 diff);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Remote location information
|
||||||
|
Player* player;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32 m_cinematicDiff;
|
||||||
|
uint32 m_lastCinematicCheck;
|
||||||
|
uint32 m_activeCinematicCameraId;
|
||||||
|
uint32 m_cinematicLength;
|
||||||
|
std::vector<FlyByCamera> const* m_cinematicCamera;
|
||||||
|
Position m_remoteSightPosition;
|
||||||
|
TempSummon* m_CinematicObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -383,12 +383,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
|||||||
|
|
||||||
_activeCheats = CHEAT_NONE;
|
_activeCheats = CHEAT_NONE;
|
||||||
|
|
||||||
m_cinematicDiff = 0;
|
_cinematicMgr = new CinematicMgr(this);
|
||||||
m_lastCinematicCheck = 0;
|
|
||||||
m_activeCinematicCameraId = 0;
|
|
||||||
m_cinematicCamera = nullptr;
|
|
||||||
m_remoteSightPosition = Position(0.0f, 0.0f, 0.0f);
|
|
||||||
m_CinematicObject = nullptr;
|
|
||||||
|
|
||||||
m_achievementMgr = new AchievementMgr(this);
|
m_achievementMgr = new AchievementMgr(this);
|
||||||
m_reputationMgr = new ReputationMgr(this);
|
m_reputationMgr = new ReputationMgr(this);
|
||||||
@@ -5574,14 +5569,14 @@ void Player::SendDirectMessage(WorldPacket const* data) const
|
|||||||
m_session->SendPacket(data);
|
m_session->SendPacket(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::SendCinematicStart(uint32 CinematicSequenceId)
|
void Player::SendCinematicStart(uint32 CinematicSequenceId) const
|
||||||
{
|
{
|
||||||
WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
|
WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
|
||||||
data << uint32(CinematicSequenceId);
|
data << uint32(CinematicSequenceId);
|
||||||
SendDirectMessage(&data);
|
SendDirectMessage(&data);
|
||||||
if (const CinematicSequencesEntry* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId))
|
if (CinematicSequencesEntry const* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId))
|
||||||
{
|
{
|
||||||
SetActiveCinematicCamera(sequence->cinematicCamera);
|
_cinematicMgr->SetActiveCinematicCamera(sequence->cinematicCamera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15498,56 +15493,6 @@ bool Player::SetFeatherFall(bool apply, bool packetOnly /*= false*/)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::BeginCinematic()
|
|
||||||
{
|
|
||||||
// Sanity check for active camera set
|
|
||||||
if (m_activeCinematicCameraId == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto itr = sFlyByCameraStore.find(m_activeCinematicCameraId);
|
|
||||||
if (itr != sFlyByCameraStore.end())
|
|
||||||
{
|
|
||||||
// Initialize diff, and set camera
|
|
||||||
m_cinematicDiff = 0;
|
|
||||||
m_cinematicCamera = &itr->second;
|
|
||||||
|
|
||||||
auto camitr = m_cinematicCamera->begin();
|
|
||||||
if (camitr != m_cinematicCamera->end())
|
|
||||||
{
|
|
||||||
Position pos(camitr->locations.x, camitr->locations.y, camitr->locations.z, camitr->locations.w);
|
|
||||||
if (!pos.IsPositionValid())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_mapRef->LoadGrid(camitr->locations.x, camitr->locations.y);
|
|
||||||
m_CinematicObject = SummonCreature(VISUAL_WAYPOINT, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000);
|
|
||||||
if (m_CinematicObject)
|
|
||||||
{
|
|
||||||
m_CinematicObject->setActive(true);
|
|
||||||
SetViewpoint(m_CinematicObject, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::EndCinematic()
|
|
||||||
{
|
|
||||||
m_cinematicDiff = 0;
|
|
||||||
m_cinematicCamera = nullptr;
|
|
||||||
m_activeCinematicCameraId = 0;
|
|
||||||
if (m_CinematicObject)
|
|
||||||
{
|
|
||||||
if (m_seer && m_seer == m_CinematicObject)
|
|
||||||
{
|
|
||||||
SetViewpoint(m_CinematicObject, false);
|
|
||||||
}
|
|
||||||
m_CinematicObject->AddObjectToRemoveList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Guild* Player::GetGuild() const
|
Guild* Player::GetGuild() const
|
||||||
{
|
{
|
||||||
uint32 guildId = GetGuildId();
|
uint32 guildId = GetGuildId();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "ArenaTeam.h"
|
#include "ArenaTeam.h"
|
||||||
#include "Battleground.h"
|
#include "Battleground.h"
|
||||||
#include "CharacterCache.h"
|
#include "CharacterCache.h"
|
||||||
|
#include "CinematicMgr.h"
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
#include "DatabaseEnvFwd.h"
|
#include "DatabaseEnvFwd.h"
|
||||||
#include "GroupReference.h"
|
#include "GroupReference.h"
|
||||||
@@ -1036,6 +1037,7 @@ struct EntryPointData
|
|||||||
class Player : public Unit, public GridObject<Player>
|
class Player : public Unit, public GridObject<Player>
|
||||||
{
|
{
|
||||||
friend class WorldSession;
|
friend class WorldSession;
|
||||||
|
friend class CinematicMgr;
|
||||||
friend void Item::AddToUpdateQueueOf(Player* player);
|
friend void Item::AddToUpdateQueueOf(Player* player);
|
||||||
friend void Item::RemoveFromUpdateQueueOf(Player* player);
|
friend void Item::RemoveFromUpdateQueueOf(Player* player);
|
||||||
public:
|
public:
|
||||||
@@ -1326,6 +1328,8 @@ public:
|
|||||||
[[nodiscard]] TradeData* GetTradeData() const { return m_trade; }
|
[[nodiscard]] TradeData* GetTradeData() const { return m_trade; }
|
||||||
void TradeCancel(bool sendback);
|
void TradeCancel(bool sendback);
|
||||||
|
|
||||||
|
CinematicMgr* GetCinematicMgr() const { return _cinematicMgr; }
|
||||||
|
|
||||||
void UpdateEnchantTime(uint32 time);
|
void UpdateEnchantTime(uint32 time);
|
||||||
void UpdateSoulboundTradeItems();
|
void UpdateSoulboundTradeItems();
|
||||||
void AddTradeableItem(Item* item);
|
void AddTradeableItem(Item* item);
|
||||||
@@ -2368,7 +2372,7 @@ public:
|
|||||||
[[nodiscard]] bool IsPetNeedBeTemporaryUnsummoned() const { return GetSession()->PlayerLogout() || !IsInWorld() || !IsAlive() || IsMounted()/*+in flight*/ || GetVehicle() || IsBeingTeleported(); }
|
[[nodiscard]] bool IsPetNeedBeTemporaryUnsummoned() const { return GetSession()->PlayerLogout() || !IsInWorld() || !IsAlive() || IsMounted()/*+in flight*/ || GetVehicle() || IsBeingTeleported(); }
|
||||||
bool CanResummonPet(uint32 spellid);
|
bool CanResummonPet(uint32 spellid);
|
||||||
|
|
||||||
void SendCinematicStart(uint32 CinematicSequenceId);
|
void SendCinematicStart(uint32 CinematicSequenceId) const;
|
||||||
void SendMovieStart(uint32 MovieId);
|
void SendMovieStart(uint32 MovieId);
|
||||||
|
|
||||||
uint32 DoRandomRoll(uint32 minimum, uint32 maximum);
|
uint32 DoRandomRoll(uint32 minimum, uint32 maximum);
|
||||||
@@ -2561,17 +2565,6 @@ public:
|
|||||||
|
|
||||||
static std::unordered_map<int, bgZoneRef> bgZoneIdToFillWorldStates; // zoneId -> FillInitialWorldStates
|
static std::unordered_map<int, bgZoneRef> bgZoneIdToFillWorldStates; // zoneId -> FillInitialWorldStates
|
||||||
|
|
||||||
// Cinematic camera data and remote sight functions
|
|
||||||
[[nodiscard]] uint32 GetActiveCinematicCamera() const { return m_activeCinematicCameraId; }
|
|
||||||
void SetActiveCinematicCamera(uint32 cinematicCameraId = 0) { m_activeCinematicCameraId = cinematicCameraId; }
|
|
||||||
[[nodiscard]] bool IsOnCinematic() const { return (m_cinematicCamera != nullptr); }
|
|
||||||
void BeginCinematic();
|
|
||||||
void EndCinematic();
|
|
||||||
void UpdateCinematicLocation(uint32 diff);
|
|
||||||
|
|
||||||
std::string GetMapAreaAndZoneString();
|
|
||||||
std::string GetCoordsMapAreaAndZoneString();
|
|
||||||
|
|
||||||
void SetFarSightDistance(float radius);
|
void SetFarSightDistance(float radius);
|
||||||
void ResetFarSightDistance();
|
void ResetFarSightDistance();
|
||||||
[[nodiscard]] Optional<float> GetFarSightDistance() const;
|
[[nodiscard]] Optional<float> GetFarSightDistance() const;
|
||||||
@@ -2866,6 +2859,8 @@ private:
|
|||||||
Item* _StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update);
|
Item* _StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update);
|
||||||
Item* _LoadItem(CharacterDatabaseTransaction trans, uint32 zoneId, uint32 timeDiff, Field* fields);
|
Item* _LoadItem(CharacterDatabaseTransaction trans, uint32 zoneId, uint32 timeDiff, Field* fields);
|
||||||
|
|
||||||
|
CinematicMgr* _cinematicMgr;
|
||||||
|
|
||||||
typedef GuidSet RefundableItemsSet;
|
typedef GuidSet RefundableItemsSet;
|
||||||
RefundableItemsSet m_refundableItems;
|
RefundableItemsSet m_refundableItems;
|
||||||
void SendRefundInfo(Item* item);
|
void SendRefundInfo(Item* item);
|
||||||
@@ -2931,14 +2926,6 @@ private:
|
|||||||
|
|
||||||
uint32 m_flightSpellActivated;
|
uint32 m_flightSpellActivated;
|
||||||
|
|
||||||
// Remote location information
|
|
||||||
uint32 m_cinematicDiff;
|
|
||||||
uint32 m_lastCinematicCheck;
|
|
||||||
uint32 m_activeCinematicCameraId;
|
|
||||||
FlyByCameraCollection* m_cinematicCamera;
|
|
||||||
Position m_remoteSightPosition;
|
|
||||||
Creature* m_CinematicObject;
|
|
||||||
|
|
||||||
WorldLocation _corpseLocation;
|
WorldLocation _corpseLocation;
|
||||||
|
|
||||||
Optional<float> _farSightDistance = { };
|
Optional<float> _farSightDistance = { };
|
||||||
|
|||||||
@@ -47,9 +47,6 @@
|
|||||||
// Zone Interval should be 1 second
|
// Zone Interval should be 1 second
|
||||||
constexpr auto ZONE_UPDATE_INTERVAL = 1000;
|
constexpr auto ZONE_UPDATE_INTERVAL = 1000;
|
||||||
|
|
||||||
constexpr auto CINEMATIC_UPDATEDIFF = 500;
|
|
||||||
constexpr auto CINEMATIC_LOOKAHEAD = 2000;
|
|
||||||
|
|
||||||
void Player::Update(uint32 p_time)
|
void Player::Update(uint32 p_time)
|
||||||
{
|
{
|
||||||
if (!IsInWorld())
|
if (!IsInWorld())
|
||||||
@@ -70,12 +67,11 @@ void Player::Update(uint32 p_time)
|
|||||||
|
|
||||||
// Update cinematic location, if 500ms have passed and we're doing a
|
// Update cinematic location, if 500ms have passed and we're doing a
|
||||||
// cinematic now.
|
// cinematic now.
|
||||||
m_cinematicDiff += p_time;
|
_cinematicMgr->m_cinematicDiff += p_time;
|
||||||
if (m_cinematicCamera && m_activeCinematicCameraId &&
|
if (_cinematicMgr->m_cinematicCamera && _cinematicMgr->m_activeCinematicCameraId && GetMSTimeDiffToNow(_cinematicMgr->m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF)
|
||||||
GetMSTimeDiffToNow(m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF)
|
|
||||||
{
|
{
|
||||||
m_lastCinematicCheck = getMSTime();
|
_cinematicMgr->m_lastCinematicCheck = getMSTime();
|
||||||
UpdateCinematicLocation(p_time);
|
_cinematicMgr->UpdateCinematicLocation(p_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to implement delayed far teleports
|
// used to implement delayed far teleports
|
||||||
@@ -1508,107 +1504,6 @@ void Player::UpdatePotionCooldown(Spell* spell)
|
|||||||
SetLastPotionId(0);
|
SetLastPotionId(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::UpdateCinematicLocation(uint32 /*diff*/)
|
|
||||||
{
|
|
||||||
Position lastPosition;
|
|
||||||
uint32 lastTimestamp = 0;
|
|
||||||
Position nextPosition;
|
|
||||||
uint32 nextTimestamp = 0;
|
|
||||||
|
|
||||||
if (m_cinematicCamera->size() == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain direction of travel
|
|
||||||
for (FlyByCamera cam : *m_cinematicCamera)
|
|
||||||
{
|
|
||||||
if (cam.timeStamp > m_cinematicDiff)
|
|
||||||
{
|
|
||||||
nextPosition = Position(cam.locations.x, cam.locations.y,
|
|
||||||
cam.locations.z, cam.locations.w);
|
|
||||||
nextTimestamp = cam.timeStamp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastPosition = Position(cam.locations.x, cam.locations.y,
|
|
||||||
cam.locations.z, cam.locations.w);
|
|
||||||
lastTimestamp = cam.timeStamp;
|
|
||||||
}
|
|
||||||
float angle = lastPosition.GetAngle(&nextPosition);
|
|
||||||
angle -= lastPosition.GetOrientation();
|
|
||||||
if (angle < 0)
|
|
||||||
{
|
|
||||||
angle += 2 * float(M_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for position around 2 second ahead of us.
|
|
||||||
int32 workDiff = m_cinematicDiff;
|
|
||||||
|
|
||||||
// Modify result based on camera direction (Humans for example, have the
|
|
||||||
// camera point behind)
|
|
||||||
workDiff += static_cast<int32>(float(CINEMATIC_LOOKAHEAD) * cos(angle));
|
|
||||||
|
|
||||||
// Get an iterator to the last entry in the cameras, to make sure we don't
|
|
||||||
// go beyond the end
|
|
||||||
FlyByCameraCollection::const_reverse_iterator endItr =
|
|
||||||
m_cinematicCamera->rbegin();
|
|
||||||
if (endItr != m_cinematicCamera->rend() &&
|
|
||||||
workDiff > static_cast<int32>(endItr->timeStamp))
|
|
||||||
{
|
|
||||||
workDiff = endItr->timeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Never try to go back in time before the start of cinematic!
|
|
||||||
if (workDiff < 0)
|
|
||||||
{
|
|
||||||
workDiff = m_cinematicDiff;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the previous and next waypoint based on timestamp
|
|
||||||
for (FlyByCamera cam : *m_cinematicCamera)
|
|
||||||
{
|
|
||||||
if (static_cast<int32>(cam.timeStamp) >= workDiff)
|
|
||||||
{
|
|
||||||
nextPosition = Position(cam.locations.x, cam.locations.y,
|
|
||||||
cam.locations.z, cam.locations.w);
|
|
||||||
nextTimestamp = cam.timeStamp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastPosition = Position(cam.locations.x, cam.locations.y,
|
|
||||||
cam.locations.z, cam.locations.w);
|
|
||||||
lastTimestamp = cam.timeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Never try to go beyond the end of the cinematic
|
|
||||||
if (workDiff > static_cast<int32>(nextTimestamp))
|
|
||||||
{
|
|
||||||
workDiff = static_cast<int32>(nextTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interpolate the position for this moment in time (or the adjusted moment
|
|
||||||
// in time)
|
|
||||||
uint32 timeDiff = nextTimestamp - lastTimestamp;
|
|
||||||
uint32 interDiff = workDiff - lastTimestamp;
|
|
||||||
float xDiff = nextPosition.m_positionX - lastPosition.m_positionX;
|
|
||||||
float yDiff = nextPosition.m_positionY - lastPosition.m_positionY;
|
|
||||||
float zDiff = nextPosition.m_positionZ - lastPosition.m_positionZ;
|
|
||||||
Position interPosition(lastPosition.m_positionX +
|
|
||||||
(xDiff * (float(interDiff) / float(timeDiff))),
|
|
||||||
lastPosition.m_positionY +
|
|
||||||
(yDiff * (float(interDiff) / float(timeDiff))),
|
|
||||||
lastPosition.m_positionZ +
|
|
||||||
(zDiff * (float(interDiff) / float(timeDiff))));
|
|
||||||
|
|
||||||
// Advance (at speed) to this position. The remote sight object is used
|
|
||||||
// to send update information to player in cinematic
|
|
||||||
if (m_CinematicObject && interPosition.IsPositionValid())
|
|
||||||
{
|
|
||||||
m_CinematicObject->MonsterMoveWithSpeed(
|
|
||||||
interPosition.m_positionX, interPosition.m_positionY,
|
|
||||||
interPosition.m_positionZ, 200.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template void Player::UpdateVisibilityOf(Player* target, UpdateData& data,
|
template void Player::UpdateVisibilityOf(Player* target, UpdateData& data,
|
||||||
std::vector<Unit*>& visibleNow);
|
std::vector<Unit*>& visibleNow);
|
||||||
template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data,
|
template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data,
|
||||||
|
|||||||
@@ -958,7 +958,7 @@ void WorldSession::HandleCompleteCinematic(WorldPacket& /*recv_data*/)
|
|||||||
LOG_DEBUG("network", "WORLD: Received CMSG_COMPLETE_CINEMATIC");
|
LOG_DEBUG("network", "WORLD: Received CMSG_COMPLETE_CINEMATIC");
|
||||||
}
|
}
|
||||||
// If player has sight bound to visual waypoint NPC we should remove it
|
// If player has sight bound to visual waypoint NPC we should remove it
|
||||||
GetPlayer()->EndCinematic();
|
GetPlayer()->GetCinematicMgr()->EndCinematic();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recv_data*/)
|
void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recv_data*/)
|
||||||
@@ -967,7 +967,7 @@ void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recv_data*/)
|
|||||||
LOG_DEBUG("network", "WORLD: Received CMSG_NEXT_CINEMATIC_CAMERA");
|
LOG_DEBUG("network", "WORLD: Received CMSG_NEXT_CINEMATIC_CAMERA");
|
||||||
}
|
}
|
||||||
// Sent by client when cinematic actually begun. So we begin the server side process
|
// Sent by client when cinematic actually begun. So we begin the server side process
|
||||||
GetPlayer()->BeginCinematic();
|
GetPlayer()->GetCinematicMgr()->BeginCinematic();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::HandleFeatherFallAck(WorldPacket& recv_data)
|
void WorldSession::HandleFeatherFallAck(WorldPacket& recv_data)
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
#include "MMapFactory.h"
|
#include "MMapFactory.h"
|
||||||
#include "MapMgr.h"
|
#include "MapMgr.h"
|
||||||
#include "Metric.h"
|
#include "Metric.h"
|
||||||
|
#include "M2Stores.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "Opcodes.h"
|
#include "Opcodes.h"
|
||||||
#include "OutdoorPvPMgr.h"
|
#include "OutdoorPvPMgr.h"
|
||||||
@@ -1530,6 +1531,9 @@ void World::SetInitialWorldSettings()
|
|||||||
LoadDBCStores(m_dataPath);
|
LoadDBCStores(m_dataPath);
|
||||||
DetectDBCLang();
|
DetectDBCLang();
|
||||||
|
|
||||||
|
// Load cinematic cameras
|
||||||
|
LoadM2Cameras(m_dataPath);
|
||||||
|
|
||||||
// Load IP Location Database
|
// Load IP Location Database
|
||||||
sIPLocation->Load();
|
sIPLocation->Load();
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "Language.h"
|
#include "Language.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "MapMgr.h"
|
#include "MapMgr.h"
|
||||||
|
#include "M2Stores.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PoolMgr.h"
|
#include "PoolMgr.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
@@ -115,7 +116,8 @@ public:
|
|||||||
// cinematicId - ID from CinematicSequences.dbc
|
// cinematicId - ID from CinematicSequences.dbc
|
||||||
static bool HandleDebugPlayCinematicCommand(ChatHandler* handler, uint32 cinematicId)
|
static bool HandleDebugPlayCinematicCommand(ChatHandler* handler, uint32 cinematicId)
|
||||||
{
|
{
|
||||||
if (!sCinematicSequencesStore.LookupEntry(cinematicId))
|
CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(cinematicId);
|
||||||
|
if (!cineSeq)
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, cinematicId);
|
handler->PSendSysMessage(LANG_CINEMATIC_NOT_EXIST, cinematicId);
|
||||||
handler->SetSentErrorMessage(true);
|
handler->SetSentErrorMessage(true);
|
||||||
@@ -123,23 +125,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dump camera locations
|
// Dump camera locations
|
||||||
if (CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(cinematicId))
|
if (std::vector<FlyByCamera> const* flyByCameras = GetFlyByCameras(cineSeq->cinematicCamera))
|
||||||
{
|
|
||||||
auto const& itr = sFlyByCameraStore.find(cineSeq->cinematicCamera);
|
|
||||||
if (itr != sFlyByCameraStore.end())
|
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage("Waypoints for sequence %u, camera %u", cinematicId, cineSeq->cinematicCamera);
|
handler->PSendSysMessage("Waypoints for sequence %u, camera %u", cinematicId, cineSeq->cinematicCamera);
|
||||||
uint32 count = 1;
|
uint32 count = 1;
|
||||||
for (FlyByCamera cam : itr->second)
|
for (FlyByCamera const& cam : *flyByCameras)
|
||||||
{
|
{
|
||||||
handler->PSendSysMessage("%02u - %7ums [%f, %f, %f] Facing %f (%f degrees)", count, cam.timeStamp, cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w, cam.locations.w * (180 / M_PI));
|
handler->PSendSysMessage("%02u - %7ums [%s (%f degrees)]", count, cam.timeStamp, cam.locations.ToString().c_str(), cam.locations.GetOrientation() * (180 / M_PI));
|
||||||
count++;
|
++count;
|
||||||
}
|
|
||||||
handler->PSendSysMessage("%lu waypoints dumped", itr->second.size());
|
|
||||||
}
|
}
|
||||||
|
handler->PSendSysMessage("%u waypoints dumped", flyByCameras->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
handler->GetSession()->GetPlayer()->SendCinematicStart(cinematicId);
|
handler->GetPlayer()->SendCinematicStart(cinematicId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,23 @@
|
|||||||
#ifndef DBCENUMS_H
|
#ifndef DBCENUMS_H
|
||||||
#define DBCENUMS_H
|
#define DBCENUMS_H
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct DBCPosition2D
|
||||||
|
{
|
||||||
|
float X;
|
||||||
|
float Y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DBCPosition3D
|
||||||
|
{
|
||||||
|
float X;
|
||||||
|
float Y;
|
||||||
|
float Z;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
// Client expected level limitation, like as used in DBC item max levels for "until max player level"
|
// Client expected level limitation, like as used in DBC item max levels for "until max player level"
|
||||||
// use as default max player level, must be fit max level for used client
|
// use as default max player level, must be fit max level for used client
|
||||||
// also see MAX_LEVEL and STRONG_MAX_LEVEL define
|
// also see MAX_LEVEL and STRONG_MAX_LEVEL define
|
||||||
|
|||||||
@@ -21,124 +21,9 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DBCStorageIterator.h"
|
#include "DBCStorageIterator.h"
|
||||||
#include "Errors.h"
|
#include "Errors.h"
|
||||||
#include <G3D/AABox.h>
|
|
||||||
#include <G3D/Vector3.h>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// Structures for M4 file. Source: https://wowdev.wiki
|
|
||||||
template<typename T>
|
|
||||||
struct M2SplineKey
|
|
||||||
{
|
|
||||||
T p0;
|
|
||||||
T p1;
|
|
||||||
T p2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct M2Header
|
|
||||||
{
|
|
||||||
char Magic[4]; // "MD20"
|
|
||||||
uint32 Version; // The version of the format.
|
|
||||||
uint32 lName; // Length of the model's name including the trailing \0
|
|
||||||
uint32 ofsName; // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess.
|
|
||||||
uint32 GlobalModelFlags; // 0x0001: tilt x, 0x0002: tilt y, 0x0008: add 2 fields in header, 0x0020: load .phys data (MoP+), 0x0080: has _lod .skin files (MoP?+), 0x0100: is camera related.
|
|
||||||
uint32 nGlobalSequences;
|
|
||||||
uint32 ofsGlobalSequences; // A list of timestamps.
|
|
||||||
uint32 nAnimations;
|
|
||||||
uint32 ofsAnimations; // Information about the animations in the model.
|
|
||||||
uint32 nAnimationLookup;
|
|
||||||
uint32 ofsAnimationLookup; // Mapping of global IDs to the entries in the Animation sequences block.
|
|
||||||
uint32 nBones; // MAX_BONES = 0x100
|
|
||||||
uint32 ofsBones; // Information about the bones in this model.
|
|
||||||
uint32 nKeyBoneLookup;
|
|
||||||
uint32 ofsKeyBoneLookup; // Lookup table for key skeletal bones.
|
|
||||||
uint32 nVertices;
|
|
||||||
uint32 ofsVertices; // Vertices of the model.
|
|
||||||
uint32 nViews; // Views (LOD) are now in .skins.
|
|
||||||
uint32 nSubmeshAnimations;
|
|
||||||
uint32 ofsSubmeshAnimations; // Submesh color and alpha animations definitions.
|
|
||||||
uint32 nTextures;
|
|
||||||
uint32 ofsTextures; // Textures of this model.
|
|
||||||
uint32 nTransparency;
|
|
||||||
uint32 ofsTransparency; // Transparency of textures.
|
|
||||||
uint32 nUVAnimation;
|
|
||||||
uint32 ofsUVAnimation;
|
|
||||||
uint32 nTexReplace;
|
|
||||||
uint32 ofsTexReplace; // Replaceable Textures.
|
|
||||||
uint32 nRenderFlags;
|
|
||||||
uint32 ofsRenderFlags; // Blending modes / render flags.
|
|
||||||
uint32 nBoneLookupTable;
|
|
||||||
uint32 ofsBoneLookupTable; // A bone lookup table.
|
|
||||||
uint32 nTexLookup;
|
|
||||||
uint32 ofsTexLookup; // The same for textures.
|
|
||||||
uint32 nTexUnits; // possibly removed with cata?!
|
|
||||||
uint32 ofsTexUnits; // And texture units. Somewhere they have to be too.
|
|
||||||
uint32 nTransLookup;
|
|
||||||
uint32 ofsTransLookup; // Everything needs its lookup. Here are the transparencies.
|
|
||||||
uint32 nUVAnimLookup;
|
|
||||||
uint32 ofsUVAnimLookup;
|
|
||||||
G3D::AABox BoundingBox; // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height
|
|
||||||
float BoundingSphereRadius;
|
|
||||||
G3D::AABox CollisionBox;
|
|
||||||
float CollisionSphereRadius;
|
|
||||||
uint32 nBoundingTriangles;
|
|
||||||
uint32 ofsBoundingTriangles; // Our bounding volumes. Similar structure like in the old ofsViews.
|
|
||||||
uint32 nBoundingVertices;
|
|
||||||
uint32 ofsBoundingVertices;
|
|
||||||
uint32 nBoundingNormals;
|
|
||||||
uint32 ofsBoundingNormals;
|
|
||||||
uint32 nAttachments;
|
|
||||||
uint32 ofsAttachments; // Attachments are for weapons etc.
|
|
||||||
uint32 nAttachLookup;
|
|
||||||
uint32 ofsAttachLookup; // Of course with a lookup.
|
|
||||||
uint32 nEvents;
|
|
||||||
uint32 ofsEvents; // Used for playing sounds when dying and a lot else.
|
|
||||||
uint32 nLights;
|
|
||||||
uint32 ofsLights; // Lights are mainly used in loginscreens but in wands and some doodads too.
|
|
||||||
uint32 nCameras; // Format of Cameras changed with version 271!
|
|
||||||
uint32 ofsCameras; // The cameras are present in most models for having a model in the Character-Tab.
|
|
||||||
uint32 nCameraLookup;
|
|
||||||
uint32 ofsCameraLookup; // And lookup-time again.
|
|
||||||
uint32 nRibbonEmitters;
|
|
||||||
uint32 ofsRibbonEmitters; // Things swirling around. See the CoT-entrance for light-trails.
|
|
||||||
uint32 nParticleEmitters;
|
|
||||||
uint32 ofsParticleEmitters; // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles.
|
|
||||||
uint32 nBlendMaps; // This has to deal with blending. Exists IFF (flags & 0x8) != 0. When set, textures blending is overriden by the associated array. See M2/WotLK#Blend_mode_overrides
|
|
||||||
uint32 ofsBlendMaps; // Same as above. Points to an array of uint16 of nBlendMaps entries -- From WoD information.};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct M2Array
|
|
||||||
{
|
|
||||||
uint32_t number;
|
|
||||||
uint32 offset_elements;
|
|
||||||
};
|
|
||||||
struct M2Track
|
|
||||||
{
|
|
||||||
uint16_t interpolation_type;
|
|
||||||
uint16_t global_sequence;
|
|
||||||
M2Array timestamps;
|
|
||||||
M2Array values;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct M2Camera
|
|
||||||
{
|
|
||||||
uint32_t type; // 0: portrait, 1: characterinfo; -1: else (flyby etc.); referenced backwards in the lookup table.
|
|
||||||
float fov; // No radians, no degrees. Multiply by 35 to get degrees.
|
|
||||||
float far_clip;
|
|
||||||
float near_clip;
|
|
||||||
M2Track positions; // How the camera's position moves. Should be 3*3 floats.
|
|
||||||
G3D::Vector3 position_base;
|
|
||||||
M2Track target_positions; // How the target moves. Should be 3*3 floats.
|
|
||||||
G3D::Vector3 target_position_base;
|
|
||||||
M2Track rolldata; // The camera can have some roll-effect. Its 0 to 2*Pi.
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FlyByCamera
|
|
||||||
{
|
|
||||||
uint32 timeStamp;
|
|
||||||
G3D::Vector4 locations;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Interface class for common access
|
/// Interface class for common access
|
||||||
class DBCStorageBase
|
class DBCStorageBase
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -692,13 +692,11 @@ struct ChrRacesEntry
|
|||||||
|
|
||||||
struct CinematicCameraEntry
|
struct CinematicCameraEntry
|
||||||
{
|
{
|
||||||
uint32 id; // 0 index
|
uint32 ID; // 0
|
||||||
char const* filename; // 1
|
char const* Model; // 1 Model filename (translate .mdx to .m2)
|
||||||
uint32 soundid; // 2 in SoundEntries.dbc or 0
|
uint32 SoundID; // 2 Sound ID (voiceover for cinematic)
|
||||||
float base_x; // 3
|
DBCPosition3D Origin; // 3-5 Position in map used for basis for M2 co-ordinates
|
||||||
float base_y; // 4
|
float OriginFacing; // 6 Orientation in map used for basis for M2 co-ordinates
|
||||||
float base_z; // 5
|
|
||||||
float base_o; // 6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CinematicSequencesEntry
|
struct CinematicSequencesEntry
|
||||||
|
|||||||
@@ -1097,7 +1097,7 @@ void ExtractCameraFiles(int locale, bool basicLocale)
|
|||||||
std::vector<std::string> camerafiles;
|
std::vector<std::string> camerafiles;
|
||||||
size_t cam_count = camdbc.getRecordCount();
|
size_t cam_count = camdbc.getRecordCount();
|
||||||
|
|
||||||
for (uint32 i = 0; i < cam_count; ++i)
|
for (size_t i = 0; i < cam_count; ++i)
|
||||||
{
|
{
|
||||||
std::string camFile(camdbc.getRecord(i).getString(1));
|
std::string camFile(camdbc.getRecord(i).getString(1));
|
||||||
size_t loc = camFile.find(".mdx");
|
size_t loc = camFile.find(".mdx");
|
||||||
|
|||||||
Reference in New Issue
Block a user