diff options
Diffstat (limited to 'src')
33 files changed, 1016 insertions, 473 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/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 68658586239..61b5da47b7f 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -134,7 +134,6 @@ TaxiMask sTaxiNodesMask; TaxiMask sOldContinentsNodesMask; TaxiMask sHordeTaxiNodesMask; TaxiMask sAllianceTaxiNodesMask; -TaxiMask sDeathKnightTaxiNodesMask; TaxiPathSetBySource sTaxiPathSetBySource; TaxiPathNodesByPath sTaxiPathNodesByPath; @@ -455,55 +454,29 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) TaxiMaskSize, (((sTaxiNodesStore.GetNumRows() - 1) / 8) + 1)); } - std::set<uint32> spellPaths; - for (SpellEffectEntry const* sInfo : sSpellEffectStore) - if (sInfo->Effect == SPELL_EFFECT_SEND_TAXI) - spellPaths.insert(sInfo->EffectMiscValue); - - memset(sTaxiNodesMask, 0, sizeof(sTaxiNodesMask)); - memset(sOldContinentsNodesMask, 0, sizeof(sOldContinentsNodesMask)); - memset(sHordeTaxiNodesMask, 0, sizeof(sHordeTaxiNodesMask)); - memset(sAllianceTaxiNodesMask, 0, sizeof(sAllianceTaxiNodesMask)); - memset(sDeathKnightTaxiNodesMask, 0, sizeof(sDeathKnightTaxiNodesMask)); + sTaxiNodesMask.fill(0); + sOldContinentsNodesMask.fill(0); + sHordeTaxiNodesMask.fill(0); + sAllianceTaxiNodesMask.fill(0); for (TaxiNodesEntry const* node : sTaxiNodesStore) { - TaxiPathSetBySource::const_iterator src_i = sTaxiPathSetBySource.find(node->ID); - if (src_i != sTaxiPathSetBySource.end() && !src_i->second.empty()) - { - bool ok = false; - for (TaxiPathSetForSource::const_iterator dest_i = src_i->second.begin(); dest_i != src_i->second.end(); ++dest_i) - { - // not spell path - if (spellPaths.find(dest_i->second.ID) == spellPaths.end()) - { - ok = true; - break; - } - } - - if (!ok) - continue; - } + if (!(node->Flags & (TAXI_NODE_FLAG_ALLIANCE | TAXI_NODE_FLAG_HORDE))) + continue; // valid taxi network node uint8 field = (uint8)((node->ID - 1) / 8); uint32 submask = 1 << ((node->ID - 1) % 8); sTaxiNodesMask[field] |= submask; - if (node->MountCreatureID[0] && node->MountCreatureID[0] != 32981) + if (node->Flags & TAXI_NODE_FLAG_HORDE) sHordeTaxiNodesMask[field] |= submask; - if (node->MountCreatureID[1] && node->MountCreatureID[1] != 32981) + if (node->Flags & TAXI_NODE_FLAG_ALLIANCE) sAllianceTaxiNodesMask[field] |= submask; - if (node->MountCreatureID[0] == 32981 || node->MountCreatureID[1] == 32981) - sDeathKnightTaxiNodesMask[field] |= submask; - // old continent node (+ nodes virtually at old continents, check explicitly to avoid loading map files for zone info) - if (node->MapID < 2 || node->ID == 82 || node->ID == 83 || node->ID == 93 || node->ID == 94) + uint32 nodeMap; + DeterminaAlternateMapPosition(node->MapID, node->Pos.X, node->Pos.Y, node->Pos.Z, &nodeMap); + if (nodeMap < 2) sOldContinentsNodesMask[field] |= submask; - - // fix DK node at Ebon Hold and Shadow Vault flight master - if (node->ID == 315 || node->ID == 333) - ((TaxiNodesEntry*)node)->MountCreatureID[1] = 32981; } } diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 4184ab5b5d4..0769e6e9739 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -110,7 +110,6 @@ extern TaxiMask sTaxiNodesMask; extern TaxiMask sOldContinentsNodesMask; extern TaxiMask sHordeTaxiNodesMask; extern TaxiMask sAllianceTaxiNodesMask; -extern TaxiMask sDeathKnightTaxiNodesMask; extern TaxiPathSetBySource sTaxiPathSetBySource; extern TaxiPathNodesByPath sTaxiPathNodesByPath; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 9c898ea0101..0544ce82cea 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -1361,6 +1361,6 @@ typedef std::vector<TaxiPathNodeEntry const*> TaxiPathNodeList; typedef std::vector<TaxiPathNodeList> TaxiPathNodesByPath; #define TaxiMaskSize 217 -typedef uint8 TaxiMask[TaxiMaskSize]; +typedef std::array<uint8, TaxiMaskSize> TaxiMask; #endif diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index ed1a1470e91..6a230bc9d1e 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -684,6 +684,18 @@ enum SummonPropFlags SUMMON_PROP_FLAG_UNK21 = 0x00100000 // Totems }; +enum TaxiNodeFlags +{ + TAXI_NODE_FLAG_ALLIANCE = 0x1, + TAXI_NODE_FLAG_HORDE = 0x2 +}; + +enum TaxiPathNodeFlags +{ + TAXI_PATH_NODE_FLAG_TELEPORT = 0x1, + TAXI_PATH_NODE_FLAG_STOP = 0x2 +}; + enum VehicleSeatFlags { VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001, diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 8402c3989b3..1d3a982d586 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -156,6 +156,7 @@ DBCStorage<VehicleSeatEntry> sVehicleSeatStore(VehicleSeatfmt); DBCStorage<WMOAreaTableEntry> sWMOAreaTableStore(WMOAreaTablefmt); static WMOAreaInfoByTripple sWMOAreaInfoByTripple; DBCStorage<WorldMapAreaEntry> sWorldMapAreaStore(WorldMapAreafmt); +DBCStorage<WorldMapTransformsEntry> sWorldMapTransformsStore(WorldMapTransformsfmt); DBCStorage<WorldSafeLocsEntry> sWorldSafeLocsStore(WorldSafeLocsfmt); GameTable<GtBarberShopCostBaseEntry> sGtBarberShopCostBaseStore(GtBarberShopCostBasefmt); @@ -376,6 +377,7 @@ void LoadDBCStores(const std::string& dataPath, uint32 defaultLocale) LOAD_DBC(sVehicleStore, "Vehicle.dbc");//20444 LOAD_DBC(sWMOAreaTableStore, "WMOAreaTable.dbc");//20444 LOAD_DBC(sWorldMapAreaStore, "WorldMapArea.dbc");//20444 + LOAD_DBC(sWorldMapTransformsStore, "WorldMapTransforms.dbc");//20444 LOAD_DBC(sWorldSafeLocsStore, "WorldSafeLocs.dbc"); // 20444 #undef LOAD_DBC @@ -893,3 +895,51 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u return NULL; } + +void DeterminaAlternateMapPosition(uint32 mapId, float x, float y, float z, uint32* newMapId /*= nullptr*/, DBCPosition2D* newPos /*= nullptr*/) +{ + WorldMapTransformsEntry const* transformation = nullptr; + for (WorldMapTransformsEntry const* transform : sWorldMapTransformsStore) + { + if (transform->MapID != mapId) + continue; + + if (transform->RegionMin.X > x || transform->RegionMax.X < x) + continue; + if (transform->RegionMin.Y > y || transform->RegionMax.Y < y) + continue; + if (transform->RegionMin.Z > z || transform->RegionMax.Z < z) + continue; + + transformation = transform; + break; + } + + if (!transformation) + { + if (newMapId) + *newMapId = mapId; + + if (newPos) + { + newPos->X = x; + newPos->Y = y; + } + return; + } + + if (newMapId) + *newMapId = transformation->NewMapID; + + if (!newPos) + return; + + if (transformation->RegionScale > 0.0f && transformation->RegionScale < 1.0f) + { + newPos->X = (x - transformation->RegionMin.X) * transformation->RegionScale + transformation->RegionMin.X; + newPos->Y = (y - transformation->RegionMin.Y) * transformation->RegionScale + transformation->RegionMin.Y; + } + + newPos->X += transformation->RegionOffset.X; + newPos->Y += transformation->RegionOffset.Y; +} diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index c8e03ee95e7..63cff4a4fea 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -93,6 +93,8 @@ uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId); void Zone2MapCoordinates(float &x, float &y, uint32 worldMapAreaId); void Map2ZoneCoordinates(float &x, float &y, uint32 worldMapAreaId); +// WorldMapTransforms +void DeterminaAlternateMapPosition(uint32 mapId, float x, float y, float z, uint32* newMapId = nullptr, DBCPosition2D* newPos = nullptr); uint32 GetMaxLevelForExpansion(uint32 expansion); uint32 GetExpansionForLevel(uint32 level); diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index b2a2704307e..76487aadffc 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1411,6 +1411,20 @@ struct WorldMapAreaEntry //uint32 LevelRangeMax; // 13 Maximum recommended level displayed on world map }; +struct WorldMapTransformsEntry +{ + //uint32 ID; // 0 + uint32 MapID; // 1 + DBCPosition3D RegionMin; // 2 + DBCPosition3D RegionMax; // 3 + uint32 NewMapID; // 4 + DBCPosition2D RegionOffset; // 5 + //uint32 NewDungeonMapID; // 6 + //uint32 Flags; // 7 + //uint32 NewAreaID; // 8 + float RegionScale; // 9 +}; + struct WorldSafeLocsEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 6b2163cabca..900df980021 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -120,6 +120,7 @@ char const Vehiclefmt[] = "niiffffiiiiiiiifffffffffffffffxxxxfifiiii"; char const VehicleSeatfmt[] = "niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiffffffffffffiiiiiiiii"; char const WMOAreaTablefmt[] = "niiixxxxxiixxxx"; char const WorldMapAreafmt[] = "xinxffffixxxxx"; +char const WorldMapTransformsfmt[] = "diffffffiffxxxf"; char const WorldSafeLocsfmt[] = "niffffx"; #endif 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 */ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 5352112caca..b048afe16a6 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -5673,9 +5673,10 @@ uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, ui float dist = 10000; uint32 id = 0; + uint32 requireFlag = (team == ALLIANCE) ? TAXI_NODE_FLAG_ALLIANCE : TAXI_NODE_FLAG_HORDE; for (TaxiNodesEntry const* node : sTaxiNodesStore) { - if (!node || node->MapID != mapid || (!node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981)) // dk flight + if (!node || node->MapID != mapid || !(node->Flags & requireFlag)) continue; uint8 field = (uint8)((node->ID - 1) / 8); 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/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 39a81b12336..c3ed19fdf71 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -2009,41 +2009,14 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res // Update Taxi path // this doesn't seem to be 100% blizzlike... but it can't really be helped. std::ostringstream taximaskstream; - uint32 numFullTaximasks = level / 7; - if (numFullTaximasks > 11) - numFullTaximasks = 11; - - if (newTeamId == TEAM_ALLIANCE) + TaxiMask const& factionMask = newTeamId == TEAM_HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask; + for (uint8 i = 0; i < TaxiMaskSize; ++i) { - if (playerClass != CLASS_DEATH_KNIGHT) - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sAllianceTaxiNodesMask[i]) << ' '; - } - else - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sAllianceTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << ' '; - } + // i = (315 - 1) / 8 = 39 + // m = 1 << ((315 - 1) % 8) = 4 + uint8 deathKnightExtraNode = playerClass != CLASS_DEATH_KNIGHT || i != 39 ? 0 : 4; + taximaskstream << uint32(factionMask[i] | deathKnightExtraNode) << ' '; } - else - { - if (playerClass != CLASS_DEATH_KNIGHT) - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sHordeTaxiNodesMask[i]) << ' '; - } - else - { - for (uint8 i = 0; i < numFullTaximasks; ++i) - taximaskstream << uint32(sHordeTaxiNodesMask[i] | sDeathKnightTaxiNodesMask[i]) << ' '; - } - } - - uint32 numEmptyTaximasks = 11 - numFullTaximasks; - for (uint8 i = 0; i < numEmptyTaximasks; ++i) - taximaskstream << "0 "; - taximaskstream << '0'; stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXIMASK); stmt->setString(0, taximaskstream.str()); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 4256a41f80f..279345845a1 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& moveSplineDone) +{ + MovementInfo movementInfo = moveSplineDone.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..d3612e5a031 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& enableTaxiNode) { - ObjectGuid guid; + Creature* unit = GetPlayer()->GetMap()->GetCreature(enableTaxiNode.Unit); + SendLearnNewTaxiNode(unit); +} + - recvData >> guid; - SendTaxiStatus(guid); +void WorldSession::HandleTaxiNodeStatusQueryOpcode(WorldPackets::Taxi::TaxiNodeStatusQuery& taxiNodeStatusQuery) +{ + SendTaxiStatus(taxiNodeStatusQuery.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; + + 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; - TC_LOG_DEBUG("network", "WORLD: current location %u ", curloc); + 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& taxiQueryAvailableNodes) { - ObjectGuid guid; - recvData >> guid; - // cheating checks - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(taxiQueryAvailableNodes.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.", taxiQueryAvailableNodes.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); + WorldPackets::Taxi::ShowTaxiNodes data; + data.WindowInfo = boost::in_place(); + data.WindowInfo->UnitGUID = unit->GetGUID(); + data.WindowInfo->CurrentNode = curloc; - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_SHOWTAXINODES"); + 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,50 @@ 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); - } + SendPacket(WorldPackets::Taxi::NewTaxiPath().Write()); } -void WorldSession::HandleActivateTaxiExpressOpcode (WorldPacket& recvData) +void WorldSession::HandleActivateTaxiOpcode(WorldPackets::Taxi::ActivateTaxi& activateTaxi) { - 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); -} - -void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) -{ - 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(activateTaxi.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.", activateTaxi.Vendor.ToString().c_str()); return; } - // at this point only 1 node is expected (final destination) - if (GetPlayer()->m_taxi.GetPath().size() != 1) + uint32 curloc = sObjectMgr->GetNearestTaxiNode(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetMapId(), GetPlayer()->GetTeam()); + if (!curloc) 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()); + TaxiNodesEntry const* from = sTaxiNodesStore.LookupEntry(curloc); + TaxiNodesEntry const* to = sTaxiNodesStore.LookupEntry(activateTaxi.Node); + if (!to) 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(activateTaxi.Node)) { SendActivateTaxiReply(ERR_TAXINOTVISITED); return; } } - GetPlayer()->ActivateTaxiPathTo(nodes, npc); + std::vector<uint32> nodes; + sTaxiPathGraph.GetCompleteNodeRoute(from, to, GetPlayer(), 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& /*taxiRequestEarlyLanding*/) +{ + GetPlayer()->m_taxi.RequestEarlyLanding(); +} diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index 86c4fb73108..4540aba77c5 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -131,7 +131,7 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl if (!mapChange) { TaxiPathNodeEntry const* node_i = path[i]; - if (i != path.size() - 1 && (node_i->Flags & 1 || node_i->MapID != path[i + 1]->MapID)) + if (i != path.size() - 1 && (node_i->Flags & TAXI_PATH_NODE_FLAG_TELEPORT || node_i->MapID != path[i + 1]->MapID)) { keyFrames.back().Teleport = true; mapChange = true; diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 5e032dbd71f..715d82877a0 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -63,7 +63,7 @@ struct KeyFrame uint32 NextArriveTime; bool IsTeleportFrame() const { return Teleport; } - bool IsStopFrame() const { return Node->Flags == 2; } + bool IsStopFrame() const { return (Node->Flags & TAXI_PATH_NODE_FLAG_STOP) != 0; } }; struct TransportTemplate 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/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index a0858b35c17..bf2148fc0b8 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -329,7 +329,7 @@ void FlightPathMovementGenerator::DoFinalize(Player* player) player->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_TAXI_BENCHMARK); } -#define PLAYER_FLIGHT_SPEED 32.0f +#define PLAYER_FLIGHT_SPEED 30.0f void FlightPathMovementGenerator::DoReset(Player* player) { diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index cd6f1334682..5b6b9803b4a 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -687,3 +687,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 011a74b07e0..66261564989 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..1dfa44d68a0 --- /dev/null +++ b/src/server/game/Server/Packets/TaxiPackets.cpp @@ -0,0 +1,74 @@ +/* +* 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); + } + + _worldPacket.append(Nodes->data(), Nodes->size()); + + 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.WriteBits(Reply, 4); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/TaxiPackets.h b/src/server/game/Server/Packets/TaxiPackets.h new file mode 100644 index 00000000000..0c916548bac --- /dev/null +++ b/src/server/game/Server/Packets/TaxiPackets.h @@ -0,0 +1,126 @@ +/* +* 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" +#include "DB2Structure.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; + TaxiMask const* Nodes = nullptr; + }; + + 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; + + uint8 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 f5f7e3c4abf..fbbfb8cef53 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_UNHANDLED, PROCESS_THREADSAFE, 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 b70d4da5596..79e50046d9a 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -400,6 +400,7 @@ namespace WorldPackets class MoveSetCollisionHeightAck; class MoveTimeSkipped; class SummonResponse; + class MoveSplineDone; } namespace NPC @@ -557,6 +558,16 @@ namespace WorldPackets class LearnTalents; } + namespace Taxi + { + class ShowTaxiNodes; + class TaxiNodeStatusQuery; + class EnableTaxiNode; + class TaxiQueryAvailableNodes; + class ActivateTaxi; + class TaxiRequestEarlyLanding; + } + namespace Ticket { class GMTicketGetSystemStatus; @@ -1228,12 +1239,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& enableTaxiNode); + void HandleTaxiNodeStatusQueryOpcode(WorldPackets::Taxi::TaxiNodeStatusQuery& taxiNodeStatusQuery); + void HandleTaxiQueryAvailableNodesOpcode(WorldPackets::Taxi::TaxiQueryAvailableNodes& taxiQueryAvailableNodes); + void HandleActivateTaxiOpcode(WorldPackets::Taxi::ActivateTaxi& activateTaxi); + void HandleMoveSplineDoneOpcode(WorldPackets::Movement::MoveSplineDone& moveSplineDone); void SendActivateTaxiReply(ActivateTaxiReply reply); + void HandleTaxiRequestEarlyLanding(WorldPackets::Taxi::TaxiRequestEarlyLanding& taxiRequestEarlyLanding); 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..3acc8fb47f9 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 + sTaxiPathGraph.Initialize(); + sSpellMgr->LoadPetFamilySpellsStore(); std::unordered_map<uint32, std::vector<uint32>> mapData; |