diff options
| author | ModoX <moardox@gmail.com> | 2024-01-05 17:56:19 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-05 17:56:19 +0100 |
| commit | 12186ef8573f60abeff4747da58767ee71092600 (patch) | |
| tree | 7d9a1da93e86fa3ccd84c02658bface3ef536721 /src/server/game/Movement | |
| parent | 390f0be9fb22766638006f43e4d0887108ba49e8 (diff) | |
Core/Waypoints: Refactor to split data into path and node related info in db (#29506)
Diffstat (limited to 'src/server/game/Movement')
6 files changed, 382 insertions, 154 deletions
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index a049481bee9..00ec6f25de0 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -1121,7 +1121,7 @@ void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional< Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath) { TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})", - _owner->GetGUID().ToString(), path.id, repeatable ? "YES" : "NO"); + _owner->GetGUID().ToString(), path.Id, repeatable ? "YES" : "NO"); Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT); } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index cde3f8f097b..bd5e6cbe996 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -105,15 +105,15 @@ void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer/* = 0*/) bool WaypointMovementGenerator<Creature>::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z) { // prevent a crash at empty waypoint path. - if (!_path || _path->nodes.empty()) + if (!_path || _path->Nodes.empty()) return false; - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::GetResetPosition: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes.at(_currentNode); + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::GetResetPosition: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); + WaypointNode const &waypoint = _path->Nodes.at(_currentNode); - x = waypoint.x; - y = waypoint.y; - z = waypoint.z; + x = waypoint.X; + y = waypoint.Y; + z = waypoint.Z; return true; } @@ -124,7 +124,7 @@ void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner) if (_loadedFromDB) { if (!_pathId) - _pathId = owner->GetWaypointPath(); + _pathId = owner->GetWaypointPathId(); _path = sWaypointMgr->GetPath(_pathId); } @@ -135,6 +135,11 @@ void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner) return; } + _followPathBackwardsFromEndToStart = _path->Flags.HasFlag(WaypointPathFlags::FollowPathBackwardsFromEndToStart); + + if (_path->Nodes.size() == 1) + _repeating = false; + owner->StopMoving(); _nextMoveTime.Reset(1000); @@ -155,7 +160,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff) if (!owner || !owner->IsAlive()) return true; - if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->nodes.empty()) + if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->Nodes.empty()) return true; if (_duration) @@ -261,25 +266,29 @@ void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool activ void WaypointMovementGenerator<Creature>::MovementInform(Creature* owner) { - if (owner->AI()) - owner->AI()->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); + WaypointNode const& waypoint = _path->Nodes.at(_currentNode); + if (CreatureAI* AI = owner->AI()) + { + AI->MovementInform(WAYPOINT_MOTION_TYPE, waypoint.Id); + AI->WaypointReached(waypoint.Id, _path->Id); + } } void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner) { - if (!_path || _path->nodes.empty()) + if (!_path || _path->Nodes.empty()) return; - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::OnArrived: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes.at(_currentNode); - if (waypoint.delay) + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::OnArrived: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); + WaypointNode const &waypoint = _path->Nodes.at(_currentNode); + if (waypoint.Delay) { owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); - _nextMoveTime.Reset(waypoint.delay); + _nextMoveTime.Reset(waypoint.Delay); } - if (_waitTimeRangeAtPathEnd && _followPathBackwardsFromEndToStart - && ((_isReturningToStart && _currentNode == 0) || (!_isReturningToStart && _currentNode == _path->nodes.size() - 1))) + if (_waitTimeRangeAtPathEnd && _followPathBackwardsFromEndToStart && *_followPathBackwardsFromEndToStart + && ((_isReturningToStart && _currentNode == 0) || (!_isReturningToStart && _currentNode == _path->Nodes.size() - 1))) { owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); Milliseconds waitTime = randtime(_waitTimeRangeAtPathEnd->first, _waitTimeRangeAtPathEnd->second); @@ -292,20 +301,15 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner) _nextMoveTime.Reset(waitTime); } - // inform AI - if (CreatureAI* AI = owner->AI()) - { - AI->MovementInform(WAYPOINT_MOTION_TYPE, _currentNode); - AI->WaypointReached(waypoint.id, _path->id); - } + MovementInform(owner); - owner->UpdateCurrentWaypointInfo(waypoint.id, _path->id); + owner->UpdateCurrentWaypointInfo(waypoint.Id, _path->Id); } void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaunch/* = false*/) { // sanity checks - if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || !_path || _path->nodes.empty() || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)))) + if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || !_path || _path->Nodes.empty() || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)))) return; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || (owner->IsFormationLeader() && !owner->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation @@ -320,18 +324,18 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun { if (ComputeNextNode()) { - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); // inform AI if (CreatureAI* AI = owner->AI()) - AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id); + AI->WaypointStarted(_path->Nodes[_currentNode].Id, _path->Id); } else { - WaypointNode const &waypoint = _path->nodes[_currentNode]; - float x = waypoint.x; - float y = waypoint.y; - float z = waypoint.z; + WaypointNode const& waypoint = _path->Nodes[_currentNode]; + float x = waypoint.X; + float y = waypoint.Y; + float z = waypoint.Z; float o = owner->GetOrientation(); if (!transportPath) @@ -352,7 +356,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun // inform AI if (CreatureAI* AI = owner->AI()) - AI->WaypointPathEnded(waypoint.id, _path->id); + AI->WaypointPathEnded(waypoint.Id, _path->Id); return; } } @@ -362,11 +366,11 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun // inform AI if (CreatureAI* AI = owner->AI()) - AI->WaypointStarted(_path->nodes[_currentNode].id, _path->id); + AI->WaypointStarted(_path->Nodes[_currentNode].Id, _path->Id); } - ASSERT(_currentNode < _path->nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->id); - WaypointNode const &waypoint = _path->nodes[_currentNode]; + ASSERT(_currentNode < _path->Nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, _path->Id); + WaypointNode const &waypoint = _path->Nodes[_currentNode]; RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED); @@ -380,28 +384,29 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call //! but formationDest contains global coordinates - init.MoveTo(waypoint.x, waypoint.y, waypoint.z, _generatePath); + init.MoveTo(waypoint.X, waypoint.Y, waypoint.Z, _generatePath); - if (waypoint.orientation.has_value() && (waypoint.delay > 0 || _currentNode == _path->nodes.size() - 1)) - init.SetFacing(*waypoint.orientation); + if (waypoint.Orientation.has_value() && (waypoint.Delay > 0 || _currentNode == _path->Nodes.size() - 1)) + init.SetFacing(*waypoint.Orientation); - switch (waypoint.moveType) + switch (_path->MoveType) { - case WAYPOINT_MOVE_TYPE_LAND: + case WaypointMoveType::Land: init.SetAnimation(AnimTier::Ground); break; - case WAYPOINT_MOVE_TYPE_TAKEOFF: + case WaypointMoveType::TakeOff: init.SetAnimation(AnimTier::Hover); break; - case WAYPOINT_MOVE_TYPE_RUN: + case WaypointMoveType::Run: init.SetWalk(false); break; - case WAYPOINT_MOVE_TYPE_WALK: + case WaypointMoveType::Walk: init.SetWalk(true); break; default: break; } + switch (_speedSelectionMode) // overrides move type from each waypoint if set { case MovementWalkRunSpeedSelectionMode::Default: @@ -427,18 +432,18 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun bool WaypointMovementGenerator<Creature>::ComputeNextNode() { - if ((_currentNode == _path->nodes.size() - 1) && !_repeating) + if ((_currentNode == _path->Nodes.size() - 1) && !_repeating) return false; - if (!_followPathBackwardsFromEndToStart || _path->nodes.size() < 2) - _currentNode = (_currentNode + 1) % _path->nodes.size(); + if (!_followPathBackwardsFromEndToStart.value_or(false) || _path->Nodes.size() < WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES) + _currentNode = (_currentNode + 1) % _path->Nodes.size(); else { if (!_isReturningToStart) { - if (++_currentNode >= _path->nodes.size()) + if (++_currentNode >= _path->Nodes.size()) { - _currentNode -= 2; + _currentNode -= WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES; _isReturningToStart = true; } } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 3764a9629f0..6474e9df85e 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -85,7 +85,7 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat MovementWalkRunSpeedSelectionMode _speedSelectionMode; Optional<std::pair<Milliseconds, Milliseconds>> _waitTimeRangeAtPathEnd; Optional<float> _wanderDistanceAtPathEnds; - bool _followPathBackwardsFromEndToStart; + Optional<bool> _followPathBackwardsFromEndToStart; bool _isReturningToStart; bool _generatePath; }; diff --git a/src/server/game/Movement/Waypoints/WaypointDefines.h b/src/server/game/Movement/Waypoints/WaypointDefines.h index 119219dd3d4..d801531b316 100644 --- a/src/server/game/Movement/Waypoints/WaypointDefines.h +++ b/src/server/game/Movement/Waypoints/WaypointDefines.h @@ -19,51 +19,68 @@ #define TRINITY_WAYPOINTDEFINES_H #include "Define.h" +#include "EnumFlag.h" #include "Optional.h" #include <vector> -enum WaypointMoveType +#define WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES 2 + +enum class WaypointMoveType : uint8 { - WAYPOINT_MOVE_TYPE_WALK, - WAYPOINT_MOVE_TYPE_RUN, - WAYPOINT_MOVE_TYPE_LAND, - WAYPOINT_MOVE_TYPE_TAKEOFF, + Walk = 0, + Run = 1, + Land = 2, + TakeOff = 3, - WAYPOINT_MOVE_TYPE_MAX + Max }; +enum class WaypointPathFlags : uint8 +{ + None = 0x00, + FollowPathBackwardsFromEndToStart = 0x01, +}; + +DEFINE_ENUM_FLAG(WaypointPathFlags); + struct WaypointNode { - WaypointNode() : id(0), x(0.f), y(0.f), z(0.f), delay(0), moveType(WAYPOINT_MOVE_TYPE_RUN) { } - WaypointNode(uint32 _id, float _x, float _y, float _z, Optional<float> _orientation = { }, uint32 _delay = 0) + WaypointNode() : Id(0), X(0.f), Y(0.f), Z(0.f), Delay(0), MoveType(WaypointMoveType::Walk) { } + WaypointNode(uint32 id, float x, float y, float z, Optional<float> orientation = { }, uint32 delay = 0) { - id = _id; - x = _x; - y = _y; - z = _z; - orientation = _orientation; - delay = _delay; - moveType = WAYPOINT_MOVE_TYPE_WALK; + Id = id; + X = x; + Y = y; + Z = z; + Orientation = orientation; + Delay = delay; + MoveType = WaypointMoveType::Walk; } - uint32 id; - float x, y, z; - Optional<float> orientation; - uint32 delay; - uint32 moveType; + uint32 Id; + float X; + float Y; + float Z; + Optional<float> Orientation; + uint32 Delay; + WaypointMoveType MoveType; }; struct WaypointPath { - WaypointPath() : id(0) { } - WaypointPath(uint32 _id, std::vector<WaypointNode>&& _nodes) + WaypointPath() : Id(0), MoveType(WaypointMoveType::Walk), Flags(WaypointPathFlags::None) { } + WaypointPath(uint32 id, std::vector<WaypointNode>&& nodes, WaypointMoveType moveType = WaypointMoveType::Walk, WaypointPathFlags flags = WaypointPathFlags::None) { - id = _id; - nodes = _nodes; + Id = id; + Nodes = nodes; + Flags = flags; + MoveType = moveType; } - std::vector<WaypointNode> nodes; - uint32 id; + std::vector<WaypointNode> Nodes; + uint32 Id; + WaypointMoveType MoveType; + EnumFlag<WaypointPathFlags> Flags = WaypointPathFlags::None; }; #endif diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp index ab018e66233..cb282e6ec30 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.cpp +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -19,17 +19,31 @@ #include "DatabaseEnv.h" #include "GridDefines.h" #include "Log.h" +#include "MapUtils.h" +#include "ObjectAccessor.h" +#include "Optional.h" +#include "TemporarySummon.h" +#include "Unit.h" -void WaypointMgr::Load() +void WaypointMgr::LoadPaths() +{ + _LoadPaths(); + _LoadPathNodes(); + DoPostLoadingChecks(); +} + +void WaypointMgr::_LoadPaths() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 - QueryResult result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, orientation, move_type, delay FROM waypoint_data ORDER BY id, point"); + _pathStore.clear(); + + // 0 1 2 + QueryResult result = WorldDatabase.Query("SELECT PathId, MoveType, Flags FROM waypoint_path"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 waypoints. DB table `waypoint_data` is empty!"); + TC_LOG_INFO("server.loading", ">> Loaded 0 waypoint paths. DB table `waypoint_path` is empty!"); return; } @@ -37,42 +51,92 @@ void WaypointMgr::Load() do { - Field* fields = result->Fetch(); - uint32 pathId = fields[0].GetUInt32(); - float x = fields[2].GetFloat(); - float y = fields[3].GetFloat(); - float z = fields[4].GetFloat(); - Optional<float> o; - if (!fields[5].IsNull()) - o = fields[5].GetFloat(); - - Trinity::NormalizeMapCoord(x); - Trinity::NormalizeMapCoord(y); - - WaypointNode waypoint; - waypoint.id = fields[1].GetUInt32(); - waypoint.x = x; - waypoint.y = y; - waypoint.z = z; - waypoint.orientation = o; - waypoint.moveType = fields[6].GetUInt32(); - - if (waypoint.moveType >= WAYPOINT_MOVE_TYPE_MAX) - { - TC_LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", waypoint.id); - continue; - } + LoadPathFromDB(result->Fetch()); + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded {} waypoint paths in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void WaypointMgr::_LoadPathNodes() +{ + uint32 oldMSTime = getMSTime(); + // 0 1 2 3 4 5 6 + QueryResult result = WorldDatabase.Query("SELECT PathId, NodeId, PositionX, PositionY, PositionZ, Orientation, Delay FROM waypoint_path_node ORDER BY PathId, NodeId"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 waypoint path nodes. DB table `waypoint_path_node` is empty!"); + return; + } - waypoint.delay = fields[7].GetUInt32(); + uint32 count = 0; - WaypointPath& path = _waypointStore[pathId]; - path.id = pathId; - path.nodes.push_back(std::move(waypoint)); + do + { + LoadPathNodesFromDB(result->Fetch()); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded {} waypoints in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded {} waypoint path nodes in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + DoPostLoadingChecks(); +} + +void WaypointMgr::LoadPathFromDB(Field* fields) +{ + uint32 pathId = fields[0].GetUInt32(); + + WaypointPath& path = _pathStore[pathId]; + path.Id = pathId; + path.MoveType = (WaypointMoveType)fields[1].GetUInt8(); + + if (path.MoveType >= WaypointMoveType::Max) + { + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has invalid MoveType {}, ignoring", pathId, AsUnderlyingType(path.MoveType)); + return; + } + path.Flags = (WaypointPathFlags)fields[2].GetUInt8(); + path.Nodes.clear(); +} + +void WaypointMgr::LoadPathNodesFromDB(Field* fields) +{ + uint32 pathId = fields[0].GetUInt32(); + + if (_pathStore.find(pathId) == _pathStore.end()) + { + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path_node` does not exist in `waypoint_path`, ignoring", pathId); + return; + } + + float x = fields[2].GetFloat(); + float y = fields[3].GetFloat(); + float z = fields[4].GetFloat(); + Optional<float> o; + if (!fields[5].IsNull()) + o = fields[5].GetFloat(); + + Trinity::NormalizeMapCoord(x); + Trinity::NormalizeMapCoord(y); + + WaypointNode waypoint(fields[1].GetUInt32(), x, y, z, o, fields[6].GetUInt32()); + + WaypointPath& path = _pathStore[pathId]; + path.Nodes.push_back(std::move(waypoint)); +} + +void WaypointMgr::DoPostLoadingChecks() +{ + for (auto const& path : _pathStore) + { + WaypointPath pathInfo = path.second; + if (pathInfo.Nodes.empty()) + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has no assigned nodes in `waypoint_path_node`", pathInfo.Id); + + if (pathInfo.Flags.HasFlag(WaypointPathFlags::FollowPathBackwardsFromEndToStart) && pathInfo.Nodes.size() < WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES) + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has FollowPathBackwardsFromEndToStart set, but only {} nodes, requires {}", pathInfo.Id, pathInfo.Nodes.size(), WAYPOINT_PATH_FLAG_FOLLOW_PATH_BACKWARDS_MINIMUM_NODES); + } } WaypointMgr* WaypointMgr::instance() @@ -81,61 +145,177 @@ WaypointMgr* WaypointMgr::instance() return &instance; } -void WaypointMgr::ReloadPath(uint32 id) +void WaypointMgr::ReloadPath(uint32 pathId) { - WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID); + // waypoint_path + { + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_PATH_BY_PATHID); + stmt->setUInt32(0, pathId); - stmt->setUInt32(0, id); + PreparedQueryResult result = WorldDatabase.Query(stmt); - PreparedQueryResult result = WorldDatabase.Query(stmt); + if (!result) + { + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` not found, ignoring", pathId); + return; + } - if (!result) - return; + do + { + LoadPathFromDB(result->Fetch()); + } while (result->NextRow()); + } - std::vector<WaypointNode> values; - do + // waypoint_path_data { - Field* fields = result->Fetch(); - float x = fields[1].GetFloat(); - float y = fields[2].GetFloat(); - float z = fields[3].GetFloat(); - Optional<float> o; - if (!fields[4].IsNull()) - o = fields[4].GetFloat(); - - Trinity::NormalizeMapCoord(x); - Trinity::NormalizeMapCoord(y); - - WaypointNode waypoint; - waypoint.id = fields[0].GetUInt32(); - waypoint.x = x; - waypoint.y = y; - waypoint.z = z; - waypoint.orientation = o; - waypoint.moveType = fields[5].GetUInt32(); - - if (waypoint.moveType >= WAYPOINT_MOVE_TYPE_MAX) + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_PATH_NODE_BY_PATHID); + stmt->setUInt32(0, pathId); + + PreparedQueryResult result = WorldDatabase.Query(stmt); + + if (!result) { - TC_LOG_ERROR("sql.sql", "Waypoint {} in waypoint_data has invalid move_type, ignoring", waypoint.id); + TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path_node` not found, ignoring", pathId); + return; + } + + do + { + LoadPathNodesFromDB(result->Fetch()); + } while (result->NextRow()); + } +} + +void WaypointMgr::VisualizePath(Unit* owner, WaypointPath const* path, Optional<uint32> displayId) +{ + for (WaypointNode const& node : path->Nodes) + { + std::pair<uint32, uint32> pathNodePair(path->Id, node.Id); + + auto itr = _nodeToVisualWaypointGUIDsMap.find(pathNodePair); + if (itr != _nodeToVisualWaypointGUIDsMap.end()) + continue; + + TempSummon* summon = owner->SummonCreature(VISUAL_WAYPOINT, node.X, node.Y, node.Z, node.Orientation ? *node.Orientation : 0.0f); + if (!summon) continue; + + if (displayId) + { + summon->SetDisplayId(*displayId, true); + summon->SetObjectScale(0.5f); } - waypoint.delay = fields[6].GetUInt32(); + _nodeToVisualWaypointGUIDsMap[pathNodePair] = summon->GetGUID(); + _visualWaypointGUIDToNodeMap[summon->GetGUID()] = std::pair<WaypointPath const*, WaypointNode const*>(path, &node); + } +} + +void WaypointMgr::DevisualizePath(Unit* owner, WaypointPath const* path) +{ + for (WaypointNode const& node : path->Nodes) + { + std::pair<uint32, uint32> pathNodePair(path->Id, node.Id); + auto itr = _nodeToVisualWaypointGUIDsMap.find(pathNodePair); + if (itr == _nodeToVisualWaypointGUIDsMap.end()) + continue; + + Creature* creature = ObjectAccessor::GetCreature(*owner, itr->second); + if (!creature) + continue; + + _visualWaypointGUIDToNodeMap.erase(itr->second); + _nodeToVisualWaypointGUIDsMap.erase(pathNodePair); - values.push_back(std::move(waypoint)); + creature->DespawnOrUnsummon(); } - while (result->NextRow()); +} + +void WaypointMgr::MoveNode(WaypointPath const* path, WaypointNode const* node, Position const& pos) +{ + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_PATH_NODE_POSITION); + stmt->setFloat(0, pos.GetPositionX()); + stmt->setFloat(1, pos.GetPositionY()); + stmt->setFloat(2, pos.GetPositionZ()); + stmt->setFloat(3, pos.GetOrientation()); + stmt->setUInt32(4, path->Id); + stmt->setUInt32(5, node->Id); + WorldDatabase.Execute(stmt); +} + +void WaypointMgr::DeleteNode(WaypointPath const* path, WaypointNode const* node) +{ + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_WAYPOINT_PATH_NODE); + stmt->setUInt32(0, path->Id); + stmt->setUInt32(1, node->Id); + WorldDatabase.Execute(stmt); + + stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_PATH_NODE); + stmt->setUInt32(0, path->Id); + stmt->setUInt32(1, node->Id); + WorldDatabase.Execute(stmt); +} + +void WaypointMgr::DeleteNode(uint32 pathId, uint32 nodeId) +{ + WaypointPath const* path = GetPath(pathId); + if (!path) + return; + + WaypointNode const* node = GetNode(path, nodeId); + if (!node) + return; - WaypointPath& path = _waypointStore[id]; - path.id = id; - path.nodes = std::move(values); + DeleteNode(path, node); } -WaypointPath const* WaypointMgr::GetPath(uint32 id) const +WaypointPath const* WaypointMgr::GetPath(uint32 pathId) const { - auto itr = _waypointStore.find(id); - if (itr != _waypointStore.end()) - return &itr->second; + return Trinity::Containers::MapGetValuePtr(_pathStore, pathId); +} +WaypointNode const* WaypointMgr::GetNode(WaypointPath const* path, uint32 nodeId) const +{ + for (WaypointNode const& node : path->Nodes) + { + if (node.Id == nodeId) + return &node; + } return nullptr; } + +WaypointNode const* WaypointMgr::GetNode(uint32 pathId, uint32 nodeId) const +{ + WaypointPath const* path = GetPath(pathId); + if (!path) + return nullptr; + + return GetNode(path->Id, nodeId); +} + +WaypointPath const* WaypointMgr::GetPathByVisualGUID(ObjectGuid guid) const +{ + auto itr = _visualWaypointGUIDToNodeMap.find(guid); + if (itr == _visualWaypointGUIDToNodeMap.end()) + return nullptr; + + return itr->second.first; +} + +WaypointNode const* WaypointMgr::GetNodeByVisualGUID(ObjectGuid guid) const +{ + auto itr = _visualWaypointGUIDToNodeMap.find(guid); + if (itr == _visualWaypointGUIDToNodeMap.end()) + return nullptr; + + return itr->second.second; +} + +ObjectGuid const& WaypointMgr::GetVisualGUIDByNode(uint32 pathId, uint32 nodeId) const +{ + auto itr = _nodeToVisualWaypointGUIDsMap.find(std::make_pair(pathId, nodeId)); + if (itr == _nodeToVisualWaypointGUIDsMap.end()) + return ObjectGuid::Empty; + + return itr->second; +} diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h index 906c6981e28..721f79d76a6 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.h +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -19,27 +19,53 @@ #define TRINITY_WAYPOINTMANAGER_H #include "Define.h" +#include "Field.h" +#include "Hash.h" +#include "ObjectGuid.h" +#include "Position.h" #include "WaypointDefines.h" #include <unordered_map> +class Unit; + class TC_GAME_API WaypointMgr { public: static WaypointMgr* instance(); // Attempts to reload a single path from database - void ReloadPath(uint32 id); + void ReloadPath(uint32 pathId); // Loads all paths from database, should only run on startup - void Load(); + void LoadPaths(); + void LoadPathFromDB(Field* fields); + void LoadPathNodesFromDB(Field* fields); + void DoPostLoadingChecks(); + + void VisualizePath(Unit* owner, WaypointPath const* path, Optional<uint32> displayId); + void DevisualizePath(Unit* owner, WaypointPath const* path); + + void MoveNode(WaypointPath const* path, WaypointNode const* node, Position const& pos); + void DeleteNode(WaypointPath const* path, WaypointNode const* node); + void DeleteNode(uint32 pathId, uint32 nodeId); - // Returns the path from a given id - WaypointPath const* GetPath(uint32 id) const; + WaypointPath const* GetPath(uint32 pathId) const; + WaypointNode const* GetNode(WaypointPath const* path, uint32 nodeId) const; + WaypointNode const* GetNode(uint32 pathId, uint32 nodeId) const; + WaypointPath const* GetPathByVisualGUID(ObjectGuid guid) const; + WaypointNode const* GetNodeByVisualGUID(ObjectGuid guid) const; + ObjectGuid const& GetVisualGUIDByNode(uint32 pathId, uint32 nodeId) const; private: WaypointMgr() { } - std::unordered_map<uint32, WaypointPath> _waypointStore; + void _LoadPaths(); + void _LoadPathNodes(); + + std::unordered_map<uint32 /*pathId*/, WaypointPath> _pathStore; + + std::unordered_map<std::pair<uint32 /*pathId*/, uint32 /*nodeId*/>, ObjectGuid> _nodeToVisualWaypointGUIDsMap; + std::unordered_map<ObjectGuid, std::pair<WaypointPath const*, WaypointNode const*>> _visualWaypointGUIDToNodeMap; }; #define sWaypointMgr WaypointMgr::instance() |
