aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-04-20 00:22:34 +0200
committerShauren <shauren.trinity@gmail.com>2024-04-20 00:22:34 +0200
commit204f65684c2a027baa7a3c2d647f0e735a368c62 (patch)
tree0162aa60518576af4477963a83a8b5e8b7f757a5 /src
parentcf4c3b5467fde04f53636443a7a8b392aa527cf5 (diff)
Core/Movement: Merge waypoints without delay into a single movement packet
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp110
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h1
-rw-r--r--src/server/game/Movement/Waypoints/WaypointDefines.h3
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.cpp21
4 files changed, 129 insertions, 6 deletions
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index c8545090156..fa87733d6f9 100644
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -24,8 +24,10 @@
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "MovementDefines.h"
+#include "PathGenerator.h"
#include "Transport.h"
#include "WaypointManager.h"
+#include <span>
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
@@ -61,6 +63,8 @@ WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath cons
ScriptResult = std::move(scriptResult);
if (duration)
_duration.emplace(*duration);
+
+ std::get<std::unique_ptr<WaypointPath>>(_path)->BuildSegments();
}
WaypointMovementGenerator<Creature>::~WaypointMovementGenerator() = default;
@@ -215,6 +219,16 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
if (owner->GetTransGUID().IsEmpty())
owner->SetHomePosition(owner->GetPosition());
+ // handle switching points in continuous segments
+ if (_waypointTransitionSplinePoints.size() > 1 && owner->movespline->currentPathIdx() >= _waypointTransitionSplinePoints.front())
+ {
+ OnArrived(owner);
+ _waypointTransitionSplinePoints.erase(_waypointTransitionSplinePoints.begin());
+ if (ComputeNextNode())
+ if (CreatureAI* ai = owner->AI())
+ ai->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
+ }
+
// relaunch movement if its speed has changed
if (HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING))
StartMove(owner, true);
@@ -336,6 +350,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
bool const transportPath = !owner->GetTransGUID().IsEmpty();
+ uint32 previousNode = _currentNode;
if (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) && HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))
{
if (ComputeNextNode())
@@ -388,7 +403,69 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
}
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];
+
+ std::span<WaypointNode const> segment = [&]
+ {
+ // find the continuous segment that our destination waypoint is on
+ auto segmentItr = std::ranges::find_if(path->ContinuousSegments, [&](std::pair<std::size_t, std::size_t> segmentRange)
+ {
+ auto isInSegmentRange = [&](uint32 node) { return node >= segmentRange.first && node < segmentRange.first + segmentRange.second; };
+ return isInSegmentRange(_currentNode) && isInSegmentRange(previousNode);
+ });
+
+ // handle path returning directly from last point to first
+ if (segmentItr == path->ContinuousSegments.end())
+ {
+ if (_currentNode != 0 || previousNode != path->Nodes.size() - 1)
+ return std::span(&path->Nodes[_currentNode], 1);
+
+ segmentItr = path->ContinuousSegments.begin();
+ }
+
+ if (!_isReturningToStart)
+ return std::span(&path->Nodes[_currentNode], segmentItr->second - (_currentNode - segmentItr->first));
+
+ return std::span(&path->Nodes[segmentItr->first], _currentNode - segmentItr->first + 1);
+ }();
+
+ WaypointNode const& lastWaypointForSegment = !_isReturningToStart ? segment.back() : segment.front();
+
+ _waypointTransitionSplinePoints.clear();
+ Movement::PointsArray points;
+ auto fillPath = [this, owner, &points]<typename iterator>(iterator itr, iterator end)
+ {
+ Optional<PathGenerator> generator;
+ if (_generatePath)
+ generator.emplace(owner);
+
+ Position source = owner->GetPosition();
+ points.emplace_back(source.GetPositionX(), source.GetPositionY(), source.GetPositionZ());
+
+ while (itr != end)
+ {
+ if (generator)
+ {
+ bool result = generator->CalculatePath(source.GetPositionX(), source.GetPositionY(), source.GetPositionZ(), itr->X, itr->Y, itr->Z);
+ if (result && !(generator->GetPathType() & PATHFIND_NOPATH))
+ points.insert(points.end(), generator->GetPath().begin() + 1, generator->GetPath().end());
+ else
+ generator.reset(); // when path generation to a waypoint fails, add all remaining points without pathfinding (preserve legacy behavior of MoveSplineInit::MoveTo)
+ }
+
+ if (!generator)
+ points.emplace_back(itr->X, itr->Y, itr->Z);
+
+ _waypointTransitionSplinePoints.push_back(points.size() - 1);
+
+ source.Relocate(itr->X, itr->Y, itr->Z);
+ ++itr;
+ }
+ };
+
+ if (!_isReturningToStart)
+ fillPath(segment.begin(), segment.end());
+ else
+ fillPath(segment.rbegin(), segment.rend());
RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
@@ -396,22 +473,28 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
Movement::MoveSplineInit init(owner);
+ // because steering flag can cause position on client to not be perfectly accurate, dont do it in combat
+ if (!owner->IsInCombat())
+ init.SetSteering();
+
//! If creature is on transport, we assume waypoints set in DB are already transport offsets
if (transportPath)
init.DisableTransportPathTransformations();
- init.MoveTo(waypoint.X, waypoint.Y, waypoint.Z, _generatePath);
+ init.MovebyPath(points);
- if (waypoint.Orientation.has_value() && (waypoint.Delay || _currentNode == path->Nodes.size() - 1))
- init.SetFacing(*waypoint.Orientation);
+ if (lastWaypointForSegment.Orientation.has_value() && (lastWaypointForSegment.Delay || _currentNode == path->Nodes.size() - 1))
+ init.SetFacing(*lastWaypointForSegment.Orientation);
switch (path->MoveType)
{
case WaypointMoveType::Land:
init.SetAnimation(AnimTier::Ground);
+ init.SetFly();
break;
case WaypointMoveType::TakeOff:
init.SetAnimation(AnimTier::Fly);
+ init.SetFly();
break;
case WaypointMoveType::Run:
init.SetWalk(false);
@@ -443,6 +526,25 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
if (_speed)
init.SetVelocity(*_speed);
+ if (init.Path().size() > 2)
+ {
+ G3D::Vector3 mid = (init.Path().front() + init.Path().back()) / 2.0f;
+ auto itr = init.Path().begin() + 1;
+ auto end = itr + (init.Path().size() - 2);
+ while (itr != end)
+ {
+ G3D::Vector3 offset = *itr - mid;
+ if (std::fabs(offset.x) >= 128.0f || std::fabs(offset.y) >= 128.0f || std::fabs(offset.z) >= 64.0f)
+ {
+ // when distance is too great, send path in uncompressed state otherwise too much precision is lost on each point
+ init.SetUncompressed();
+ break;
+ }
+
+ ++itr;
+ }
+ }
+
init.Launch();
// inform formation
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
index f6f3380cbe2..29b1b48354a 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
@@ -84,6 +84,7 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat
bool IsLoadedFromDB() const { return std::holds_alternative<WaypointPath const*>(_path); }
+ std::vector<int32> _waypointTransitionSplinePoints;
TimeTracker _nextMoveTime;
uint32 _pathId;
bool _repeating;
diff --git a/src/server/game/Movement/Waypoints/WaypointDefines.h b/src/server/game/Movement/Waypoints/WaypointDefines.h
index 2d897c0eb09..cf5c85a1161 100644
--- a/src/server/game/Movement/Waypoints/WaypointDefines.h
+++ b/src/server/game/Movement/Waypoints/WaypointDefines.h
@@ -79,10 +79,13 @@ struct WaypointPath
}
std::vector<WaypointNode> Nodes;
+ std::vector<std::pair<std::size_t, std::size_t>> ContinuousSegments;
uint32 Id = 0;
WaypointMoveType MoveType = WaypointMoveType::Walk;
EnumFlag<WaypointPathFlags> Flags = WaypointPathFlags::None;
Optional<float> Velocity;
+
+ void BuildSegments();
};
#endif
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp
index 40106ecb2e4..ffb984fb4af 100644
--- a/src/server/game/Movement/Waypoints/WaypointManager.cpp
+++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp
@@ -139,9 +139,10 @@ void WaypointMgr::LoadPathNodesFromDB(Field* fields)
void WaypointMgr::DoPostLoadingChecks()
{
- for (auto const& path : _pathStore)
+ for (auto& [pathId, pathInfo] : _pathStore)
{
- WaypointPath pathInfo = path.second;
+ pathInfo.BuildSegments();
+
if (pathInfo.Nodes.empty())
TC_LOG_ERROR("sql.sql", "PathId {} in `waypoint_path` has no assigned nodes in `waypoint_path_node`", pathInfo.Id);
@@ -194,6 +195,9 @@ void WaypointMgr::ReloadPath(uint32 pathId)
{
LoadPathNodesFromDB(result->Fetch());
} while (result->NextRow());
+
+ if (WaypointPath* path = Trinity::Containers::MapGetValuePtr(_pathStore, pathId))
+ path->BuildSegments();
}
}
@@ -330,3 +334,16 @@ ObjectGuid const& WaypointMgr::GetVisualGUIDByNode(uint32 pathId, uint32 nodeId)
return itr->second;
}
+
+void WaypointPath::BuildSegments()
+{
+ ContinuousSegments.assign(1, { 0, 0 });
+ for (std::size_t i = 0; i < Nodes.size(); ++i)
+ {
+ ++ContinuousSegments.back().second;
+
+ // split on delay
+ if (i + 1 != Nodes.size() && Nodes[i].Delay)
+ ContinuousSegments.emplace_back(i, 1);
+ }
+}