aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Movement
diff options
context:
space:
mode:
authorModoX <moardox@gmail.com>2024-01-05 17:56:19 +0100
committerGitHub <noreply@github.com>2024-01-05 17:56:19 +0100
commit12186ef8573f60abeff4747da58767ee71092600 (patch)
tree7d9a1da93e86fa3ccd84c02658bface3ef536721 /src/server/game/Movement
parent390f0be9fb22766638006f43e4d0887108ba49e8 (diff)
Core/Waypoints: Refactor to split data into path and node related info in db (#29506)
Diffstat (limited to 'src/server/game/Movement')
-rw-r--r--src/server/game/Movement/MotionMaster.cpp2
-rw-r--r--src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp101
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h2
-rw-r--r--src/server/game/Movement/Waypoints/WaypointDefines.h69
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.cpp326
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.h36
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()