From 87b4533046d337fe05d7891c3632d34f8811b73e Mon Sep 17 00:00:00 2001 From: r00ty-tc Date: Thu, 14 Apr 2016 01:34:17 +0200 Subject: [Core/Maps] Activate creatures and objects during opening cinematics and other flyby cameras (sunwell etc). Requires re-running map extractor to extract camera m2 files from data files. These are very small. Closes #4755 Closes #16772 --- src/server/game/DataStores/DBCStores.cpp | 247 +++++++++++++++++++++++++++++ src/server/game/DataStores/DBCStores.h | 5 + src/server/game/DataStores/DBCStructure.h | 12 +- src/server/game/DataStores/DBCfmt.h | 3 +- src/server/game/Entities/Object/Object.cpp | 18 +++ src/server/game/Entities/Player/Player.cpp | 144 ++++++++++++++++- src/server/game/Entities/Player/Player.h | 21 ++- src/server/game/Handlers/MiscHandler.cpp | 6 +- src/server/game/Maps/Map.cpp | 13 +- 9 files changed, 454 insertions(+), 15 deletions(-) (limited to 'src/server/game') diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 0e9b50d64c5..5ede70da2a3 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -27,6 +27,9 @@ #include #include +#include +#include +#include typedef std::map AreaFlagByAreaID; typedef std::map AreaFlagByMapID; @@ -73,6 +76,7 @@ DBCStorage sCharTitlesStore(CharTitlesEntryfmt); DBCStorage sChatChannelsStore(ChatChannelsEntryfmt); DBCStorage sChrClassesStore(ChrClassesEntryfmt); DBCStorage sChrRacesStore(ChrRacesEntryfmt); +DBCStorage sCinematicCameraStore(CinematicCameraEntryfmt); DBCStorage sCinematicSequencesStore(CinematicSequencesEntryfmt); DBCStorage sCreatureDisplayInfoStore(CreatureDisplayInfofmt); DBCStorage sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt); @@ -217,6 +221,8 @@ DBCStorage sWorldMapAreaStore(WorldMapAreaEntryfmt); DBCStorage sWorldMapOverlayStore(WorldMapOverlayEntryfmt); DBCStorage sWorldSafeLocsStore(WorldSafeLocsEntryfmt); +std::unordered_map sFlyByCameraStore; + typedef std::list StoreProblemList; uint32 DBCFileCount = 0; @@ -311,6 +317,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sChatChannelsStore, dbcPath, "ChatChannels.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sChrClassesStore, dbcPath, "ChrClasses.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sChrRacesStore, dbcPath, "ChrRaces.dbc"); + LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicCameraStore, dbcPath, "CinematicCamera.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoExtraStore, dbcPath, "CreatureDisplayInfoExtra.dbc"); @@ -717,10 +724,250 @@ void LoadDBCStores(const std::string& dataPath) exit(1); } + LoadM2Cameras(dataPath); + TC_LOG_INFO("server.loading", ">> Initialized %d data stores in %u ms", DBCFileCount, GetMSTimeDiffToNow(oldMSTime)); } +// 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 = 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->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(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); + + if (thisCam.locations.w < 0) + thisCam.locations.w += 2 * float(M_PI); + } + + cameras.push_back(thisCam); + positions++; + currPos += sizeof(M2SplineKey); + } + } + + sFlyByCameraStore[dbcentry->id] = cameras; + return true; +} + +void LoadM2Cameras(const std::string& dataPath) +{ + sFlyByCameraStore.clear(); + TC_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(fileSize) < sizeof(M2Header)) + { + TC_LOG_ERROR("server.loading", "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")) + { + TC_LOG_ERROR("server.loading", "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)) + { + TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", 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)) + TC_LOG_ERROR("server.loading", "Camera file %s is damaged. Camera references position beyond file end", filename.c_str()); + } + } + TC_LOG_INFO("server.loading", ">> Loaded %u cinematic waypoint sets in %u ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime)); +} + SimpleFactionsList const* GetFactionTeamList(uint32 faction) { FactionTeamMap::const_iterator itr = sFactionTeamMap.find(faction); diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index beb0bb514cc..6cad13fdf9a 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -27,6 +27,8 @@ #include typedef std::list SimpleFactionsList; +typedef std::vector FlyByCameraCollection; + TC_GAME_API SimpleFactionsList const* GetFactionTeamList(uint32 faction); TC_GAME_API char* GetPetName(uint32 petfamily, uint32 dbclang); @@ -96,6 +98,7 @@ TC_GAME_API extern DBCStorage sCharSectionsStore; TC_GAME_API extern DBCStorage sCharTitlesStore; TC_GAME_API extern DBCStorage sChrClassesStore; TC_GAME_API extern DBCStorage sChrRacesStore; +TC_GAME_API extern DBCStorage sCinematicCameraStore; TC_GAME_API extern DBCStorage sCinematicSequencesStore; TC_GAME_API extern DBCStorage sCreatureDisplayInfoStore; TC_GAME_API extern DBCStorage sCreatureDisplayInfoExtraStore; @@ -193,7 +196,9 @@ TC_GAME_API extern DBCStorage sWMOAreaTableStore; //TC_GAME_API extern DBCStorage sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates TC_GAME_API extern DBCStorage sWorldMapOverlayStore; TC_GAME_API extern DBCStorage sWorldSafeLocsStore; +TC_GAME_API extern std::unordered_map sFlyByCameraStore; TC_GAME_API void LoadDBCStores(const std::string& dataPath); +TC_GAME_API void LoadM2Cameras(const std::string& dataPath); #endif diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index b5dc4489148..51b3dcbd38b 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -725,24 +725,22 @@ struct ChrRacesEntry uint32 expansion; // 68 (0 - original race, 1 - tbc addon, ...) }; -/* not used struct CinematicCameraEntry { uint32 id; // 0 index char* filename; // 1 uint32 soundid; // 2 in SoundEntries.dbc or 0 - float start_x; // 3 - float start_y; // 4 - float start_z; // 5 - float unk6; // 6 speed? + float base_x; // 3 + float base_y; // 4 + float base_z; // 5 + float base_o; // 6 }; -*/ struct CinematicSequencesEntry { uint32 Id; // 0 index //uint32 unk1; // 1 always 0 - //uint32 cinematicCamera; // 2 id in CinematicCamera.dbc + uint32 cinematicCamera; // 2 id in CinematicCamera.dbc // 3-9 always 0 }; diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index c61ec997bc2..1accc81714b 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -38,7 +38,8 @@ char const CharTitlesEntryfmt[] = "nxssssssssssssssssxssssssssssssssssxi"; char const ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; char const ChrClassesEntryfmt[] = "nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; char const ChrRacesEntryfmt[] = "niixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; -char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx"; +char const CinematicCameraEntryfmt[] = "nsiffff"; +char const CinematicSequencesEntryfmt[] = "nxixxxxxxx"; char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxx"; char const CreatureDisplayInfoExtrafmt[] = "diixxxxxxxxxxxxxxxxxx"; char const CreatureFamilyfmt[] = "nfifiiiiixssssssssssssssssxx"; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 12f2c169fe5..45952ba51ac 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1470,9 +1470,20 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const float WorldObject::GetGridActivationRange() const { if (ToPlayer()) + { + if (ToPlayer()->IsOnCinematic()) + return DEFAULT_VISIBILITY_INSTANCE; return GetMap()->GetVisibilityRange(); + } else if (ToCreature()) return ToCreature()->m_SightDistance; + else if (ToDynObject()) + { + if (isActiveObject()) + return GetMap()->GetVisibilityRange(); + else + return 0.0f; + } else return 0.0f; } @@ -1493,6 +1504,8 @@ float WorldObject::GetSightRange(const WorldObject* target) const { if (target && target->isActiveObject() && !target->ToPlayer()) return MAX_VISIBILITY_DISTANCE; + else if (ToPlayer()->IsOnCinematic()) + return DEFAULT_VISIBILITY_INSTANCE; else return GetMap()->GetVisibilityRange(); } @@ -1502,6 +1515,11 @@ float WorldObject::GetSightRange(const WorldObject* target) const return SIGHT_RANGE_UNIT; } + if (ToDynObject() && isActiveObject()) + { + return GetMap()->GetVisibilityRange(); + } + return 0.0f; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8b50d1fb406..c58f2c940fc 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -96,6 +96,9 @@ #define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x)) #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) +#define CINEMATIC_LOOKAHEAD (2 * IN_MILLISECONDS) +#define CINEMATIC_UPDATEDIFF 500 + enum CharacterFlags { CHARACTER_FLAG_NONE = 0x00000000, @@ -535,6 +538,14 @@ Player::Player(WorldSession* session): Unit(true) _activeCheats = CHEAT_NONE; healthBeforeDuel = 0; manaBeforeDuel = 0; + + m_cinematicDiff = 0; + 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_reputationMgr = new ReputationMgr(this); } @@ -1224,7 +1235,15 @@ void Player::Update(uint32 p_time) m_spellModTakingSpell = nullptr; } - //used to implement delayed far teleport + // Update cinematic location, if 500ms have passed and we're doing a cinematic now. + m_cinematicDiff += p_time; + if (m_cinematicCamera && m_activeCinematicCameraId && GetMSTimeDiffToNow(m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF) + { + m_lastCinematicCheck = getMSTime(); + UpdateCinematicLocation(p_time); + } + + //used to implement delayed far teleports SetCanDelayTeleport(true); Unit::Update(p_time); SetCanDelayTeleport(false); @@ -6398,11 +6417,13 @@ void Player::SendDirectMessage(WorldPacket const* data) const m_session->SendPacket(data); } -void Player::SendCinematicStart(uint32 CinematicSequenceId) const +void Player::SendCinematicStart(uint32 CinematicSequenceId) { WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4); data << uint32(CinematicSequenceId); SendDirectMessage(&data); + if (const CinematicSequencesEntry* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId)) + SetActiveCinematicCamera(sequence->cinematicCamera); } void Player::SendMovieStart(uint32 MovieId) const @@ -26189,6 +26210,125 @@ float Player::GetCollisionHeight(bool mounted) const } } +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(); + } +} + +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(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 = 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(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.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, false, true); +} + + std::string Player::GetMapAreaAndZoneString() const { uint32 areaId = GetAreaId(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index b8719d3e927..fd0fac69674 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2129,7 +2129,7 @@ class TC_GAME_API Player : public Unit, public GridObject void ResummonPetTemporaryUnSummonedIfAny(); bool IsPetNeedBeTemporaryUnsummoned() const; - void SendCinematicStart(uint32 CinematicSequenceId) const; + void SendCinematicStart(uint32 CinematicSequenceId); void SendMovieStart(uint32 MovieId) const; /*********************************************************/ @@ -2265,6 +2265,17 @@ class TC_GAME_API Player : public Unit, public GridObject std::string GetMapAreaAndZoneString() const; std::string GetCoordsMapAreaAndZoneString() const; + // 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); + + std::string GetMapAreaAndZoneString(); + std::string GetCoordsMapAreaAndZoneString(); + protected: // Gamemaster whisper whitelist GuidList WhisperList; @@ -2590,6 +2601,14 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 manaBeforeDuel; WorldLocation _corpseLocation; + + // Remote location information + uint32 m_cinematicDiff; + uint32 m_lastCinematicCheck; + uint32 m_activeCinematicCameraId; + FlyByCameraCollection* m_cinematicCamera; + Position m_remoteSightPosition; + Creature* m_CinematicObject; }; TC_GAME_API void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 9efdfce9243..467d3730ab2 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1056,12 +1056,14 @@ void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recvData) void WorldSession::HandleCompleteCinematic(WorldPacket& /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Received CMSG_COMPLETE_CINEMATIC"); + // If player has sight bound to visual waypoint NPC we should remove it + GetPlayer()->EndCinematic(); } void WorldSession::HandleNextCinematicCamera(WorldPacket& /*recvData*/) { - TC_LOG_DEBUG("network", "WORLD: Received CMSG_NEXT_CINEMATIC_CAMERA"); + // Sent by client when cinematic actually begun. So we begin the server side process + GetPlayer()->BeginCinematic(); } void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 18fabd20f24..664ed3dc8ec 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -714,6 +714,15 @@ void Map::Update(const uint32 t_diff) VisitNearbyCellsOf(player, grid_object_update, world_object_update); + // If player is using far sight, visit that object too + if (WorldObject* viewPoint = player->GetViewpoint()) + { + if (Creature* viewCreature = viewPoint->ToCreature()) + VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update); + else if (DynamicObject* viewObject = viewPoint->ToDynObject()) + VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update); + } + // Handle updates for creatures in combat with player and are more than 60 yards away if (player->IsInCombat()) { @@ -2658,8 +2667,8 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellCoord cellpa cell.SetNoCreate(); TypeContainerVisitor world_notifier(notifier); TypeContainerVisitor grid_notifier(notifier); - cell.Visit(cellpair, world_notifier, *this, *player, player->GetSightRange()); - cell.Visit(cellpair, grid_notifier, *this, *player, player->GetSightRange()); + cell.Visit(cellpair, world_notifier, *this, *player->m_seer, player->GetSightRange()); + cell.Visit(cellpair, grid_notifier, *this, *player->m_seer, player->GetSightRange()); // send data notifier.SendToSelf(); -- cgit v1.2.3