From 196f935cd8d22d0d412d463683145c7ac6283e35 Mon Sep 17 00:00:00 2001 From: StormBytePP Date: Sun, 30 Aug 2015 19:26:33 +0200 Subject: Core/Taxi: Implemented taxi routes, thanks to @MitchesD patch for initial work, and @Shauren for IDA help Conflicts: src/server/game/Entities/Player/Player.cpp src/server/game/Entities/Player/Player.h src/server/game/Handlers/TaxiHandler.cpp --- src/server/game/CMakeLists.txt | 1 + src/server/game/Entities/Player/Player.cpp | 144 +-------------- src/server/game/Entities/Player/Player.h | 60 +------ src/server/game/Entities/Player/PlayerTaxi.cpp | 189 ++++++++++++++++++++ src/server/game/Entities/Player/PlayerTaxi.h | 65 +++++++ src/server/game/Entities/Taxi/TaxiPathGraph.cpp | 184 +++++++++++++++++++ src/server/game/Entities/Taxi/TaxiPathGraph.h | 91 ++++++++++ src/server/game/Globals/ObjectMgr.h | 1 + src/server/game/Handlers/MovementHandler.cpp | 44 +++++ src/server/game/Handlers/TaxiHandler.cpp | 198 ++++++--------------- src/server/game/Miscellaneous/SharedDefines.h | 32 ++-- src/server/game/Server/Packets/MovementPackets.cpp | 6 + src/server/game/Server/Packets/MovementPackets.h | 11 ++ src/server/game/Server/Packets/TaxiPackets.cpp | 78 ++++++++ src/server/game/Server/Packets/TaxiPackets.h | 125 +++++++++++++ src/server/game/Server/Protocol/Opcodes.cpp | 21 +-- src/server/game/Server/WorldSession.h | 22 ++- src/server/game/World/World.cpp | 4 + 18 files changed, 908 insertions(+), 368 deletions(-) create mode 100644 src/server/game/Entities/Player/PlayerTaxi.cpp create mode 100644 src/server/game/Entities/Player/PlayerTaxi.h create mode 100644 src/server/game/Entities/Taxi/TaxiPathGraph.cpp create mode 100644 src/server/game/Entities/Taxi/TaxiPathGraph.h create mode 100644 src/server/game/Server/Packets/TaxiPackets.cpp create mode 100644 src/server/game/Server/Packets/TaxiPackets.h (limited to 'src') diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 14bb8f25389..e4388c31e44 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -139,6 +139,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Object/Updates ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Pet ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Player + ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Taxi ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Totem ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Transport ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Unit diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9689144ebc9..95cd705beba 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -87,6 +87,7 @@ #include "SpellMgr.h" #include "SpellPackets.h" #include "TalentPackets.h" +#include "TaxiPackets.h" #include "ToyPackets.h" #include "TradePackets.h" #include "Transport.h" @@ -129,148 +130,6 @@ uint32 const MasterySpells[MAX_CLASSES] = uint64 const MAX_MONEY_AMOUNT = 9999999999ULL; -// == PlayerTaxi ================================================ - -PlayerTaxi::PlayerTaxi() -{ - memset(m_taximask, 0, sizeof(m_taximask)); -} - -void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) -{ - // class specific initial known nodes - switch (chrClass) - { - case CLASS_DEATH_KNIGHT: - { - for (uint8 i = 0; i < TaxiMaskSize; ++i) - m_taximask[i] |= sOldContinentsNodesMask[i]; - break; - } - } - - // race specific initial known nodes: capital and taxi hub masks - switch (race) - { - case RACE_HUMAN: SetTaximaskNode(2); break; // Human - case RACE_ORC: SetTaximaskNode(23); break; // Orc - case RACE_DWARF: SetTaximaskNode(6); break; // Dwarf - case RACE_NIGHTELF: SetTaximaskNode(26); - SetTaximaskNode(27); break; // Night Elf - case RACE_UNDEAD_PLAYER: SetTaximaskNode(11); break;// Undead - case RACE_TAUREN: SetTaximaskNode(22); break; // Tauren - case RACE_GNOME: SetTaximaskNode(6); break; // Gnome - case RACE_TROLL: SetTaximaskNode(23); break; // Troll - case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf - case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei - } - - // new continent starting masks (It will be accessible only at new map) - switch (Player::TeamForRace(race)) - { - case ALLIANCE: SetTaximaskNode(100); break; - case HORDE: SetTaximaskNode(99); break; - } - // level dependent taxi hubs - if (level >= 68) - SetTaximaskNode(213); //Shattered Sun Staging Area -} - -void PlayerTaxi::LoadTaxiMask(std::string const &data) -{ - Tokenizer tokens(data, ' '); - - uint8 index = 0; - for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index) - { - // load and set bits only for existing taxi nodes - m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter); - } -} - -void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all) -{ - data << uint32(TaxiMaskSize); - if (all) - { - for (uint8 i = 0; i < TaxiMaskSize; ++i) - data << uint8(sTaxiNodesMask[i]); // all existed nodes - } - else - { - for (uint8 i = 0; i < TaxiMaskSize; ++i) - data << uint8(m_taximask[i]); // known nodes - } -} - -bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team) -{ - ClearTaxiDestinations(); - - Tokenizer Tokenizer(values, ' '); - - for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter) - { - uint32 node = atoul(*iter); - AddTaxiDestination(node); - } - - if (m_TaxiDestinations.empty()) - return true; - - // Check integrity - if (m_TaxiDestinations.size() < 2) - return false; - - for (size_t i = 1; i < m_TaxiDestinations.size(); ++i) - { - uint32 cost; - uint32 path; - sObjectMgr->GetTaxiPath(m_TaxiDestinations[i-1], m_TaxiDestinations[i], path, cost); - if (!path) - return false; - } - - // can't load taxi path without mount set (quest taxi path?) - if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), team, true)) - return false; - - return true; -} - -std::string PlayerTaxi::SaveTaxiDestinationsToString() -{ - if (m_TaxiDestinations.empty()) - return ""; - - std::ostringstream ss; - - for (size_t i=0; i < m_TaxiDestinations.size(); ++i) - ss << m_TaxiDestinations[i] << ' '; - - return ss.str(); -} - -uint32 PlayerTaxi::GetCurrentTaxiPath() const -{ - if (m_TaxiDestinations.size() < 2) - return 0; - - uint32 path; - uint32 cost; - - sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost); - - return path; -} - -std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi) -{ - for (uint8 i = 0; i < TaxiMaskSize; ++i) - ss << uint32(taxi.m_taximask[i]) << ' '; - return ss; -} - //== TradeData ================================================= TradeData* TradeData::GetTraderData() const @@ -21016,7 +20875,6 @@ bool Player::ActivateTaxiPathTo(std::vector const& nodes, Creature* npc GetSession()->SendActivateTaxiReply(ERR_TAXIUNSPECIFIEDSERVERERROR); return false; } - // Prepare to flight start now // stop combat at start taxi flight if any diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 559f1f28570..51316b21c1a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -31,10 +31,7 @@ #include "Unit.h" #include "Opcodes.h" #include "WorldSession.h" - -#include -#include -#include +#include "PlayerTaxi.h" struct CreatureTemplate; struct Mail; @@ -1086,61 +1083,6 @@ enum PlayerLogXPReason LOG_XP_REASON_NO_KILL = 1 }; -class PlayerTaxi -{ - public: - PlayerTaxi(); - ~PlayerTaxi() { } - // Nodes - void InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level); - void LoadTaxiMask(std::string const& data); - - bool IsTaximaskNodeKnown(uint32 nodeidx) const - { - uint8 field = uint8((nodeidx - 1) / 8); - uint32 submask = 1 << ((nodeidx-1) % 8); - return (m_taximask[field] & submask) == submask; - } - bool SetTaximaskNode(uint32 nodeidx) - { - uint8 field = uint8((nodeidx - 1) / 8); - uint32 submask = 1 << ((nodeidx- 1) % 8); - if ((m_taximask[field] & submask) != submask) - { - m_taximask[field] |= submask; - return true; - } - else - return false; - } - void AppendTaximaskTo(ByteBuffer& data, bool all); - - // Destinations - bool LoadTaxiDestinationsFromString(std::string const& values, uint32 team); - std::string SaveTaxiDestinationsToString(); - - void ClearTaxiDestinations() { m_TaxiDestinations.clear(); } - void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); } - uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); } - uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; } - uint32 GetCurrentTaxiPath() const; - uint32 NextTaxiDestination() - { - m_TaxiDestinations.pop_front(); - return GetTaxiDestination(); - } - - std::deque const& GetPath() const { return m_TaxiDestinations; } - bool empty() const { return m_TaxiDestinations.empty(); } - - friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi); - private: - TaxiMask m_taximask; - std::deque m_TaxiDestinations; -}; - -std::ostringstream& operator << (std::ostringstream& ss, PlayerTaxi const& taxi); - class Player; /// Holder for Battleground data diff --git a/src/server/game/Entities/Player/PlayerTaxi.cpp b/src/server/game/Entities/Player/PlayerTaxi.cpp new file mode 100644 index 00000000000..b7daa0b61d1 --- /dev/null +++ b/src/server/game/Entities/Player/PlayerTaxi.cpp @@ -0,0 +1,189 @@ +#include "Player.h" +#include "TaxiPackets.h" +#include "ObjectMgr.h" +#include +#include + + +PlayerTaxi::PlayerTaxi() +{ + memset(m_taximask, 0, sizeof(m_taximask)); +} + +void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) +{ + // class specific initial known nodes + switch (chrClass) + { + case CLASS_DEATH_KNIGHT: + { + for (uint8 i = 0; i < TaxiMaskSize; ++i) + m_taximask[i] |= sOldContinentsNodesMask[i]; + break; + } + } + + // race specific initial known nodes: capital and taxi hub masks + switch (race) + { + case RACE_HUMAN: + case RACE_DWARF: + case RACE_NIGHTELF: + case RACE_GNOME: + case RACE_DRAENEI: + case RACE_WORGEN: + case RACE_PANDAREN_ALLIANCE: + SetTaximaskNode(2); // Stormwind, Elwynn + SetTaximaskNode(6); // Ironforge, Dun Morogh + SetTaximaskNode(26); // Lor'danel, Darkshore + SetTaximaskNode(27); // Rut'theran Village, Teldrassil + SetTaximaskNode(49); // Moonglade (Alliance) + SetTaximaskNode(94); // The Exodar + SetTaximaskNode(456); // Dolanaar, Teldrassil + SetTaximaskNode(457); // Darnassus, Teldrassil + SetTaximaskNode(582); // Goldshire, Elwynn + SetTaximaskNode(589); // Eastvale Logging Camp, Elwynn + SetTaximaskNode(619); // Kharanos, Dun Morogh + SetTaximaskNode(620); // Gol'Bolar Quarry, Dun Morogh + SetTaximaskNode(624); // Azure Watch, Azuremyst Isle + break; + + case RACE_ORC: + case RACE_UNDEAD_PLAYER: + case RACE_TAUREN: + case RACE_TROLL: + case RACE_BLOODELF: + case RACE_GOBLIN: + case RACE_PANDAREN_HORDE: + SetTaximaskNode(11); // Undercity, Tirisfal + SetTaximaskNode(22); // Thunder Bluff, Mulgore + SetTaximaskNode(23); // Orgrimmar, Durotar + SetTaximaskNode(69); // Moonglade (Horde) + SetTaximaskNode(82); // Silvermoon City + SetTaximaskNode(384); // The Bulwark, Tirisfal + SetTaximaskNode(402); // Bloodhoof Village, Mulgore + SetTaximaskNode(460); // Brill, Tirisfal Glades + SetTaximaskNode(536); // Sen'jin Village, Durotar + SetTaximaskNode(537); // Razor Hill, Durotar + SetTaximaskNode(625); // Fairbreeze Village, Eversong Woods + SetTaximaskNode(631); // Falconwing Square, Eversong Woods + break; + } + + // new continent starting masks (It will be accessible only at new map) + switch (Player::TeamForRace(race)) + { + case ALLIANCE: SetTaximaskNode(100); break; + case HORDE: SetTaximaskNode(99); break; + } + // level dependent taxi hubs + if (level >= 68) + SetTaximaskNode(213); //Shattered Sun Staging Area +} + +void PlayerTaxi::LoadTaxiMask(std::string const &data) +{ + Tokenizer tokens(data, ' '); + + uint8 index = 0; + for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index) + { + // load and set bits only for existing taxi nodes + m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter); + } +} + +void PlayerTaxi::AppendTaximaskTo(WorldPackets::Taxi::ShowTaxiNodes& data, bool all) +{ + if (all) + { + for (uint8 i = 0; i < TaxiMaskSize; ++i) + data.Nodes.push_back(sTaxiNodesMask[i]); // all existed nodes + } + else + { + for (uint8 i = 0; i < TaxiMaskSize; ++i) + data.Nodes.push_back(m_taximask[i]); // known nodes + } +} + +bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team) +{ + ClearTaxiDestinations(); + + Tokenizer Tokenizer(values, ' '); + + for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter) + { + uint32 node = atoul(*iter); + AddTaxiDestination(node); + } + + if (m_TaxiDestinations.empty()) + return true; + + // Check integrity + if (m_TaxiDestinations.size() < 2) + return false; + + for (size_t i = 1; i < m_TaxiDestinations.size(); ++i) + { + uint32 cost; + uint32 path; + sObjectMgr->GetTaxiPath(m_TaxiDestinations[i-1], m_TaxiDestinations[i], path, cost); + if (!path) + return false; + } + + // can't load taxi path without mount set (quest taxi path?) + if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), team, true)) + return false; + + return true; +} + +std::string PlayerTaxi::SaveTaxiDestinationsToString() +{ + if (m_TaxiDestinations.empty()) + return ""; + + std::ostringstream ss; + + for (size_t i=0; i < m_TaxiDestinations.size(); ++i) + ss << m_TaxiDestinations[i] << ' '; + + return ss.str(); +} + +uint32 PlayerTaxi::GetCurrentTaxiPath() const +{ + if (m_TaxiDestinations.size() < 2) + return 0; + + uint32 path; + uint32 cost; + + sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost); + + return path; +} + +std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi) +{ + for (uint8 i = 0; i < TaxiMaskSize; ++i) + ss << uint32(taxi.m_taximask[i]) << ' '; + return ss; +} + +void PlayerTaxi::RequestEarlyLanding() +{ + if (m_TaxiDestinations.empty()) + return; + + for (std::deque::iterator it = m_TaxiDestinations.begin(); it != m_TaxiDestinations.end(); it++) + if (IsTaximaskNodeKnown(*it)) + { + m_TaxiDestinations.erase(++it, m_TaxiDestinations.end()); + return; + } +} diff --git a/src/server/game/Entities/Player/PlayerTaxi.h b/src/server/game/Entities/Player/PlayerTaxi.h new file mode 100644 index 00000000000..c19e3835ead --- /dev/null +++ b/src/server/game/Entities/Player/PlayerTaxi.h @@ -0,0 +1,65 @@ +#ifndef __PLAYERTAXI_H__ +#define __PLAYERTAXI_H__ + +#include "DB2Stores.h" +#include "Define.h" +#include "WorldSession.h" +#include + +class PlayerTaxi +{ + public: + PlayerTaxi(); + ~PlayerTaxi() { } + // Nodes + void InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level); + void LoadTaxiMask(std::string const& data); + + bool IsTaximaskNodeKnown(uint32 nodeidx) const + { + uint8 field = uint8((nodeidx - 1) / 8); + uint32 submask = 1 << ((nodeidx-1) % 8); + return (m_taximask[field] & submask) == submask; + } + bool SetTaximaskNode(uint32 nodeidx) + { + uint8 field = uint8((nodeidx - 1) / 8); + uint32 submask = 1 << ((nodeidx- 1) % 8); + if ((m_taximask[field] & submask) != submask) + { + m_taximask[field] |= submask; + return true; + } + else + return false; + } + void AppendTaximaskTo(WorldPackets::Taxi::ShowTaxiNodes& data, bool all); + TaxiMask const& GetTaxiMask() const { return m_taximask; } + + // Destinations + bool LoadTaxiDestinationsFromString(std::string const& values, uint32 team); + std::string SaveTaxiDestinationsToString(); + + void ClearTaxiDestinations() { m_TaxiDestinations.clear(); } + void AddTaxiDestination(uint32 dest) { m_TaxiDestinations.push_back(dest); } + void SetTaxiDestination(std::vector& nodes) { m_TaxiDestinations.clear(); m_TaxiDestinations.insert(m_TaxiDestinations.begin(), nodes.begin(), nodes.end()); } + uint32 GetTaxiSource() const { return m_TaxiDestinations.empty() ? 0 : m_TaxiDestinations.front(); } + uint32 GetTaxiDestination() const { return m_TaxiDestinations.size() < 2 ? 0 : m_TaxiDestinations[1]; } + uint32 GetCurrentTaxiPath() const; + uint32 NextTaxiDestination() + { + m_TaxiDestinations.pop_front(); + return GetTaxiDestination(); + } + void RequestEarlyLanding(); + bool empty() const { return m_TaxiDestinations.empty(); } + + friend std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi); + private: + TaxiMask m_taximask; + std::deque m_TaxiDestinations; +}; + +std::ostringstream& operator << (std::ostringstream& ss, PlayerTaxi const& taxi); + +#endif diff --git a/src/server/game/Entities/Taxi/TaxiPathGraph.cpp b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp new file mode 100644 index 00000000000..7c6f0c388a4 --- /dev/null +++ b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp @@ -0,0 +1,184 @@ +#include "TaxiPathGraph.h" +#include +#include "Util.h" +#include "DB2Stores.h" +#include "Config.h" +#include + + +TaxiPathGraph::Graph TaxiPathGraph::m_graph = TaxiPathGraph::Graph(); +std::vector TaxiPathGraph::m_vertices = std::vector(); +std::map TaxiPathGraph::m_nodeIDToVertexID = std::map(); +std::set TaxiPathGraph::m_edgeDuplicateControl = std::set(); +const int TaxiPathGraph::MaxFlightDistanceThreshold = 4000; //Because the client seems not to chose long flight paths even if that means the chosen path is not the minimum one + +TaxiPathGraph::TaxiPathGraph() { } + +TaxiPathGraph::~TaxiPathGraph() { } + +void TaxiPathGraph::Initialize() +{ + if (_getVertexCount() > 0) + return; + + m_edgeDuplicateControl.clear(); + std::vector> edges; + + std::set returnableNodeIDs; // Used to omit special nodes which you can't return from + + for (TaxiPathEntry const* nodeInfo : sTaxiPathStore) + if (nodeInfo->From != nodeInfo->To) + returnableNodeIDs.insert(nodeInfo->From); + + // Initialize here + for (TaxiPathEntry const* nodeInfo : sTaxiPathStore) + { + TaxiNodesEntry const* from = sTaxiNodesStore.LookupEntry(nodeInfo->From); + TaxiNodesEntry const* to = sTaxiNodesStore.LookupEntry(nodeInfo->To); + if (from && to && + returnableNodeIDs.find(nodeInfo->From) != returnableNodeIDs.end() && returnableNodeIDs.find(nodeInfo->To) != returnableNodeIDs.end()) + { + _addVerticeAndEdgeFromNodeInfo(TaxiNodeInfo(from->ID, from->Name->Str[sConfigMgr->GetIntDefault("DBC.Locale", LOCALE_enUS)], from->Pos.X, from->Pos.Y, from->Pos.Z), + TaxiNodeInfo(to->ID, to->Name->Str[sConfigMgr->GetIntDefault("DBC.Locale", LOCALE_enUS)], to->Pos.X, to->Pos.Y, to->Pos.Z), nodeInfo->Cost, edges); + } + } + + returnableNodeIDs.clear(); + // create graph + m_graph = Graph(_getVertexCount()); + WeightMap weightmap = boost::get(boost::edge_weight, m_graph); + /*IndexMap indexmap = boost::get(boost::vertex_index, m_graph);*/ + + for(std::size_t j = 0; j < edges.size(); ++j) { + edge_descriptor e; bool inserted; + boost::tie(e, inserted) = boost::add_edge(edges[j].first.first, + edges[j].first.second, + m_graph); + weightmap[e] = edges[j].second; + } + m_edgeDuplicateControl.clear(); +} + +uint32 TaxiPathGraph::_getNodeIDFromVertexID(vertex vertexID) +{ + if (vertexID < m_vertices.size()) + return m_vertices[vertexID].nodeID; + + return std::numeric_limits::max(); +} + +TaxiPathGraph::vertex TaxiPathGraph::_getVertexIDFromNodeID(uint32_t nodeID) +{ + if (m_nodeIDToVertexID.find(nodeID) != m_nodeIDToVertexID.end()) + return m_nodeIDToVertexID[nodeID]; + + return std::numeric_limits::max(); +} + +TaxiPathGraph::vertex TaxiPathGraph::_getVertexIDFromNodeID(TaxiNodeInfo const& nodeInfo) +{ + if (m_nodeIDToVertexID.find(nodeInfo.nodeID) != m_nodeIDToVertexID.end()) + return m_nodeIDToVertexID[nodeInfo.nodeID]; + + return std::numeric_limits::max(); +} + +size_t TaxiPathGraph::_getVertexCount() +{ + //So we can use this function for readability, we define either max defined vertices or already loaded in graph count + return std::max(boost::num_vertices(m_graph), m_vertices.size()); +} + +void TaxiPathGraph::_addVerticeAndEdgeFromNodeInfo(const TaxiNodeInfo& from, const TaxiNodeInfo& to, uint32 /* money */, std::vector>& edges) +{ + if (from.nodeID != to.nodeID && m_edgeDuplicateControl.find(edge(from.nodeID, to.nodeID)) == m_edgeDuplicateControl.end()) + { + vertex fromVertexID = _createVertexFromFromNodeInfoIfNeeded(from); + vertex toVertexID = _createVertexFromFromNodeInfoIfNeeded(to); + + edges.push_back(std::make_pair(edge(fromVertexID, toVertexID), from.pos.Distance(to.pos))); + m_edgeDuplicateControl.insert(edge(from.nodeID, to.nodeID)); + } +} + +size_t TaxiPathGraph::GetCompleteNodeRoute(uint32_t sourceNodeID, uint32_t destinationNodeID, std::vector& shortestPath) +{ + /* + Information about node algorithm from client + Since client does not give information about *ALL* nodes you have to pass by when going from sourceNodeID to destinationNodeID, algorithms like A* on directed graph of taxi + nodes are needed. But since, 6.x implemented early landing request feature, client seems not to be picking the least expensive path in terms in neither distance neither money cost. + Examining several paths I discovered the following algorithm: + * If destinationNodeID has is the next destination, connected directly to sourceNodeID, then, client just pick up this route regardless of distance + * else, client will avoid to pick a node which distance is equal or greater than TaxiPathGraph::MaxFlightDistanceThreshold to avoid long node to node distances for requesting + early landings, so we use A* algorithm with a custom weight property map to reflect this condition. + + * When early landing is requested, according to behavior on retail, you can never end in a node you did not discovered before + */ + bool hasDirectPath = false; + shortestPath.clear(); + + // Find if we have a direct path from sourceNodeID to destinationNodeID in graph + typename boost::graph_traits::out_edge_iterator ei, ei_end; + for (boost::tie(ei, ei_end) = boost::out_edges(_getVertexIDFromNodeID(sourceNodeID), m_graph); ei != ei_end && !hasDirectPath; ++ei) + if (boost::target(*ei, m_graph) == _getVertexIDFromNodeID(destinationNodeID)) + hasDirectPath = true; + + if (hasDirectPath) + shortestPath = { sourceNodeID, destinationNodeID }; + else + { + std::vector p(boost::num_vertices(m_graph)); + std::vector d(boost::num_vertices(m_graph)); + + vertex start = _getVertexIDFromNodeID(sourceNodeID); + vertex goal = _getVertexIDFromNodeID(destinationNodeID); + + try + { + auto wow_custom_weight_map = boost::make_transform_value_property_map( + [](float w) { return w>MaxFlightDistanceThreshold ? std::numeric_limits::infinity() : w; }, + boost::get(boost::edge_weight, m_graph) + ); + boost::astar_search(m_graph, start, + boost::astar_heuristic(), + boost::weight_map(wow_custom_weight_map) + .predecessor_map(boost::make_iterator_property_map(p.begin(), get(boost::vertex_index, m_graph))) + .distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, m_graph))) + .visitor(astar_goal_visitor(goal))); + } + catch(found_goal fg) + { // found a path to the goal + std::list shortest_path; + for(vertex v = goal;; v = p[v]) { + shortest_path.push_front(v); + if(p[v] == v) + break; + } + + for(std::list::const_iterator spi = shortest_path.begin(); spi != shortest_path.end(); spi++) + shortestPath.push_back(_getNodeIDFromVertexID(*spi)); + } + } + return shortestPath.size(); +} + +TaxiPathGraph::TaxiNodeInfo const* TaxiPathGraph::GetTaxiNodeInfoByID(uint32_t nodeID) +{ + vertex vertexID = _getVertexIDFromNodeID(nodeID); + if (m_vertices.size() < vertexID) + return nullptr; + return &m_vertices[vertexID]; +} + +TaxiPathGraph::vertex TaxiPathGraph::_createVertexFromFromNodeInfoIfNeeded(const TaxiNodeInfo& nodeInfo) +{ + //Check if we need a new one or if it may be already created + if (m_nodeIDToVertexID.find(nodeInfo.nodeID) == m_nodeIDToVertexID.end()) + { + vertex verID = m_vertices.size(); + m_vertices.push_back(nodeInfo); + m_nodeIDToVertexID[nodeInfo.nodeID] = verID; + return verID; + } + return m_nodeIDToVertexID[nodeInfo.nodeID]; +} diff --git a/src/server/game/Entities/Taxi/TaxiPathGraph.h b/src/server/game/Entities/Taxi/TaxiPathGraph.h new file mode 100644 index 00000000000..5ef031d697d --- /dev/null +++ b/src/server/game/Entities/Taxi/TaxiPathGraph.h @@ -0,0 +1,91 @@ +#ifndef TAXIPATHGRAPH_HPP +#define TAXIPATHGRAPH_HPP + +#include +#include +#include +#include "Define.h" + +class TaxiPathGraph +{ +public: + struct Location + { + Location(float posX, float posY, float posZ): x(posX), y(posY), z(posZ) { } + float Distance(Location const& to) const { return sqrt(pow(to.x - x, 2) + pow(to.y - y, 2) + pow(to.z - z, 2)); } + float x; + float y; + float z; + }; + struct TaxiNodeInfo + { + TaxiNodeInfo(uint32 id, std::string const& flightName, float posX, float posY, float posZ): nodeID(id), name(flightName), pos(posX, posY, posZ) + { + name.erase(std::remove(name.begin(), name.end(), '\"' ), name.end()); + } + uint32 nodeID; + std::string name; + Location pos; + }; + static TaxiPathGraph* instance() + { + static TaxiPathGraph instance; + return &instance; + } + ~TaxiPathGraph(); + + static void Initialize(); + static size_t GetCompleteNodeRoute(uint32 /* sourceNodeID */, uint32 /* destinationNodeID */, std::vector& /* shortestPath */); + static TaxiNodeInfo const* GetTaxiNodeInfoByID(uint32 nodeID); + +private: + typedef float cost; + + struct found_goal {}; // exception for termination + + // visitor that terminates when we find the goal + template + class astar_goal_visitor : public boost::default_astar_visitor + { + public: + astar_goal_visitor(Vertex goal) : m_goal(goal) {} + template + void examine_vertex(Vertex u, Graph& /* g */) { + if(u == m_goal) + throw found_goal(); + } + private: + Vertex m_goal; + }; + + // specify some types + typedef boost::adjacency_list, boost::property > Graph; + typedef boost::property_map::type WeightMap; + typedef boost::property_map::type IndexMap; + typedef Graph::vertex_descriptor vertex; + typedef Graph::edge_descriptor edge_descriptor; + typedef Graph::vertex_descriptor vertex_descriptor; + typedef Graph::vertex_iterator vertex_iterator; + typedef std::pair edge; + + static Graph m_graph; + static std::vector m_vertices; + static std::map m_nodeIDToVertexID; + static std::set m_edgeDuplicateControl; + static const int MaxFlightDistanceThreshold; + + static void _addVerticeAndEdgeFromNodeInfo(TaxiNodeInfo const& /* from */, TaxiNodeInfo const& /* to */, uint32 /* money */, std::vector>& /* edgeList */); + TaxiPathGraph(); + TaxiPathGraph(TaxiPathGraph const&) = delete; + TaxiPathGraph& operator=(TaxiPathGraph const&) = delete; + + static vertex _getVertexIDFromNodeID(uint32 nodeID); + static vertex _getVertexIDFromNodeID(TaxiNodeInfo const& nodeInfo); + static uint32 _getNodeIDFromVertexID(vertex vertexID); + static vertex _createVertexFromFromNodeInfoIfNeeded(TaxiNodeInfo const&); + static size_t _getVertexCount(); +}; + +#define sTaxiPathGraph TaxiPathGraph::instance() + +#endif /* TAXIPATHGRAPH_HPP */ diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 8e660e3f32c..c5f3fb908e7 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -796,6 +796,7 @@ class ObjectMgr uint32 GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team); void GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost); + void GetTaxiPath(uint32 source, uint32 destination, std::vector& path, uint32& cost); uint32 GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team = false); Quest const* GetQuestTemplate(uint32 quest_id) const diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 4256a41f80f..4cad8c98e42 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -526,3 +526,47 @@ void WorldSession::HandleSetCollisionHeightAck(WorldPackets::Movement::MoveSetCo void WorldSession::HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeSkipped& /*moveTimeSkipped*/) { } + +void WorldSession::HandleMoveSplineDoneOpcode(WorldPackets::Movement::MoveSplineDone& packet) +{ + MovementInfo movementInfo = packet.movementInfo; + _player->ValidateMovementInfo(&movementInfo); + + // in taxi flight packet received in 2 case: + // 1) end taxi path in far (multi-node) flight + // 2) switch from one map to other in case multim-map taxi path + // we need process only (1) + + uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); + if (curDest) + { + TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); + + // far teleport case + if (curDestNode && curDestNode->MapID != GetPlayer()->GetMapId()) + { + if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + { + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); + + flight->SetCurrentNodeAfterTeleport(); + TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()]; + flight->SkipCurrentNode(); + + GetPlayer()->TeleportTo(curDestNode->MapID, node->Loc.X, node->Loc.Y, node->Loc.Z, GetPlayer()->GetOrientation()); + } + } + + return; + } + + // at this point only 1 node is expected (final destination) + if (GetPlayer()->m_taxi.GetPath().size() != 1) + return; + + GetPlayer()->CleanupAfterTaxiFlight(); + GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); + if (GetPlayer()->pvpInfo.IsHostile) + GetPlayer()->CastSpell(GetPlayer(), 2479, true); +} diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index 1669bc306d6..b4462925e8d 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -24,14 +24,19 @@ #include "Log.h" #include "ObjectMgr.h" #include "Player.h" -#include "WaypointMovementGenerator.h" +#include "TaxiPackets.h" +#include "TaxiPathGraph.h" -void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvData) +void WorldSession::HandleEnableTaxiNodeOpcode(WorldPackets::Taxi::EnableTaxiNode& packet) { - ObjectGuid guid; + Creature* unit = GetPlayer()->GetMap()->GetCreature(packet.Unit); + SendLearnNewTaxiNode(unit); +} + - recvData >> guid; - SendTaxiStatus(guid); +void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPackets::Taxi::TaxiNodeStatusQuery& packet) +{ + SendTaxiStatus(packet.UnitGUID); } void WorldSession::SendTaxiStatus(ObjectGuid guid) @@ -46,32 +51,30 @@ void WorldSession::SendTaxiStatus(ObjectGuid guid) uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); - // not found nearest - if (curloc == 0) - return; + WorldPackets::Taxi::TaxiNodeStatus data; + data.Unit = guid; - TC_LOG_DEBUG("network", "WORLD: current location %u ", curloc); + if (!curloc) + data.Status = TAXISTATUS_NONE; + else if (unit->GetReactionTo(GetPlayer()) >= REP_NEUTRAL) + data.Status = GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? TAXISTATUS_LEARNED : TAXISTATUS_UNLEARNED; + else + data.Status = TAXISTATUS_NOT_ELIGIBLE; + + SendPacket(data.Write()); - WorldPacket data(SMSG_TAXI_NODE_STATUS, 9); - data << guid; - data << uint8(GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) ? 1 : 0); - SendPacket(&data); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_TAXINODE_STATUS"); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_TAXI_NODE_STATUS"); } -void WorldSession::HandleTaxiQueryAvailableNodes(WorldPacket& recvData) +void WorldSession::HandleTaxiQueryAvailableNodesOpcode(WorldPackets::Taxi::TaxiQueryAvailableNodes& packet) { - ObjectGuid guid; - recvData >> guid; - // cheating checks - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_FLIGHTMASTER); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleTaxiQueryAvailableNodes - %s not found or you can't interact with him.", guid.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleTaxiQueryAvailableNodes - %s not found or you can't interact with him.", packet.Unit.ToString().c_str()); return; } - // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); @@ -97,14 +100,14 @@ void WorldSession::SendTaxiMenu(Creature* unit) TC_LOG_DEBUG("network", "WORLD: CMSG_TAXINODE_STATUS_QUERY %u ", curloc); - WorldPacket data(SMSG_SHOW_TAXI_NODES, (4 + 8 + 4 + 8 * 4)); - data << uint32(1); - data << unit->GetGUID(); - data << uint32(curloc); - GetPlayer()->m_taxi.AppendTaximaskTo(data, GetPlayer()->isTaxiCheater()); - SendPacket(&data); - - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_SHOWTAXINODES"); + WorldPackets::Taxi::ShowTaxiNodes data; + data.WindowInfo = boost::in_place(); + data.WindowInfo->UnitGUID = unit->GetGUID(); + data.WindowInfo->CurrentNode = curloc; + + GetPlayer()->m_taxi.AppendTaximaskTo(data, lastTaxiCheaterState); + + SendPacket(data.Write()); GetPlayer()->SetTaxiCheater(lastTaxiCheaterState); } @@ -134,13 +137,12 @@ bool WorldSession::SendLearnNewTaxiNode(Creature* unit) if (GetPlayer()->m_taxi.SetTaximaskNode(curloc)) { - WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); - SendPacket(&msg); + SendPacket(WorldPackets::Taxi::NewTaxiPath().Write()); - WorldPacket update(SMSG_TAXI_NODE_STATUS, 9); - update << unit->GetGUID(); - update << uint8(1); - SendPacket(&update); + WorldPackets::Taxi::TaxiNodeStatus data; + data.Unit = unit->GetGUID(); + data.Status = TAXISTATUS_LEARNED; + SendPacket(data.Write()); return true; } @@ -151,128 +153,46 @@ bool WorldSession::SendLearnNewTaxiNode(Creature* unit) void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid) { if (GetPlayer()->m_taxi.SetTaximaskNode(nodeid)) - { - WorldPacket msg(SMSG_NEW_TAXI_PATH, 0); - SendPacket(&msg); - } -} - -void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket& recvData) -{ - ObjectGuid guid; - uint32 node_count; - - recvData >> guid >> node_count; - - Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!npc) - { - TC_LOG_DEBUG("network", "WORLD: HandleActivateTaxiExpressOpcode - %s not found or you can't interact with it.", guid.ToString().c_str()); - return; - } - std::vector nodes; - - for (uint32 i = 0; i < node_count; ++i) - { - uint32 node; - recvData >> node; - - if (!GetPlayer()->m_taxi.IsTaximaskNodeKnown(node) && !GetPlayer()->isTaxiCheater()) - { - SendActivateTaxiReply(ERR_TAXINOTVISITED); - recvData.rfinish(); - return; - } - - nodes.push_back(node); - } - - if (nodes.empty()) - return; - - TC_LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d", nodes.front(), nodes.back()); - - GetPlayer()->ActivateTaxiPathTo(nodes, npc); + SendPacket(WorldPackets::Taxi::NewTaxiPath().Write()); } -void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) +void WorldSession::HandleActivateTaxiOpcode(WorldPackets::Taxi::ActivateTaxi& packet) { - recvData.read_skip(); // spline id - - MovementInfo movementInfo; // used only for proper packet read - _player->ValidateMovementInfo(&movementInfo); - - // in taxi flight packet received in 2 case: - // 1) end taxi path in far (multi-node) flight - // 2) switch from one map to other in case multim-map taxi path - // we need process only (1) - - uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); - if (curDest) + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.Vendor, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!unit) { - TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); - - // far teleport case - if (curDestNode && curDestNode->MapID != GetPlayer()->GetMapId()) - { - if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) - { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - - flight->SetCurrentNodeAfterTeleport(); - TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()]; - flight->SkipCurrentNode(); - - GetPlayer()->TeleportTo(curDestNode->MapID, node->Loc.X, node->Loc.Y, node->Loc.Z, GetPlayer()->GetOrientation()); - } - } - + TC_LOG_DEBUG("network", "WORLD: HandleActivateTaxiOpcode - %s not found or you can't interact with it.", packet.Vendor.ToString().c_str()); return; } - // at this point only 1 node is expected (final destination) - if (GetPlayer()->m_taxi.GetPath().size() != 1) - return; - - GetPlayer()->CleanupAfterTaxiFlight(); - GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); - if (GetPlayer()->pvpInfo.IsHostile) - GetPlayer()->CastSpell(GetPlayer(), 2479, true); -} - -void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData) -{ - ObjectGuid guid; - std::vector nodes; - nodes.resize(2); - - recvData >> guid >> nodes[0] >> nodes[1]; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_ACTIVATETAXI from %d to %d", nodes[0], nodes[1]); - Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); - if (!npc) - { - TC_LOG_DEBUG("network", "WORLD: HandleActivateTaxiOpcode - %s not found or you can't interact with it.", guid.ToString().c_str()); + uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); + + if (!curloc) return; - } - + if (!GetPlayer()->isTaxiCheater()) { - if (!GetPlayer()->m_taxi.IsTaximaskNodeKnown(nodes[0]) || !GetPlayer()->m_taxi.IsTaximaskNodeKnown(nodes[1])) + if (!GetPlayer()->m_taxi.IsTaximaskNodeKnown(curloc) || !GetPlayer()->m_taxi.IsTaximaskNodeKnown(packet.Node)) { SendActivateTaxiReply(ERR_TAXINOTVISITED); return; } } - - GetPlayer()->ActivateTaxiPathTo(nodes, npc); + + std::vector nodes; + TaxiPathGraph::GetCompleteNodeRoute(curloc, packet.Node, nodes); + GetPlayer()->ActivateTaxiPathTo(nodes, unit); } void WorldSession::SendActivateTaxiReply(ActivateTaxiReply reply) { - WorldPacket data(SMSG_ACTIVATE_TAXI_REPLY, 4); - data << uint32(reply); - SendPacket(&data); - + WorldPackets::Taxi::ActivateTaxiReply data; + data.Reply = reply; + SendPacket(data.Write()); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_ACTIVATETAXIREPLY"); } + +void WorldSession::HandleTaxiRequestEarlyLanding(WorldPackets::Taxi::TaxiRequestEarlyLanding& /* packet */) +{ + GetPlayer()->m_taxi.RequestEarlyLanding(); +} diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index f13630188a9..fa53e28f749 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -4719,18 +4719,26 @@ enum RemoveMethod enum ActivateTaxiReply { ERR_TAXINOVENDORNEARBY = 0, - ERR_TAXINOSUCHPATH = 1, - ERR_TAXIUNSPECIFIEDSERVERERROR = 2, - ERR_TAXITOOFARAWAY = 3, - ERR_TAXINOTSTANDING = 4, - ERR_TAXISAMENODE = 5, - ERR_TAXINOTENOUGHMONEY = 6, - ERR_TAXIOK = 7, - ERR_TAXINOTVISITED = 8, - ERR_TAXIPLAYERSHAPESHIFTED = 9, - ERR_TAXIPLAYERBUSY = 11, - ERR_TAXIPLAYERALREADYMOUNTED = 12, - ERR_TAXIPLAYERMOVING = 15 + ERR_TAXIPLAYERMOVING = 1, + ERR_TAXIPLAYERALREADYMOUNTED = 2, + ERR_TAXIPLAYERBUSY = 3, + ERR_TAXINOTENOUGHMONEY = 5, + ERR_TAXINOTSTANDING = 6, + ERR_TAXIPLAYERSHAPESHIFTED = 8, + ERR_TAXIUNSPECIFIEDSERVERERROR = 9, + ERR_TAXINOSUCHPATH = 11, + ERR_TAXIOK = 12, + ERR_TAXISAMENODE = 13, + ERR_TAXITOOFARAWAY = 14, + ERR_TAXINOTVISITED = 15 +}; + +enum TaxiNodeStatus +{ + TAXISTATUS_NOT_ELIGIBLE = 0, + TAXISTATUS_UNLEARNED = 1, + TAXISTATUS_LEARNED = 2, + TAXISTATUS_NONE = 3 }; enum ProfessionUI diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index c8c26af2be2..367b0763e5a 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -689,3 +689,9 @@ WorldPacket const* WorldPackets::Movement::ControlUpdate::Write() return &_worldPacket; } + +void WorldPackets::Movement::MoveSplineDone::Read() +{ + _worldPacket >> movementInfo; + _worldPacket >> SplineID; +} diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index b00d29f5501..2fef4d10227 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -423,6 +423,17 @@ namespace WorldPackets ObjectGuid Guid; bool On = false; }; + + class MoveSplineDone final : public ClientPacket + { + public: + MoveSplineDone(WorldPacket&& packet) : ClientPacket(CMSG_MOVE_SPLINE_DONE, std::move(packet)) { } + + void Read() override; + + MovementInfo movementInfo; + int32 SplineID; + }; } ByteBuffer& operator<<(ByteBuffer& data, Movement::MonsterSplineFilterKey const& monsterSplineFilterKey); diff --git a/src/server/game/Server/Packets/TaxiPackets.cpp b/src/server/game/Server/Packets/TaxiPackets.cpp new file mode 100644 index 00000000000..1223d1c7366 --- /dev/null +++ b/src/server/game/Server/Packets/TaxiPackets.cpp @@ -0,0 +1,78 @@ +/* +* Copyright (C) 2008-2015 TrinityCore +* +* 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, see . +*/ + +#include "TaxiPackets.h" + +void WorldPackets::Taxi::TaxiNodeStatusQuery::Read() +{ + _worldPacket >> UnitGUID; +} + +WorldPacket const* WorldPackets::Taxi::TaxiNodeStatus::Write() +{ + _worldPacket << Unit; + _worldPacket.WriteBits(Status, 2); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Taxi::ShowTaxiNodes::Write() +{ + _worldPacket.WriteBit(WindowInfo.is_initialized()); + _worldPacket.FlushBits(); + + _worldPacket << uint32(Nodes.size()); + + if (WindowInfo.is_initialized()) + { + _worldPacket << WindowInfo->UnitGUID; + _worldPacket << uint32(WindowInfo->CurrentNode); + } + + for (uint8 node : Nodes) + _worldPacket << node; + + return &_worldPacket; +} + +void WorldPackets::Taxi::EnableTaxiNode::Read() +{ + _worldPacket >> Unit; +} + +void WorldPackets::Taxi::TaxiQueryAvailableNodes::Read() +{ + _worldPacket >> Unit; +} + +void WorldPackets::Taxi::ActivateTaxi::Read() +{ + _worldPacket >> Vendor; + _worldPacket >> Node; +} + +WorldPacket const* WorldPackets::Taxi::ActivateTaxiReply::Write() +{ + _worldPacket << Reply; + return &_worldPacket; +} + +void WorldPackets::Taxi::TaxiRequestEarlyLanding::Read() +{ + //Noop as it's empty packet +} diff --git a/src/server/game/Server/Packets/TaxiPackets.h b/src/server/game/Server/Packets/TaxiPackets.h new file mode 100644 index 00000000000..627854635b8 --- /dev/null +++ b/src/server/game/Server/Packets/TaxiPackets.h @@ -0,0 +1,125 @@ +/* +* Copyright (C) 2008-2015 TrinityCore +* +* 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, see . +*/ + +#ifndef TaxiPackets_h__ +#define TaxiPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace Taxi + { + class TaxiNodeStatusQuery final : public ClientPacket + { + public: + TaxiNodeStatusQuery(WorldPacket&& packet) : ClientPacket(CMSG_TAXI_NODE_STATUS_QUERY, std::move(packet)) { } + + void Read() override; + + ObjectGuid UnitGUID; + }; + + class TaxiNodeStatus final : public ServerPacket + { + public: + TaxiNodeStatus() : ServerPacket(SMSG_TAXI_NODE_STATUS, 16 + 1) { } + + WorldPacket const* Write() override; + + uint8 Status = 0; // replace with TaxiStatus enum + ObjectGuid Unit; + }; + + struct ShowTaxiNodesWindowInfo + { + ObjectGuid UnitGUID; + int32 CurrentNode = 0; + }; + + class ShowTaxiNodes final : public ServerPacket + { + public: + ShowTaxiNodes() : ServerPacket(SMSG_SHOW_TAXI_NODES) { } + + WorldPacket const* Write() override; + + Optional WindowInfo; + std::vector Nodes; + }; + + class EnableTaxiNode final : public ClientPacket + { + public: + EnableTaxiNode(WorldPacket&& packet) : ClientPacket(CMSG_ENABLE_TAXI_NODE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Unit; + }; + + class TaxiQueryAvailableNodes final : public ClientPacket + { + public: + TaxiQueryAvailableNodes(WorldPacket&& packet) : ClientPacket(CMSG_TAXI_QUERY_AVAILABLE_NODES, std::move(packet)) { } + + void Read() override; + + ObjectGuid Unit; + }; + + class ActivateTaxi final : public ClientPacket + { + public: + ActivateTaxi(WorldPacket&& packet) : ClientPacket(CMSG_ACTIVATE_TAXI, std::move(packet)) { } + + void Read() override; + + ObjectGuid Vendor; + uint32 Node; + }; + + class NewTaxiPath final : public ServerPacket + { + public: + NewTaxiPath() : ServerPacket(SMSG_NEW_TAXI_PATH, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; + + class ActivateTaxiReply final : public ServerPacket + { + public: + ActivateTaxiReply() : ServerPacket(SMSG_ACTIVATE_TAXI_REPLY, 4) { } + + WorldPacket const* Write() override; + + uint32 Reply; + }; + + class TaxiRequestEarlyLanding final : public ClientPacket + { + public: + TaxiRequestEarlyLanding(WorldPacket&& packet) : ClientPacket(CMSG_TAXI_REQUEST_EARLY_LANDING, std::move(packet)) { } + + void Read() override; + }; + } +} + +#endif // TaxiPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a214fd44556..c7e40c45289 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -52,6 +52,7 @@ #include "Packets/ScenePackets.h" #include "Packets/SocialPackets.h" #include "Packets/TalentPackets.h" +#include "Packets/TaxiPackets.h" #include "Packets/TicketPackets.h" #include "Packets/TokenPackets.h" #include "Packets/TotemPackets.h" @@ -161,7 +162,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_ACCEPT_LEVEL_GRANT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::RaF::AcceptLevelGrant, &WorldSession::HandleAcceptGrantLevel); DEFINE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::AcceptTrade, &WorldSession::HandleAcceptTradeOpcode); DEFINE_HANDLER(CMSG_ACCEPT_WARGAME_INVITE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_ACTIVATE_TAXI, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiOpcode ); + DEFINE_HANDLER(CMSG_ACTIVATE_TAXI, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Taxi::ActivateTaxi, &WorldSession::HandleActivateTaxiOpcode); DEFINE_HANDLER(CMSG_ADD_BATTLENET_FRIEND, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_ADD_FRIEND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Social::AddFriend, &WorldSession::HandleAddFriendOpcode); DEFINE_HANDLER(CMSG_ADD_IGNORE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Social::AddIgnore, &WorldSession::HandleAddIgnoreOpcode); @@ -367,7 +368,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_EJECT_PASSENGER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::EjectPassenger, &WorldSession::HandleEjectPassenger); DEFINE_HANDLER(CMSG_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::EmoteClient, &WorldSession::HandleEmoteOpcode); DEFINE_HANDLER(CMSG_ENABLE_NAGLE, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); - DEFINE_OPCODE_HANDLER_OLD(CMSG_ENABLE_TAXI_NODE, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes ); + DEFINE_HANDLER(CMSG_ENABLE_TAXI_NODE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Taxi::EnableTaxiNode, &WorldSession::HandleEnableTaxiNodeOpcode); DEFINE_HANDLER(CMSG_ENGINE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_ENUM_CHARACTERS, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::EnumCharacters, &WorldSession::HandleCharEnumOpcode); DEFINE_HANDLER(CMSG_ENUM_CHARACTERS_DELETED_BY_CLIENT, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::EnumCharacters, &WorldSession::HandleCharUndeleteEnumOpcode); @@ -555,7 +556,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_MOVE_SET_RUN_MODE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); DEFINE_HANDLER(CMSG_MOVE_SET_VEHICLE_REC_ID_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Vehicle::MoveSetVehicleRecIdAck, &WorldSession::HandleMoveSetVehicleRecAck); DEFINE_HANDLER(CMSG_MOVE_SET_WALK_MODE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MOVE_SPLINE_DONE, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleMoveSplineDoneOpcode ); + DEFINE_HANDLER(CMSG_MOVE_SPLINE_DONE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::MoveSplineDone, &WorldSession::HandleMoveSplineDoneOpcode); DEFINE_HANDLER(CMSG_MOVE_START_ASCEND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); DEFINE_HANDLER(CMSG_MOVE_START_BACKWARD, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); DEFINE_HANDLER(CMSG_MOVE_START_DESCEND, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Movement::ClientPlayerMovement, &WorldSession::HandleMovementOpcodes); @@ -777,9 +778,9 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SWAP_VOID_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::VoidStorage::SwapVoidItem, &WorldSession::HandleVoidSwapItem); DEFINE_HANDLER(CMSG_TABARD_VENDOR_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTabardVendorActivateOpcode); DEFINE_HANDLER(CMSG_TALK_TO_GOSSIP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TAXI_NODE_STATUS_QUERY, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleTaxiNodeStatusQueryOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TAXI_QUERY_AVAILABLE_NODES, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes ); - DEFINE_HANDLER(CMSG_TAXI_REQUEST_EARLY_LANDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_TAXI_NODE_STATUS_QUERY, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Taxi::TaxiNodeStatusQuery, &WorldSession::HandleTaxiNodeStatusQueryOpcode); + DEFINE_HANDLER(CMSG_TAXI_QUERY_AVAILABLE_NODES, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Taxi::TaxiQueryAvailableNodes, &WorldSession::HandleTaxiQueryAvailableNodesOpcode); + DEFINE_HANDLER(CMSG_TAXI_REQUEST_EARLY_LANDING, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Taxi::TaxiRequestEarlyLanding, &WorldSession::HandleTaxiRequestEarlyLanding); DEFINE_HANDLER(CMSG_TELEPORT_TO_UNIT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TIME_ADJUSTMENT_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TIME_SYNC_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::TimeSyncResponse, &WorldSession::HandleTimeSyncResponse); @@ -845,7 +846,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_TOYS_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATE_TAXI_REPLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATE_TAXI_REPLY, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADDON_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_BATTLENET_FRIEND_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_ITEM_PASSIVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1415,7 +1416,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UPDATE_WALK_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_PACKETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEUTRAL_PLAYER_FACTION_SELECT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_TAXI_PATH, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NEW_WORLD, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DEST_LOC_SPELL_CAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1631,7 +1632,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_BANK, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_MAILBOX, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_NEUTRAL_PLAYER_FACTION_SELECT_UI, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_TAXI_NODES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_TAXI_NODES, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SHOW_TRADE_SKILL_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SOCKET_GEMS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SOR_START_EXPERIENCE_INCOMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1677,7 +1678,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TAXI_NODE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TAXI_NODE_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TEXT_EMOTE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_CLEAR, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_THREAT_REMOVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 54c794ad0ca..95b66e1aceb 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -399,6 +399,7 @@ namespace WorldPackets class MoveSetCollisionHeightAck; class MoveTimeSkipped; class SummonResponse; + class MoveSplineDone; } namespace NPC @@ -555,6 +556,16 @@ namespace WorldPackets class SetSpecialization; class LearnTalents; } + + namespace Taxi + { + class ShowTaxiNodes; + class TaxiNodeStatusQuery; + class EnableTaxiNode; + class TaxiQueryAvailableNodes; + class ActivateTaxi; + class TaxiRequestEarlyLanding; + } namespace Ticket { @@ -1233,12 +1244,13 @@ class WorldSession void HandleGuildFinderRemoveRecruit(WorldPacket& recvPacket); void HandleGuildFinderSetGuildPost(WorldPacket& recvPacket); - void HandleTaxiNodeStatusQueryOpcode(WorldPacket& recvPacket); - void HandleTaxiQueryAvailableNodes(WorldPacket& recvPacket); - void HandleActivateTaxiOpcode(WorldPacket& recvPacket); - void HandleActivateTaxiExpressOpcode(WorldPacket& recvPacket); - void HandleMoveSplineDoneOpcode(WorldPacket& recvPacket); + void HandleEnableTaxiNodeOpcode(WorldPackets::Taxi::EnableTaxiNode& packet); + void HandleTaxiNodeStatusQueryOpcode(WorldPackets::Taxi::TaxiNodeStatusQuery& packet); + void HandleTaxiQueryAvailableNodesOpcode(WorldPackets::Taxi::TaxiQueryAvailableNodes& packet); + void HandleActivateTaxiOpcode(WorldPackets::Taxi::ActivateTaxi& packet); + void HandleMoveSplineDoneOpcode(WorldPackets::Movement::MoveSplineDone& packet); void SendActivateTaxiReply(ActivateTaxiReply reply); + void HandleTaxiRequestEarlyLanding(WorldPackets::Taxi::TaxiRequestEarlyLanding& packet); void HandleTabardVendorActivateOpcode(WorldPackets::NPC::Hello& packet); void HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index d6cceac46fb..abbe5d9bd24 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -60,6 +60,7 @@ #include "SkillExtraItems.h" #include "SmartAI.h" #include "SupportMgr.h" +#include "TaxiPathGraph.h" #include "TransportMgr.h" #include "Unit.h" #include "VMapFactory.h" @@ -1470,6 +1471,9 @@ void World::SetInitialWorldSettings() ///- Load GameTables LoadGameTables(m_dataPath, m_defaultDbcLocale); + //Load weighted graph on taxi nodes path + TaxiPathGraph::Initialize(); + sSpellMgr->LoadPetFamilySpellsStore(); std::unordered_map> mapData; -- cgit v1.2.3