[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
This commit is contained in:
r00ty-tc
2016-04-14 01:34:17 +02:00
parent afaa8e2c60
commit 87b4533046
12 changed files with 655 additions and 20 deletions
+247
View File
@@ -27,6 +27,9 @@
#include <boost/regex.hpp>
#include <map>
#include <fstream>
#include <iostream>
#include <iomanip>
typedef std::map<uint16, uint32> AreaFlagByAreaID;
typedef std::map<uint32, uint32> AreaFlagByMapID;
@@ -73,6 +76,7 @@ DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
DBCStorage <CinematicCameraEntry> sCinematicCameraStore(CinematicCameraEntryfmt);
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
@@ -217,6 +221,8 @@ DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreaEntryfmt);
DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore(WorldMapOverlayEntryfmt);
DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsEntryfmt);
std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
typedef std::list<std::string> 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<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();
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<uint32 const>(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<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 const>(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<M2Camera const*>(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);
+5
View File
@@ -27,6 +27,8 @@
#include <list>
typedef std::list<uint32> SimpleFactionsList;
typedef std::vector<FlyByCamera> 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 <CharSectionsEntry> sCharSectionsStore;
TC_GAME_API extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
TC_GAME_API extern DBCStorage <ChrClassesEntry> sChrClassesStore;
TC_GAME_API extern DBCStorage <ChrRacesEntry> sChrRacesStore;
TC_GAME_API extern DBCStorage <CinematicCameraEntry> sCinematicCameraStore;
TC_GAME_API extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore;
TC_GAME_API extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
TC_GAME_API extern DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore;
@@ -193,7 +196,9 @@ TC_GAME_API extern DBCStorage <WMOAreaTableEntry> sWMOAreaTableStore;
//TC_GAME_API extern DBCStorage <WorldMapAreaEntry> sWorldMapAreaStore; -- use Zone2MapCoordinates and Map2ZoneCoordinates
TC_GAME_API extern DBCStorage <WorldMapOverlayEntry> sWorldMapOverlayStore;
TC_GAME_API extern DBCStorage <WorldSafeLocsEntry> sWorldSafeLocsStore;
TC_GAME_API extern std::unordered_map<uint32, FlyByCameraCollection> sFlyByCameraStore;
TC_GAME_API void LoadDBCStores(const std::string& dataPath);
TC_GAME_API void LoadM2Cameras(const std::string& dataPath);
#endif
+5 -7
View File
@@ -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
};
+2 -1
View File
@@ -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";
@@ -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;
}
+142 -2
View File
@@ -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<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, false, true);
}
std::string Player::GetMapAreaAndZoneString() const
{
uint32 areaId = GetAreaId();
+20 -1
View File
@@ -2129,7 +2129,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
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<Player>
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<Player>
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);
+4 -2
View File
@@ -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)
+11 -2
View File
@@ -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<Trinity::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
TypeContainerVisitor<Trinity::VisibleNotifier, GridTypeMapContainer > 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();
+17
View File
@@ -124,6 +124,23 @@ public:
return false;
}
// Dump camera locations
if (CinematicSequencesEntry const* cineSeq = sCinematicSequencesStore.LookupEntry(id))
{
std::unordered_map<uint32, FlyByCameraCollection>::const_iterator itr = sFlyByCameraStore.find(cineSeq->cinematicCamera);
if (itr != sFlyByCameraStore.end())
{
handler->PSendSysMessage("Waypoints for sequence %u, camera %u", id, cineSeq->cinematicCamera);
uint32 count = 1 ;
for (FlyByCamera cam : itr->second)
{
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));
count++;
}
handler->PSendSysMessage("%u waypoints dumped", itr->second.size());
}
}
handler->GetSession()->GetPlayer()->SendCinematicStart(id);
return true;
}
+115
View File
@@ -25,6 +25,121 @@
#include "DatabaseWorkerPool.h"
#include "Implementation/WorldDatabase.h"
#include "DatabaseEnv.h"
#include <G3D/Vector3.h>
#include <G3D/AABox.h>
// 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;
};
struct SqlDbc
{
+69 -5
View File
@@ -53,12 +53,13 @@ char input_path[MAX_PATH_LENGTH] = ".";
// **************************************************
enum Extract
{
EXTRACT_MAP = 1,
EXTRACT_DBC = 2
EXTRACT_MAP = 1,
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)
bool CONF_allow_height_limit = true;
float CONF_use_minHeight = -500.0f;
@@ -103,7 +104,7 @@ void Usage(char* prg)
"%s -[var] [value]\n"\
"-i set input path (max %d characters)\n"\
"-o set output path (max %d characters)\n"\
"-e extract only MAP(1)/DBC(2) - standard: both(3)\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"\
"Example: %s -f 0 -i \"c:\\games\\game\"", prg, MAX_PATH_LENGTH - 1, MAX_PATH_LENGTH - 1, prg);
exit(1);
@@ -151,7 +152,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
@@ -1025,6 +1026,56 @@ void ExtractDBCFiles(int locale, bool basicLocale)
printf("Extracted %u DBC files\n\n", count);
}
void ExtractCameraFiles(int locale, bool basicLocale)
{
printf("Extracting camera files...\n");
DBCFile camdbc("DBFilesClient\\CinematicCamera.dbc");
if (!camdbc.open())
{
printf("Unable to open CinematicCamera.dbc. Camera extract aborted.\n");
return;
}
// get camera file list from DBC
std::vector<std::string> camerafiles;
size_t cam_count = camdbc.getRecordCount();
for (uint32 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);
if (!basicLocale)
{
path += langs[locale];
path += "/";
CreateDir(path);
}
// extract M2s
uint32 count = 0;
for (std::string thisFile : camerafiles)
{
std::string filename = path;
filename += (thisFile.c_str() + strlen("Cameras\\"));
if (boost::filesystem::exists(filename))
continue;
if (ExtractFile(thisFile.c_str(), filename))
++count;
}
printf("Extracted %u camera files\n", count);
}
void LoadLocaleMPQFiles(int const locale)
{
std::string fileName = Trinity::StringFormat("%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]);
@@ -1111,6 +1162,19 @@ int main(int argc, char * arg[])
return 0;
}
if (CONF_extract & EXTRACT_CAMERA)
{
printf("Using locale: %s\n", langs[FirstLocale]);
// Open MPQs
LoadLocaleMPQFiles(FirstLocale);
LoadCommonMPQFiles();
ExtractCameraFiles(FirstLocale, true);
// Close MPQs
CloseMPQFiles();
}
if (CONF_extract & EXTRACT_MAP)
{
printf("Using locale: %s\n", langs[FirstLocale]);