mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Movement: Implemented cyclic waypoint movement (#29923)
Co-authored-by: Shauren <shauren.trinity@gmail.com>
This commit is contained in:
@@ -41,7 +41,7 @@ WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bo
|
||||
: PathMovementBase(PathType(std::in_place_type<WaypointPath const*>)), _pathId(pathId), _speed(speed), _speedSelectionMode(speedSelectionMode),
|
||||
_waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)), _wanderDistanceAtPathEnds(wanderDistanceAtPathEnds),
|
||||
_followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _exactSplinePath(exactSplinePath), _repeating(repeating), _generatePath(generatePath),
|
||||
_moveTimer(0), _nextMoveTime(0), _isReturningToStart(false)
|
||||
_moveTimer(0), _nextMoveTime(0), _waypointTransitionSplinePointsIndex(0), _isReturningToStart(false)
|
||||
{
|
||||
Mode = MOTION_MODE_DEFAULT;
|
||||
Priority = MOTION_PRIORITY_NORMAL;
|
||||
@@ -59,7 +59,7 @@ WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath cons
|
||||
: PathMovementBase(std::make_unique<WaypointPath>(path)), _pathId(0), _speed(speed), _speedSelectionMode(speedSelectionMode),
|
||||
_waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)), _wanderDistanceAtPathEnds(wanderDistanceAtPathEnds),
|
||||
_followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _exactSplinePath(exactSplinePath), _repeating(repeating), _generatePath(generatePath),
|
||||
_moveTimer(0), _nextMoveTime(0), _isReturningToStart(false)
|
||||
_moveTimer(0), _nextMoveTime(0), _waypointTransitionSplinePointsIndex(0), _isReturningToStart(false)
|
||||
{
|
||||
Mode = MOTION_MODE_DEFAULT;
|
||||
Priority = MOTION_PRIORITY_NORMAL;
|
||||
@@ -218,7 +218,7 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
|
||||
}
|
||||
|
||||
// if it's moving
|
||||
if (!UpdateMoveTimer(diff))
|
||||
if (!UpdateMoveTimer(diff) && !owner->movespline->Finalized())
|
||||
{
|
||||
// set home position at place (every MotionMaster::UpdateMotion)
|
||||
if (owner->GetTransGUID().IsEmpty())
|
||||
@@ -227,10 +227,11 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
|
||||
// handle switching points in continuous segments
|
||||
if (IsExactSplinePath())
|
||||
{
|
||||
if (_waypointTransitionSplinePoints.size() > 1 && owner->movespline->currentPathIdx() >= _waypointTransitionSplinePoints.front())
|
||||
if (_waypointTransitionSplinePointsIndex < _waypointTransitionSplinePoints.size()
|
||||
&& owner->movespline->currentPathIdx() >= _waypointTransitionSplinePoints[_waypointTransitionSplinePointsIndex])
|
||||
{
|
||||
OnArrived(owner);
|
||||
_waypointTransitionSplinePoints.erase(_waypointTransitionSplinePoints.begin());
|
||||
++_waypointTransitionSplinePointsIndex;
|
||||
if (ComputeNextNode())
|
||||
if (CreatureAI* ai = owner->AI())
|
||||
ai->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
|
||||
@@ -363,13 +364,14 @@ void CreateSingularPointPath(Unit const* owner, WaypointPath const* path, uint32
|
||||
waypointTransitionSplinePoints->push_back(points->size() - 1);
|
||||
}
|
||||
|
||||
void CreateMergedPath(Unit const* owner, WaypointPath const* path, uint32 previousNode, uint32 currentNode, bool isReturningToStart, bool generatePath,
|
||||
void CreateMergedPath(Unit const* owner, WaypointPath const* path, uint32 previousNode, uint32 currentNode,
|
||||
bool isReturningToStart, bool generatePath, bool isCyclic,
|
||||
Movement::PointsArray* points, std::vector<int32>* waypointTransitionSplinePoints, WaypointNode const** lastWaypointOnPath)
|
||||
{
|
||||
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 segmentItr = std::ranges::find_if(path->ContinuousSegments, [&](std::pair<std::size_t, std::size_t> const& segmentRange)
|
||||
{
|
||||
auto isInSegmentRange = [&](uint32 node) { return node >= segmentRange.first && node < segmentRange.first + segmentRange.second; };
|
||||
return isInSegmentRange(currentNode) && isInSegmentRange(previousNode);
|
||||
@@ -423,6 +425,15 @@ void CreateMergedPath(Unit const* owner, WaypointPath const* path, uint32 previo
|
||||
}
|
||||
};
|
||||
|
||||
if (isCyclic)
|
||||
{
|
||||
// create new cyclic path starting at current node
|
||||
std::vector<WaypointNode> cyclicPath = path->Nodes;
|
||||
std::rotate(cyclicPath.begin(), cyclicPath.begin() + currentNode, cyclicPath.end());
|
||||
fillPath(cyclicPath.begin(), cyclicPath.end());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isReturningToStart)
|
||||
fillPath(segment.begin(), segment.end());
|
||||
else
|
||||
@@ -503,18 +514,35 @@ 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* lastWaypointForSegment = &path->Nodes[_currentNode];
|
||||
|
||||
bool isCyclic = IsCyclic();
|
||||
Movement::PointsArray points;
|
||||
|
||||
if (IsExactSplinePath())
|
||||
CreateMergedPath(owner, path, previousNode, _currentNode, _isReturningToStart, false,
|
||||
CreateMergedPath(owner, path, previousNode, _currentNode, _isReturningToStart, false, isCyclic,
|
||||
&points, &_waypointTransitionSplinePoints, &lastWaypointForSegment);
|
||||
else
|
||||
CreateSingularPointPath(owner, path, _currentNode, _generatePath, &points, &_waypointTransitionSplinePoints);
|
||||
|
||||
_waypointTransitionSplinePointsIndex = 0;
|
||||
|
||||
RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
|
||||
|
||||
owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
|
||||
if (isCyclic)
|
||||
{
|
||||
bool isFirstCycle = relaunch || owner->movespline->Finalized() || !owner->movespline->isCyclic();
|
||||
if (!isFirstCycle)
|
||||
{
|
||||
for (int32& point : _waypointTransitionSplinePoints)
|
||||
--point;
|
||||
|
||||
// cyclic paths are using identical duration to first cycle with EnterCycle
|
||||
_moveTimer.Reset(Milliseconds(owner->movespline->Duration()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Movement::MoveSplineInit init(owner);
|
||||
|
||||
//! If creature is on transport, we assume waypoints set in DB are already transport offsets
|
||||
@@ -567,7 +595,10 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
|
||||
if (_speed)
|
||||
init.SetVelocity(*_speed);
|
||||
|
||||
if (IsExactSplinePath() && points.size() > 2 && owner->CanFly())
|
||||
if (isCyclic)
|
||||
init.SetCyclic();
|
||||
|
||||
if (IsExactSplinePath() && (points.size() > 2 && owner->CanFly()))
|
||||
init.SetSmooth();
|
||||
|
||||
Milliseconds duration(init.Launch());
|
||||
@@ -633,6 +664,14 @@ bool WaypointMovementGenerator<Creature>::IsExactSplinePath() const
|
||||
return GetPath()->Flags.HasFlag(WaypointPathFlags::ExactSplinePath);
|
||||
}
|
||||
|
||||
bool WaypointMovementGenerator<Creature>::IsCyclic() const
|
||||
{
|
||||
return !IsFollowingPathBackwardsFromEndToStart()
|
||||
&& IsExactSplinePath()
|
||||
&& _repeating
|
||||
&& GetPath()->ContinuousSegments.size() == 1;
|
||||
}
|
||||
|
||||
std::string WaypointMovementGenerator<Creature>::GetDebugInfo() const
|
||||
{
|
||||
return Trinity::StringFormat("{}\n{}",
|
||||
|
||||
@@ -84,6 +84,7 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat
|
||||
|
||||
bool IsFollowingPathBackwardsFromEndToStart() const;
|
||||
bool IsExactSplinePath() const;
|
||||
bool IsCyclic() const;
|
||||
|
||||
bool IsLoadedFromDB() const { return std::holds_alternative<WaypointPath const*>(_path); }
|
||||
|
||||
@@ -101,6 +102,7 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat
|
||||
TimeTracker _moveTimer;
|
||||
TimeTracker _nextMoveTime;
|
||||
std::vector<int32> _waypointTransitionSplinePoints;
|
||||
uint32 _waypointTransitionSplinePointsIndex;
|
||||
bool _isReturningToStart;
|
||||
};
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Movement
|
||||
// flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably
|
||||
Mask_No_Monster_Move = Done, // SKIP
|
||||
// Unused, not suported flags
|
||||
Mask_Unused = No_Spline | Enter_Cycle | Frozen | Unknown_0x100 | Unknown_0x20000 | Unknown_0x40000
|
||||
Mask_Unused = No_Spline | Frozen | Unknown_0x100 | Unknown_0x20000 | Unknown_0x40000
|
||||
| Unknown_0x800000 | FadeObject | UnlimitedSpeed | Unknown_0x40000000 | Unknown_0x80000000 // SKIP
|
||||
};
|
||||
|
||||
|
||||
@@ -372,7 +372,13 @@ void WorldPackets::Movement::CommonMovement::WriteCreateObjectSplineDataBlock(::
|
||||
if (!moveSpline.isCyclic()) // Destination
|
||||
dest = moveSpline.FinalDestination();
|
||||
else
|
||||
dest = G3D::Vector3::zero();
|
||||
{
|
||||
::Movement::MoveSpline::MySpline const& spline = moveSpline._Spline();
|
||||
if (spline.getPointCount() <= 1)
|
||||
dest = G3D::Vector3::zero();
|
||||
else
|
||||
dest = spline.getPoint(spline.last() - 1);
|
||||
}
|
||||
|
||||
data << dest.x << dest.y << dest.z;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user