aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStormBytePP <stormbyte@gmail.com>2015-08-30 19:26:33 +0200
committerStormBytePP <stormbyte@gmail.com>2015-09-14 01:51:38 +0200
commit196f935cd8d22d0d412d463683145c7ac6283e35 (patch)
treeed3762158eea64c6a392169e9e9cbe539941ea9c /src
parent04de58c8d3beb393233071650c65d50967b45266 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/server/game/CMakeLists.txt1
-rw-r--r--src/server/game/Entities/Player/Player.cpp144
-rw-r--r--src/server/game/Entities/Player/Player.h60
-rw-r--r--src/server/game/Entities/Player/PlayerTaxi.cpp189
-rw-r--r--src/server/game/Entities/Player/PlayerTaxi.h65
-rw-r--r--src/server/game/Entities/Taxi/TaxiPathGraph.cpp184
-rw-r--r--src/server/game/Entities/Taxi/TaxiPathGraph.h91
-rw-r--r--src/server/game/Globals/ObjectMgr.h1
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp44
-rw-r--r--src/server/game/Handlers/TaxiHandler.cpp198
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h32
-rw-r--r--src/server/game/Server/Packets/MovementPackets.cpp6
-rw-r--r--src/server/game/Server/Packets/MovementPackets.h11
-rw-r--r--src/server/game/Server/Packets/TaxiPackets.cpp78
-rw-r--r--src/server/game/Server/Packets/TaxiPackets.h125
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp21
-rw-r--r--src/server/game/Server/WorldSession.h22
-rw-r--r--src/server/game/World/World.cpp4
18 files changed, 908 insertions, 368 deletions
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<uint32> 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 <limits>
-#include <string>
-#include <vector>
+#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<uint32> 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<uint32> 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 <limits>
+#include <math.h>
+
+
+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<uint32>::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 <map>
+
+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<uint32>& 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<uint32> 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 <utility>
+#include "Util.h"
+#include "DB2Stores.h"
+#include "Config.h"
+#include <boost/property_map/transform_value_property_map.hpp>
+
+
+TaxiPathGraph::Graph TaxiPathGraph::m_graph = TaxiPathGraph::Graph();
+std::vector<TaxiPathGraph::TaxiNodeInfo> TaxiPathGraph::m_vertices = std::vector<TaxiPathGraph::TaxiNodeInfo>();
+std::map<uint32, TaxiPathGraph::vertex> TaxiPathGraph::m_nodeIDToVertexID = std::map<uint32, TaxiPathGraph::vertex>();
+std::set<TaxiPathGraph::edge> TaxiPathGraph::m_edgeDuplicateControl = std::set<TaxiPathGraph::edge>();
+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<std::pair<edge, cost>> edges;
+
+ std::set<uint32> 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<uint32>::max();
+}
+
+TaxiPathGraph::vertex TaxiPathGraph::_getVertexIDFromNodeID(uint32_t nodeID)
+{
+ if (m_nodeIDToVertexID.find(nodeID) != m_nodeIDToVertexID.end())
+ return m_nodeIDToVertexID[nodeID];
+
+ return std::numeric_limits<vertex>::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<vertex>::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<std::pair<edge, cost>>& 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<uint32>& 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<Graph>::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<Graph::vertex_descriptor> p(boost::num_vertices(m_graph));
+ std::vector<cost> 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<cost>::infinity() : w; },
+ boost::get(boost::edge_weight, m_graph)
+ );
+ boost::astar_search(m_graph, start,
+ boost::astar_heuristic<Graph, cost>(),
+ 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<vertex>(goal)));
+ }
+ catch(found_goal fg)
+ { // found a path to the goal
+ std::list<vertex> shortest_path;
+ for(vertex v = goal;; v = p[v]) {
+ shortest_path.push_front(v);
+ if(p[v] == v)
+ break;
+ }
+
+ for(std::list<vertex>::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 <boost/graph/astar_search.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <vector>
+#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<uint32>& /* 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 Vertex>
+ class astar_goal_visitor : public boost::default_astar_visitor
+ {
+ public:
+ astar_goal_visitor(Vertex goal) : m_goal(goal) {}
+ template <class Graph>
+ 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::listS, boost::vecS, boost::directedS, boost::property<boost::vertex_index_t, uint32>, boost::property<boost::edge_weight_t, cost> > Graph;
+ typedef boost::property_map<Graph, boost::edge_weight_t>::type WeightMap;
+ typedef boost::property_map<Graph, boost::vertex_index_t>::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<uint32, uint32> edge;
+
+ static Graph m_graph;
+ static std::vector<TaxiNodeInfo> m_vertices;
+ static std::map<uint32, vertex> m_nodeIDToVertexID;
+ static std::set<edge> m_edgeDuplicateControl;
+ static const int MaxFlightDistanceThreshold;
+
+ static void _addVerticeAndEdgeFromNodeInfo(TaxiNodeInfo const& /* from */, TaxiNodeInfo const& /* to */, uint32 /* money */, std::vector<std::pair<edge, cost>>& /* 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<uint32>& 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<uint32> 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<uint32>(); // 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<uint32> 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<uint32> 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 <http://www.trinitycore.org/>
+*
+* 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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 <http://www.trinitycore.org/>
+*
+* 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<ShowTaxiNodesWindowInfo> WindowInfo;
+ std::vector<uint8> 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<uint32, std::vector<uint32>> mapData;