diff options
| author | Shauren <shauren.trinity@gmail.com> | 2015-09-19 17:41:24 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2015-09-19 17:41:24 +0200 |
| commit | 3b52fcc7693f14f2b7e6f2130a73379ec33bd5c0 (patch) | |
| tree | 5e9aad7a3564e7d3d74a1ffd91579db41bb0c388 /src/server/game/Entities | |
| parent | 10b068ce5dbf9da7be6a727e0cdb0360f5c4b615 (diff) | |
| parent | f34bae89d3869ddc5f74a85d9a6fa44f67ca4635 (diff) | |
Merge remote-tracking branch 'origin/6.x_implement_taxi' into 6.x
Diffstat (limited to 'src/server/game/Entities')
| -rw-r--r-- | src/server/game/Entities/Object/Object.h | 33 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Position.h | 33 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 147 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 60 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/PlayerTaxi.cpp | 180 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/PlayerTaxi.h | 66 | ||||
| -rw-r--r-- | src/server/game/Entities/Taxi/TaxiPathGraph.cpp | 186 | ||||
| -rw-r--r-- | src/server/game/Entities/Taxi/TaxiPathGraph.h | 71 |
8 files changed, 541 insertions, 235 deletions
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 42e5137e6f9..54b6677f714 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -351,39 +351,6 @@ struct MovementInfo void OutDebug(); }; -#define MAPID_INVALID 0xFFFFFFFF - -class WorldLocation : public Position -{ - public: - explicit WorldLocation(uint32 _mapId = MAPID_INVALID, float _x = 0.f, float _y = 0.f, float _z = 0.f, float _o = 0.f) - : Position(_x, _y, _z, _o), m_mapId(_mapId) { } - - WorldLocation(WorldLocation const& loc) - : Position(loc), m_mapId(loc.GetMapId()) { } - - void WorldRelocate(WorldLocation const& loc) - { - m_mapId = loc.GetMapId(); - Relocate(loc); - } - - void WorldRelocate(uint32 _mapId = MAPID_INVALID, float _x = 0.f, float _y = 0.f, float _z = 0.f, float _o = 0.f) - { - m_mapId = _mapId; - Relocate(_x, _y, _z, _o); - } - - WorldLocation GetWorldLocation() const - { - return *this; - } - - uint32 GetMapId() const { return m_mapId; } - - uint32 m_mapId; -}; - template<class T> class GridObject { diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index 5bd37567811..109ff09d66c 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -215,6 +215,39 @@ public: } }; +#define MAPID_INVALID 0xFFFFFFFF + +class WorldLocation : public Position +{ +public: + explicit WorldLocation(uint32 mapId = MAPID_INVALID, float x = 0.f, float y = 0.f, float z = 0.f, float o = 0.f) + : Position(x, y, z, o), m_mapId(mapId) { } + + WorldLocation(WorldLocation const& loc) + : Position(loc), m_mapId(loc.GetMapId()) { } + + void WorldRelocate(WorldLocation const& loc) + { + m_mapId = loc.GetMapId(); + Relocate(loc); + } + + void WorldRelocate(uint32 mapId = MAPID_INVALID, float x = 0.f, float y = 0.f, float z = 0.f, float o = 0.f) + { + m_mapId = mapId; + Relocate(x, y, z, o); + } + + WorldLocation GetWorldLocation() const + { + return *this; + } + + uint32 GetMapId() const { return m_mapId; } + + uint32 m_mapId; +}; + ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 33f3b3cab16..6af50b89b43 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 @@ -20916,7 +20775,10 @@ void Player::SetRestBonus(float rest_bonus_new) bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/) { if (nodes.size() < 2) + { + GetSession()->SendActivateTaxiReply(ERR_TAXINOSUCHPATH); return false; + } // not let cheating with start flight in time of logout process || while in combat || has type state: stunned || has type state: root if (GetSession()->isLogingOut() || IsInCombat() || HasUnitState(UNIT_STATE_STUNNED) || HasUnitState(UNIT_STATE_ROOT)) @@ -20999,7 +20861,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 20f6e201f0f..d16fc7a1fc1 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..466cb7b947b --- /dev/null +++ b/src/server/game/Entities/Player/PlayerTaxi.cpp @@ -0,0 +1,180 @@ +#include "Player.h" +#include "TaxiPackets.h" +#include "ObjectMgr.h" +#include <limits> +#include <math.h> + +void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) +{ + // class specific initial known nodes + TaxiMask const& factionMask = Player::TeamForRace(race) == HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask; + switch (chrClass) + { + case CLASS_DEATH_KNIGHT: + { + for (uint8 i = 0; i < TaxiMaskSize; ++i) + m_taximask[i] |= sOldContinentsNodesMask[i] & factionMask[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) + data.Nodes = &sTaxiNodesMask; // all existed nodes + else + data.Nodes = &m_taximask; // known nodes +} + +bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team) +{ + ClearTaxiDestinations(); + + Tokenizer tokens(values, ' '); + + for (Tokenizer::const_iterator iter = tokens.begin(); iter != tokens.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..6739f5f6ab1 --- /dev/null +++ b/src/server/game/Entities/Player/PlayerTaxi.h @@ -0,0 +1,66 @@ +#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(); + 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); + +#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..ef899795bfd --- /dev/null +++ b/src/server/game/Entities/Taxi/TaxiPathGraph.cpp @@ -0,0 +1,186 @@ +/* + * 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 "TaxiPathGraph.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "DBCStores.h" +#include "DB2Stores.h" +#include "Config.h" +#include "Util.h" +#include <boost/graph/dijkstra_shortest_paths.hpp> +#include <boost/property_map/transform_value_property_map.hpp> + +void TaxiPathGraph::Initialize() +{ + if (GetVertexCount() > 0) + return; + + std::vector<std::pair<edge, EdgeCost>> edges; + + // Initialize here + for (TaxiPathEntry const* path : sTaxiPathStore) + { + TaxiNodesEntry const* from = sTaxiNodesStore.LookupEntry(path->From); + TaxiNodesEntry const* to = sTaxiNodesStore.LookupEntry(path->To); + if (from && to && from->Flags & (TAXI_NODE_FLAG_ALLIANCE | TAXI_NODE_FLAG_HORDE) && to->Flags & (TAXI_NODE_FLAG_ALLIANCE | TAXI_NODE_FLAG_HORDE)) + AddVerticeAndEdgeFromNodeInfo(from, to, path->ID, edges); + } + + // create graph + m_graph = Graph(GetVertexCount()); + WeightMap weightmap = boost::get(boost::edge_weight, m_graph); + + for (std::size_t j = 0; j < edges.size(); ++j) + { + edge_descriptor e = boost::add_edge(edges[j].first.first, edges[j].first.second, m_graph).first; + weightmap[e] = edges[j].second; + } +} + +uint32 TaxiPathGraph::GetNodeIDFromVertexID(vertex_descriptor vertexID) +{ + if (vertexID < m_vertices.size()) + return m_vertices[vertexID]->ID; + + return std::numeric_limits<uint32>::max(); +} + +TaxiPathGraph::vertex_descriptor TaxiPathGraph::GetVertexIDFromNodeID(TaxiNodesEntry const* node) +{ + return node->LearnableIndex; +} + +std::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(TaxiNodesEntry const* from, TaxiNodesEntry const* to, uint32 pathId, std::vector<std::pair<edge, EdgeCost>>& edges) +{ + if (from != to) + { + vertex_descriptor fromVertexID = CreateVertexFromFromNodeInfoIfNeeded(from); + vertex_descriptor toVertexID = CreateVertexFromFromNodeInfoIfNeeded(to); + + float totalDist = 0.0f; + TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[pathId]; + if (nodes.size() < 2) + { + edges.push_back(std::make_pair(edge(fromVertexID, toVertexID), EdgeCost{ to, 0xFFFF })); + return; + } + + std::size_t last = nodes.size(); + std::size_t first = 0; + if (nodes.size() > 2) + { + --last; + ++first; + } + + for (std::size_t i = first + 1; i < last; ++i) + { + if (nodes[i - 1]->Flags & TAXI_PATH_NODE_FLAG_TELEPORT) + continue; + + uint32 map1, map2; + DBCPosition2D pos1, pos2; + + DeterminaAlternateMapPosition(nodes[i - 1]->MapID, nodes[i - 1]->Loc.X, nodes[i - 1]->Loc.Y, nodes[i - 1]->Loc.Z, &map1, &pos1); + DeterminaAlternateMapPosition(nodes[i]->MapID, nodes[i]->Loc.X, nodes[i]->Loc.Y, nodes[i]->Loc.Z, &map2, &pos2); + + if (map1 != map2) + continue; + + totalDist += std::sqrt( + std::pow(pos2.X - pos1.X, 2) + + std::pow(pos2.Y - pos1.Y, 2) + + std::pow(nodes[i]->Loc.Z - nodes[i - 1]->Loc.Z, 2)); + } + + uint32 dist = uint32(totalDist); + if (dist > 0xFFFF) + return; + + edges.push_back(std::make_pair(edge(fromVertexID, toVertexID), EdgeCost{ to, dist })); + } +} + +std::size_t TaxiPathGraph::GetCompleteNodeRoute(TaxiNodesEntry const* from, TaxiNodesEntry const* to, Player const* player, 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, we need to use Dijkstra algorithm. + 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 we use dijkstra to find the shortest path. + * When early landing is requested, according to behavior on retail, you can never end in a node you did not discovered before + */ + + // Find if we have a direct path + uint32 pathId, goldCost; + sObjectMgr->GetTaxiPath(from->ID, to->ID, pathId, goldCost); + if (pathId) + shortestPath = { from->ID, to->ID }; + else + { + shortestPath.clear(); + std::vector<vertex_descriptor> p(boost::num_vertices(m_graph)); + + boost::dijkstra_shortest_paths(m_graph, GetVertexIDFromNodeID(from), + boost::predecessor_map(boost::make_iterator_property_map(p.begin(), boost::get(boost::vertex_index, m_graph))) + .weight_map(boost::make_transform_value_property_map( + [player](EdgeCost const& edgeCost) { return edgeCost.EvaluateDistance(player); }, + boost::get(boost::edge_weight, m_graph)))); + + // found a path to the goal + for (vertex_descriptor v = GetVertexIDFromNodeID(to); ; v = p[v]) + { + shortestPath.push_back(GetNodeIDFromVertexID(v)); + if (v == p[v]) + break; + } + + std::reverse(shortestPath.begin(), shortestPath.end()); + } + + return shortestPath.size(); +} + +TaxiPathGraph::vertex_descriptor TaxiPathGraph::CreateVertexFromFromNodeInfoIfNeeded(TaxiNodesEntry const* node) +{ + //Check if we need a new one or if it may be already created + if (m_vertices.size() <= node->LearnableIndex) + m_vertices.resize(node->LearnableIndex + 1); + + m_vertices[node->LearnableIndex] = node; + return node->LearnableIndex; +} + +uint32 TaxiPathGraph::EdgeCost::EvaluateDistance(Player const* player) const +{ + uint32 requireFlag = (player->GetTeam() == ALLIANCE) ? TAXI_NODE_FLAG_ALLIANCE : TAXI_NODE_FLAG_HORDE; + if (!(To->Flags & requireFlag)) + return std::numeric_limits<uint16>::max(); + + //if (To->ConditionID && !player->MeetsCondition(To->ConditionID)) + // return std::numeric_limits<uint16>::max(); + + return Distance; +} diff --git a/src/server/game/Entities/Taxi/TaxiPathGraph.h b/src/server/game/Entities/Taxi/TaxiPathGraph.h new file mode 100644 index 00000000000..15d139fb55d --- /dev/null +++ b/src/server/game/Entities/Taxi/TaxiPathGraph.h @@ -0,0 +1,71 @@ +/* + * 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 TAXIPATHGRAPH_HPP +#define TAXIPATHGRAPH_HPP + +#include "Position.h" +#include "Define.h" +#include <boost/graph/adjacency_list.hpp> + +class Player; +struct TaxiNodesEntry; + +class TaxiPathGraph +{ +public: + static TaxiPathGraph& Instance() + { + static TaxiPathGraph instance; + return instance; + } + + void Initialize(); + std::size_t GetCompleteNodeRoute(TaxiNodesEntry const* from, TaxiNodesEntry const* to, Player const* player, std::vector<uint32>& shortestPath); + +private: + struct EdgeCost + { + TaxiNodesEntry const* To; + uint32 Distance; + uint32 EvaluateDistance(Player const* player) const; + }; + typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::property<boost::vertex_index_t, uint32>, boost::property<boost::edge_weight_t, EdgeCost>> Graph; + typedef boost::property_map<Graph, boost::edge_weight_t>::type WeightMap; + typedef Graph::vertex_descriptor vertex_descriptor; + typedef Graph::edge_descriptor edge_descriptor; + typedef std::pair<uint32, uint32> edge; + + TaxiPathGraph() { } + ~TaxiPathGraph() { } + + void AddVerticeAndEdgeFromNodeInfo(TaxiNodesEntry const* from, TaxiNodesEntry const* to, uint32 pathId, std::vector<std::pair<edge, EdgeCost>>& edges); + vertex_descriptor GetVertexIDFromNodeID(TaxiNodesEntry const* node); + uint32 GetNodeIDFromVertexID(vertex_descriptor vertexID); + vertex_descriptor CreateVertexFromFromNodeInfoIfNeeded(TaxiNodesEntry const* node); + std::size_t GetVertexCount(); + + Graph m_graph; + std::vector<TaxiNodesEntry const*> m_vertices; + + TaxiPathGraph(TaxiPathGraph const&) = delete; + TaxiPathGraph& operator=(TaxiPathGraph const&) = delete; +}; + +#define sTaxiPathGraph TaxiPathGraph::Instance() + +#endif /* TAXIPATHGRAPH_HPP */ |
