From 9d7baaa53fd43089c9b1873c0870398204dc5b7a Mon Sep 17 00:00:00 2001 From: Niam5 Date: Sun, 18 Jun 2023 18:02:27 -0700 Subject: [PATCH] Activate creatures and objects during opening cinematics port work of @r00ty-tc Co-Authored-By: Peter Camastral <6705544+krullgor@users.noreply.github.com> --- contrib/extractor/System.cpp | 103 +++++++++-- contrib/extractor/dbcfile.h | 6 +- src/game/Chat/debugcmds.cpp | 18 ++ src/game/Cinematics/CinematicMgr.cpp | 188 +++++++++++++++++++ src/game/Cinematics/CinematicMgr.h | 62 +++++++ src/game/Cinematics/M2Stores.cpp | 258 +++++++++++++++++++++++++++ src/game/Cinematics/M2Stores.h | 43 +++++ src/game/Cinematics/M2Structure.h | 149 ++++++++++++++++ src/game/Entities/MiscHandler.cpp | 4 + src/game/Entities/Player.cpp | 13 ++ src/game/Entities/Player.h | 6 + src/game/Maps/Map.cpp | 49 ++--- src/game/Maps/Map.h | 2 + src/game/Server/DBCEnums.h | 17 ++ src/game/Server/DBCStores.cpp | 2 + src/game/Server/DBCStores.h | 1 + src/game/Server/DBCStructure.h | 18 +- src/game/Server/DBCfmt.h | 3 +- src/game/World/World.cpp | 3 + 19 files changed, 898 insertions(+), 47 deletions(-) create mode 100644 src/game/Cinematics/CinematicMgr.cpp create mode 100644 src/game/Cinematics/CinematicMgr.h create mode 100644 src/game/Cinematics/M2Stores.cpp create mode 100644 src/game/Cinematics/M2Stores.h create mode 100644 src/game/Cinematics/M2Structure.h diff --git a/contrib/extractor/System.cpp b/contrib/extractor/System.cpp index ec5c6e0733..d346ef9706 100644 --- a/contrib/extractor/System.cpp +++ b/contrib/extractor/System.cpp @@ -2,15 +2,14 @@ #include #include -#include #include #include +#include +#include #ifdef _WIN32 #include "direct.h" -#include #else -#include #include #endif @@ -60,11 +59,12 @@ uint32 CONF_max_build = 0; enum Extract { EXTRACT_MAP = 1, - EXTRACT_DBC = 2 + EXTRACT_DBC = 2, + EXTRACT_CAMERA = 4 }; // Select data for extract -int CONF_extract = EXTRACT_MAP | EXTRACT_DBC; +int CONF_extract = EXTRACT_MAP | EXTRACT_DBC | EXTRACT_CAMERA; // This option allow limit minimum height to some value (Allow save some memory) // see contrib/mmap/src/Tilebuilder.h, INVALID_MAP_LIQ_HEIGHT bool CONF_allow_height_limit = true; @@ -108,13 +108,12 @@ bool FileExists(const char* FileName) void Usage(char* prg) { printf( - "Usage:\n" - "%s -[var] [value]\n" - "-i set input path\n" - "-o set output path\n" - "-e extract only MAP(1)/DBC(2) - standard: both(3)\n" - "-e extract only MAP(1)/DBC(2) - temporary only: DBC(2)\n" - "-f height stored as int (less map size but lost some accuracy) 1 by default\n" + "Usage:\n"\ + "%s -[var] [value]\n"\ + "-i set input path\n"\ + "-o set output path\n"\ + "-e extract only MAP(1)/DBC(2)/Camera(4) - standard: all(7)\n"\ + "-f height stored as int (less map size but lost some accuracy) 1 by default\n"\ "-b extract data for specific build (at least not greater it from available). Min supported build %u.\n" "Example: %s -f 0 -i \"c:\\games\\game\"", prg, MIN_SUPPORTED_BUILD, prg); exit(1); @@ -156,7 +155,7 @@ void HandleArgs(int argc, char* arg[]) if (c + 1 < argc) // all ok { CONF_extract = atoi(arg[(c++) + 1]); - if (!(CONF_extract > 0 && CONF_extract < 4)) + if (!(CONF_extract > 0 && CONF_extract < 8)) Usage(arg[0]); } else @@ -1154,6 +1153,59 @@ void AppendPatchMPQFilesToList(char const* subdir, char const* suffix, char cons #endif } +void ExtractCameraFiles(int const locale) +{ + HANDLE localeFile; + char localMPQ[512]; + sprintf(localMPQ, "%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]); + if (!SFileOpenArchive(localMPQ, 0, MPQ_OPEN_READ_ONLY, &localeFile)) + exit(1); + + printf("Extracting camera files...\n"); + + HANDLE dbcFile; + if (!SFileOpenFileEx(localeFile, "DBFilesClient\\CinematicCamera.dbc", SFILE_OPEN_FROM_MPQ, &dbcFile)) + { + printf("Fatal error: Cannot find CinematicCamera.dbc in archive!\n"); + exit(1); + } + + DBCFile camdbc(dbcFile); + if (!camdbc.open()) + { + printf("Unable to open CinematicCamera.dbc. Camera extract aborted.\n"); + return; + } + // get camera file list from DBC + std::vector camerafiles; + size_t cam_count = camdbc.getRecordCount(); + + for (size_t i = 0; i < cam_count; ++i) + { + std::string camFile(camdbc.getRecord(i).getString(1)); + size_t loc = camFile.find(".mdx"); + if (loc != std::string::npos) + camFile.replace(loc, 4, ".m2"); + camerafiles.push_back(std::string(camFile)); + } + + std::string path = output_path; + path += "/Cameras/"; + CreateDir(path); + // extract M2s + uint32 count = 0; + for (std::vector::iterator iter = camerafiles.begin(); iter != camerafiles.end(); ++iter) + { + std::string filename = path; + filename += (iter->c_str() + strlen("Cameras\\")); + + if (ExtractFile(iter->c_str(), filename)) + ++count; + } + + printf("Extracted %u camera files\n", count); +} + void LoadLocaleMPQFiles(int const locale) { char filename[512]; @@ -1195,6 +1247,16 @@ void LoadBaseMPQFiles() HANDLE worldMpqHandle; printf("Loaded MPQ files for map extraction:\n"); + + sprintf(filename, "%s/Data/Art.MPQ", input_path); + printf("%s\n", filename); + + if (!OpenArchive(filename, &worldMpqHandle)) + { + printf("Error open archive: %s\n\n", filename); + return; + } + for (int i = 1; i <= WORLD_COUNT; i++) { sprintf(filename, "%s/Data/World%s.MPQ", input_path, (i == 2 ? "2" : "")); @@ -1291,6 +1353,21 @@ int main(int argc, char* arg[]) return 0; } + if (CONF_extract & EXTRACT_CAMERA) + { + printf("Using locale: %s\n", langs[FirstLocale]); + + // Open MPQs + LoadBaseMPQFiles(); + LoadLocaleMPQFiles(FirstLocale); + + // Extract Cameras + ExtractCameraFiles(FirstLocale); + + // Close MPQs + CloseArchives(); + } + if (CONF_extract & EXTRACT_MAP) { printf("Using locale: %s\n", langs[FirstLocale]); diff --git a/contrib/extractor/dbcfile.h b/contrib/extractor/dbcfile.h index 54d7db859d..9d562bc865 100644 --- a/contrib/extractor/dbcfile.h +++ b/contrib/extractor/dbcfile.h @@ -45,17 +45,17 @@ class DBCFile float getFloat(size_t field) const { assert(field < file.fieldCount); - return *reinterpret_cast(offset + (field * 4)); + return *reinterpret_cast(offset + field * 4); } unsigned int getUInt(size_t field) const { assert(field < file.fieldCount); - return *reinterpret_cast(offset + (field * 4)); + return *reinterpret_cast(offset + field * 4); } int getInt(size_t field) const { assert(field < file.fieldCount); - return *reinterpret_cast(offset + (field * 4)); + return *reinterpret_cast(offset + field * 4); } const char* getString(size_t field) const { diff --git a/src/game/Chat/debugcmds.cpp b/src/game/Chat/debugcmds.cpp index c261c55aaa..aaac76e8df 100644 --- a/src/game/Chat/debugcmds.cpp +++ b/src/game/Chat/debugcmds.cpp @@ -30,6 +30,7 @@ #include "Globals/ObjectMgr.h" #include "Entities/ObjectGuid.h" #include "Spells/SpellMgr.h" +#include "Cinematics/M2Stores.h" bool ChatHandler::HandleDebugSendSpellFailCommand(char* args) { @@ -227,6 +228,23 @@ bool ChatHandler::HandleDebugPlayCinematicCommand(char* args) return false; } + // Dump camera locations + if (CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(dwId)) + { + std::unordered_map::const_iterator itr = sFlyByCameraStore.find(cineSeq->cinematicCamera); + if (itr != sFlyByCameraStore.end()) + { + PSendSysMessage("Waypoints for sequence %u, camera %u", dwId, cineSeq->cinematicCamera); + uint32 count = 1; + for (FlyByCamera cam : itr->second) + { + 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)); + count++; + } + PSendSysMessage("%u waypoints dumped", itr->second.size()); + } + } + m_session->GetPlayer()->SendCinematicStart(dwId); return true; } diff --git a/src/game/Cinematics/CinematicMgr.cpp b/src/game/Cinematics/CinematicMgr.cpp new file mode 100644 index 0000000000..b04004528a --- /dev/null +++ b/src/game/Cinematics/CinematicMgr.cpp @@ -0,0 +1,188 @@ +/* +* This file is part of the CMaNGOS 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 General Public License as published by +* the Free Software Foundation; either version 2 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "CinematicMgr.h" +#include "Entities/Player.h" + +CinematicMgr::CinematicMgr(Player* playerref) +{ + player = playerref; + m_cinematicDiff = 0; + m_lastCinematicCheck = 0; + m_activeCinematicCameraId = 0; + m_cinematicLength = 0; + m_cinematicCamera = nullptr; + m_remoteSightPosition = { 0.0f, 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; + + 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 (!MaNGOS::IsValidMapCoord(pos.x, pos.y, pos.z, pos.o)) + return; + + player->GetMap()->ForceLoadGrid(camitr->locations.x, camitr->locations.y); + m_CinematicObject = player->SummonCreature(VISUAL_WAYPOINT, pos.x, pos.y, pos.z, 0.0f, TEMPSPAWN_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS); + if (m_CinematicObject) + { + m_CinematicObject->SetActiveObjectState(true); + player->GetCamera().SetView(m_CinematicObject, true); + } + + // Get cinematic length + FlyByCameraCollection::const_reverse_iterator camrevitr = m_cinematicCamera->rbegin(); + if (camrevitr != m_cinematicCamera->rend()) + m_cinematicLength = camrevitr->timeStamp; + else + m_cinematicLength = 0; + } + } +} + +void CinematicMgr::EndCinematic() +{ + if (m_activeCinematicCameraId == 0) + return; + + m_cinematicDiff = 0; + m_cinematicCamera = nullptr; + m_activeCinematicCameraId = 0; + if (m_CinematicObject) + { + if (WorldObject* vpObject = player->GetCamera().GetBody()) + if (vpObject == m_CinematicObject) + player->GetCamera().ResetView(); + + m_CinematicObject->AddObjectToRemoveList(); + } +} + +bool CinematicMgr::UpdateCinematicLocation(uint32 /*diff*/) +{ + // should not occur + if (m_activeCinematicCameraId == 0) + return false; + + // 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(); + return false; + } + + // just created and waiting BeginCinematic call + if (!m_cinematicCamera || m_cinematicCamera->size() == 0) + return true; + + 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 = { cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w }; + nextTimestamp = cam.timeStamp; + break; + } + lastPosition = { cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w }; + lastTimestamp = cam.timeStamp; + } + + float dx = nextPosition.x - lastPosition.x; + float dy = nextPosition.y - lastPosition.y; + + float angle = std::atan2(dy, dx); + angle = (angle >= 0) ? angle : 2 * float(M_PI) + angle; + + angle -= lastPosition.o; + 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(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(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(cam.timeStamp) >= workDiff) + { + nextPosition = { cam.locations.x, cam.locations.y, cam.locations.z, cam.locations.w }; + nextTimestamp = cam.timeStamp; + break; + } + lastPosition = { 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(nextTimestamp)) + workDiff = static_cast(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.x - lastPosition.x; + float yDiff = nextPosition.y - lastPosition.y; + float zDiff = nextPosition.z - lastPosition.z; + Position interPosition = { lastPosition.x + (xDiff * (float(interDiff) / float(timeDiff))), lastPosition.y + + (yDiff * (float(interDiff) / float(timeDiff))), lastPosition.z + (zDiff * (float(interDiff) / float(timeDiff))), 0.0f }; + + // Advance (at speed) to this position. The remote sight object is used + // to send update information to player in cinematic + if (m_CinematicObject && MaNGOS::IsValidMapCoord(interPosition.x, interPosition.y, interPosition.z, interPosition.o)) + m_CinematicObject->MonsterMoveWithSpeed(interPosition.x, interPosition.y, interPosition.z, 500.0f, false, true); + + return true; +} diff --git a/src/game/Cinematics/CinematicMgr.h b/src/game/Cinematics/CinematicMgr.h new file mode 100644 index 0000000000..26c13a4016 --- /dev/null +++ b/src/game/Cinematics/CinematicMgr.h @@ -0,0 +1,62 @@ +/* +* This file is part of the CMaNGOS 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 General Public License as published by +* the Free Software Foundation; either version 2 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MANGOS_CINEMATICMGR_H +#define MANGOS_CINEMATICMGR_H + +#include "Entities/Object.h" +#include "M2Stores.h" + +#define CINEMATIC_LOOKAHEAD (2 * IN_MILLISECONDS) +#define CINEMATIC_UPDATEDIFF 200 + +class Player; +class CinematicMgr; + +typedef std::unique_ptr CinematicMgrUPtr; + +class 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(); + bool UpdateCinematicLocation(uint32 diff); + +private: + // Remote location information + Player* player; + +protected: + uint32 m_cinematicDiff; + uint32 m_lastCinematicCheck; + uint32 m_activeCinematicCameraId; + uint32 m_cinematicLength; + FlyByCameraCollection* m_cinematicCamera; + Position m_remoteSightPosition; + Creature* m_CinematicObject; +}; + +#endif diff --git a/src/game/Cinematics/M2Stores.cpp b/src/game/Cinematics/M2Stores.cpp new file mode 100644 index 0000000000..688fc26615 --- /dev/null +++ b/src/game/Cinematics/M2Stores.cpp @@ -0,0 +1,258 @@ +/* +* This file is part of the CMaNGOS 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 General Public License as published by +* the Free Software Foundation; either version 2 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Server/DBCStores.h" +#include "M2Structure.h" +#include "M2Stores.h" +#include "Common.h" +#include "Log.h" +#include "World/World.h" +#include +#include + +std::unordered_map sFlyByCameraStore; + +// Convert the geomoetry from a spline value, to an actual world 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 = 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(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(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(buffer + targTsArray->offset_elements); + M2Array const* targArray = reinterpret_cast(buffer + cam->target_positions.values.offset_elements); + + if (targArray->offset_elements + sizeof(M2SplineKey) > buffSize) + return false; + M2SplineKey const* targPositions = reinterpret_cast 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) > 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); + } + } + + // 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(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(buffer + posTsArray->offset_elements); + M2Array const* posArray = reinterpret_cast(buffer + cam->positions.values.offset_elements); + if (posArray->offset_elements + sizeof(M2SplineKey) > buffSize) + return false; + M2SplineKey const* positions = reinterpret_cast 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) > 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); + } + + cameras.push_back(thisCam); + positions++; + currPos += sizeof(M2SplineKey); + } + } + + sFlyByCameraStore[dbcentry->ID] = cameras; + return true; +} + +void LoadM2Cameras(std::string const& dataPath) +{ + sFlyByCameraStore.clear(); + + uint32 oldMSTime = WorldTimer::getMSTime(); + for (uint32 i = 0; i < sCinematicCameraStore.GetNumRows(); ++i) + { + if (CinematicCameraEntry const* dbcentry = sCinematicCameraStore.LookupEntry(i)) + { + std::string filename = dataPath; + filename.append(dbcentry->Model); + + // Replace slashes + std::replace(filename.begin(), filename.end(), '\\', '/'); + + // Replace mdx to .m2 + size_t 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(fileSize) < sizeof(M2Header)) + { + sLog.outError("Camera file %s is damaged. File is smaller than header size", filename.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")) + { + sLog.outError("Camera file %s is damaged. File identifier not found", filename.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 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(buffer.data()); + + if (header->ofsCameras + sizeof(M2Camera) > static_cast(fileSize)) + { + sLog.outError("Camera file %s is damaged. Camera references position beyond file end (header)", filename.c_str()); + continue; + } + + // Get camera(s) - Main header, then dump them. + M2Camera const* cam = reinterpret_cast(buffer.data() + header->ofsCameras); + if (!readCamera(cam, fileSize, header, dbcentry)) + sLog.outError("Camera file %s is damaged. Camera references position beyond file end (camera)", filename.c_str()); + } + } + sLog.outString(">> Loaded %u cinematic waypoint sets in %u ms", static_cast(sFlyByCameraStore.size()), WorldTimer::getMSTimeDiff(oldMSTime, WorldTimer::getMSTime())); + sLog.outString(); +} diff --git a/src/game/Cinematics/M2Stores.h b/src/game/Cinematics/M2Stores.h new file mode 100644 index 0000000000..efcc08439e --- /dev/null +++ b/src/game/Cinematics/M2Stores.h @@ -0,0 +1,43 @@ +/* +* This file is part of the CMaNGOS 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 General Public License as published by +* the Free Software Foundation; either version 2 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MANGOS_M2STORES_H +#define MANGOS_M2STORES_H + +#include "Common.h" + +struct CamLocation +{ + CamLocation() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {} + CamLocation(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {} + float x, y, z, w; +}; + +struct FlyByCamera +{ + uint32 timeStamp; + CamLocation locations; +}; + +typedef std::vector FlyByCameraCollection; + +extern std::unordered_map sFlyByCameraStore; + +void LoadM2Cameras(std::string const& dataPath); + +#endif diff --git a/src/game/Cinematics/M2Structure.h b/src/game/Cinematics/M2Structure.h new file mode 100644 index 0000000000..9c8e90ae73 --- /dev/null +++ b/src/game/Cinematics/M2Structure.h @@ -0,0 +1,149 @@ +/* +* This file is part of the CMaNGOS 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 General Public License as published by +* the Free Software Foundation; either version 2 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MANGOS_M2STRUCTURE_H +#define MANGOS_M2STRUCTURE_H + +#include +#include + +#define VERSION_ORGINAL_MIN 0 +#define VERSION_ORGINAL_MAX 256 +#define VERSION_BC_MIN 260 +#define VERSION_BC_MAX 263 +#define VERSION_WRATH_MIN 264 +#define VERSION_WRATH_MAX 264 +#define VERSION_CATA_MIN 265 +#define VERSION_CATA_MAX 271 +#define VERSION_MISTS_MIN 272 +#define VERSION_MISTS_MAX 272 +#define VERSION_WOD_MIN 272 +#define VERSION_WOD_MAX 272 +#define VERSION_LEGION_MIN 274 +#define VERSION_LEGION_MAX 274 + +// Structures for M2 file. Source: https://wowdev.wiki +#pragma pack(push, 1) +template +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 diff --git a/src/game/Entities/MiscHandler.cpp b/src/game/Entities/MiscHandler.cpp index c5ebcb0812..775c7a60e9 100644 --- a/src/game/Entities/MiscHandler.cpp +++ b/src/game/Entities/MiscHandler.cpp @@ -962,11 +962,15 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data) void WorldSession::HandleCompleteCinematic(WorldPacket& /*recv_data*/) { DEBUG_LOG("WORLD: Received opcode CMSG_COMPLETE_CINEMATIC"); + // If player has sight bound to visual waypoint NPC we should remove it + GetPlayer()->GetCinematicMgr()->EndCinematic(); } void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recv_data*/) { DEBUG_LOG("WORLD: Received opcode CMSG_NEXT_CINEMATIC_CAMERA"); + // Sent by client when cinematic actually begun. So we begin the server side process + GetPlayer()->GetCinematicMgr()->BeginCinematic(); } void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recv_data) diff --git a/src/game/Entities/Player.cpp b/src/game/Entities/Player.cpp index 64102c81f2..3a972fa034 100644 --- a/src/game/Entities/Player.cpp +++ b/src/game/Entities/Player.cpp @@ -586,6 +586,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_ m_isGhouled = false; m_createdInstanceClearTimer = MINUTE * IN_MILLISECONDS; + + _cinematicMgr = new CinematicMgr(this); } Player::~Player() @@ -639,6 +641,7 @@ Player::~Player() m_playerbotMgr = 0; } #endif + delete _cinematicMgr; } void Player::CleanupsBeforeDelete() @@ -1248,6 +1251,14 @@ void Player::Update(uint32 update_diff, uint32 p_time) if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK)) setAttackTimer(RANGED_ATTACK, (update_diff >= ranged_att ? 0 : ranged_att - update_diff)); + // Update cinematic location, if 500ms have passed and we're doing a cinematic now. + _cinematicMgr->m_cinematicDiff += p_time; + if (_cinematicMgr->m_activeCinematicCameraId != 0 && WorldTimer::getMSTimeDiff(_cinematicMgr->m_lastCinematicCheck, WorldTimer::getMSTime()) > CINEMATIC_UPDATEDIFF) + { + _cinematicMgr->m_lastCinematicCheck = WorldTimer::getMSTime(); + _cinematicMgr->UpdateCinematicLocation(p_time); + } + // Used to implement delayed far teleports SetCanDelayTeleport(true); Unit::Update(update_diff, p_time); @@ -6494,6 +6505,8 @@ void Player::SendCinematicStart(uint32 CinematicSequenceId) WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4); data << uint32(CinematicSequenceId); SendDirectMessage(data); + if (CinematicSequencesEntry const* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId)) + _cinematicMgr->SetActiveCinematicCamera(sequence->cinematicCamera); } void Player::SendMovieStart(uint32 MovieId) diff --git a/src/game/Entities/Player.h b/src/game/Entities/Player.h index 1ebfeadbe4..56b44a15c8 100644 --- a/src/game/Entities/Player.h +++ b/src/game/Entities/Player.h @@ -39,6 +39,7 @@ #include "Chat/Chat.h" #include "Server/SQLStorages.h" #include "Server/DBCStores.h" +#include "Cinematics/CinematicMgr.h" #include @@ -1040,6 +1041,7 @@ class TradeData class Player : public Unit { friend class WorldSession; + friend class CinematicMgr; friend void Item::AddToUpdateQueueOf(Player* player); friend void Item::RemoveFromUpdateQueueOf(Player* player); public: @@ -1189,6 +1191,8 @@ class Player : public Unit void TextEmote(const std::string& text); void Whisper(const std::string& text, const uint32 language, ObjectGuid receiver); + CinematicMgr* GetCinematicMgr() const { return _cinematicMgr; } + /*********************************************************/ /*** STORAGE SYSTEM ***/ /*********************************************************/ @@ -2741,6 +2745,8 @@ class Player : public Unit void _fillGearScoreData(Item* item, GearScoreVec* gearScore, uint32& twoHandScore); + CinematicMgr* _cinematicMgr; + Unit* m_mover; Camera m_camera; diff --git a/src/game/Maps/Map.cpp b/src/game/Maps/Map.cpp index 62e7eaff62..004ab7c43d 100644 --- a/src/game/Maps/Map.cpp +++ b/src/game/Maps/Map.cpp @@ -470,6 +470,31 @@ bool Map::loaded(const GridPair& p) const return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); } +void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor& gridVisitor, TypeContainerVisitor& worldVisitor) +{ + // lets update mobs/objects in ALL visible cells around player! + CellArea area = Cell::CalculateCellArea(obj->GetPositionX(), obj->GetPositionY(), GetVisibilityDistance()); + + for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x) + { + for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y) + { + // marked cells are those that have been visited + // don't visit the same cell twice + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (!isCellMarked(cell_id)) + { + markCell(cell_id); + CellPair pair(x, y); + Cell cell(pair); + cell.SetNoCreate(); + Visit(cell, gridVisitor); + Visit(cell, worldVisitor); + } + } + } +} + void Map::Update(const uint32& t_diff) { m_dyn_tree.update(t_diff); @@ -524,27 +549,11 @@ void Map::Update(const uint32& t_diff) if (!plr->IsInWorld() || !plr->IsPositionValid()) continue; - // lets update mobs/objects in ALL visible cells around player! - CellArea area = Cell::CalculateCellArea(plr->GetPositionX(), plr->GetPositionY(), GetVisibilityDistance()); + VisitNearbyCellsOf(plr, grid_object_update, world_object_update); - for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x) - { - for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y) - { - // marked cells are those that have been visited - // don't visit the same cell twice - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - { - markCell(cell_id); - CellPair pair(x, y); - Cell cell(pair); - cell.SetNoCreate(); - Visit(cell, grid_object_update); - Visit(cell, world_object_update); - } - } - } + // If player is using far sight, visit that object too + if (WorldObject* viewPoint = GetWorldObject(plr->GetFarSightGuid())) + VisitNearbyCellsOf(viewPoint, grid_object_update, world_object_update); } // non-player active objects diff --git a/src/game/Maps/Map.h b/src/game/Maps/Map.h index 24f78a05ce..9a3a5082ff 100644 --- a/src/game/Maps/Map.h +++ b/src/game/Maps/Map.h @@ -52,6 +52,7 @@ class BattleGround; class GridMap; class GameObjectModel; class WeatherSystem; +namespace MaNGOS { struct ObjectUpdater; } // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform #if defined( __GNUC__ ) @@ -118,6 +119,7 @@ class Map : public GridRefManager static void DeleteFromWorld(Player* player); // player object will deleted at call + void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor& gridVisitor, TypeContainerVisitor& worldVisitor); virtual void Update(const uint32&); void MessageBroadcast(Player const*, WorldPacket const&, bool to_self); diff --git a/src/game/Server/DBCEnums.h b/src/game/Server/DBCEnums.h index 592a238718..ba881f2a99 100644 --- a/src/game/Server/DBCEnums.h +++ b/src/game/Server/DBCEnums.h @@ -42,6 +42,23 @@ enum BattleGroundBracketId // bracketId for lev // must be max value in PvPDificulty slot+1 #define MAX_BATTLEGROUND_BRACKETS 16 +#pragma pack(push, 1) + +struct DBCPosition2D +{ + float X; + float Y; +}; + +struct DBCPosition3D +{ + float X; + float Y; + float Z; +}; + +#pragma pack(pop) + enum AreaTeams { AREATEAM_NONE = 0, diff --git a/src/game/Server/DBCStores.cpp b/src/game/Server/DBCStores.cpp index 5bd2b3ea3b..4be35b6559 100644 --- a/src/game/Server/DBCStores.cpp +++ b/src/game/Server/DBCStores.cpp @@ -75,6 +75,7 @@ uint32 sChrClassXPowerTypesStore[MAX_CLASSES][MAX_POWERS]; // pair => power uint32 sChrClassXPowerIndexStore[MAX_CLASSES][MAX_STORED_POWERS]; DBCStorage sChrRacesStore(ChrRacesEntryfmt); +DBCStorage sCinematicCameraStore(CinematicCameraEntryfmt); DBCStorage sCinematicSequencesStore(CinematicSequencesEntryfmt); DBCStorage sCreatureDisplayInfoStore(CreatureDisplayInfofmt); DBCStorage sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt); @@ -484,6 +485,7 @@ void LoadDBCStores(const std::string& dataPath) sChrClassXPowerIndexStore[entry->classId][index] = entry->power; } LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrRacesStore, dbcPath,"ChrRaces.dbc"); + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCinematicCameraStore, dbcPath,"CinematicCamera.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCinematicSequencesStore, dbcPath,"CinematicSequences.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoStore, dbcPath,"CreatureDisplayInfo.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCreatureDisplayInfoExtraStore,dbcPath,"CreatureDisplayInfoExtra.dbc"); diff --git a/src/game/Server/DBCStores.h b/src/game/Server/DBCStores.h index db548e25dd..fb377d273a 100644 --- a/src/game/Server/DBCStores.h +++ b/src/game/Server/DBCStores.h @@ -120,6 +120,7 @@ extern DBCStorage sChrPowerTypesStore; extern uint32 sChrClassXPowerTypesStore[MAX_CLASSES][MAX_POWERS]; extern uint32 sChrClassXPowerIndexStore[MAX_CLASSES][MAX_STORED_POWERS]; extern DBCStorage sChrRacesStore; +extern DBCStorage sCinematicCameraStore; extern DBCStorage sCinematicSequencesStore; extern DBCStorage sCreatureDisplayInfoStore; extern DBCStorage sCreatureDisplayInfoExtraStore; diff --git a/src/game/Server/DBCStructure.h b/src/game/Server/DBCStructure.h index 0e238299cd..1ecf149330 100644 --- a/src/game/Server/DBCStructure.h +++ b/src/game/Server/DBCStructure.h @@ -722,22 +722,20 @@ struct ChrPowerTypesEntry uint32 power; // 2 }; -/*struct CinematicCameraEntry +struct CinematicCameraEntry { - uint32 id; // 0 m_ID - char* filename; // 1 m_model - uint32 soundid; // 2 m_soundID - float start_x; // 3 m_originX - float start_y; // 4 m_originY - float start_z; // 5 m_originZ - float unk6; // 6 m_originFacing -};*/ + uint32 ID; // 0 + char const* Model; // 1 Model filename (translate .mdx to .m2) + uint32 SoundID; // 2 Sound ID (voiceover for cinematic) + DBCPosition3D Origin; // 3-5 Position in map used for basis for M2 co-ordinates + float OriginFacing; // 6 Orientation in map used for basis for M2 co-ordinates +}; struct CinematicSequencesEntry { uint32 Id; // 0 m_ID //uint32 unk1; // 1 m_soundID - //uint32 cinematicCamera; // 2 m_camera[8] + uint32 cinematicCamera; // 2 m_camera[8] }; struct CreatureDisplayInfoEntry diff --git a/src/game/Server/DBCfmt.h b/src/game/Server/DBCfmt.h index 18cf317ad1..b1e23f6dbc 100644 --- a/src/game/Server/DBCfmt.h +++ b/src/game/Server/DBCfmt.h @@ -34,7 +34,8 @@ const char ChatChannelsEntryfmt[]="iixsx"; // ChatChannelsEntryfmt, index const char ChrClassesEntryfmt[]="nixsxxxixiiiii"; const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx"; const char ChrClassesXPowerTypesfmt[]="nii"; -const char CinematicSequencesEntryfmt[]="nxxxxxxxxx"; +const char CinematicCameraEntryfmt[] = "nsiffff"; +const char CinematicSequencesEntryfmt[] = "nxixxxxxxx"; const char CreatureDisplayInfofmt[]="nixifxxxxxxxxxxxx"; const char CreatureDisplayInfoExtrafmt[]="nixxxxxxxxxxxxxxxxxxx"; const char CreatureFamilyfmt[]="nfifiiiiixsx"; diff --git a/src/game/World/World.cpp b/src/game/World/World.cpp index 94129a8dd5..edd6cfa123 100644 --- a/src/game/World/World.cpp +++ b/src/game/World/World.cpp @@ -967,6 +967,9 @@ void World::SetInitialWorldSettings() DetectDBCLang(); sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) + sLog.outString("Loading Cinematics..."); + LoadM2Cameras(m_dataPath); + sLog.outString("Loading Script Names..."); sScriptDevAIMgr.LoadScriptNames();