diff options
Diffstat (limited to 'src')
4 files changed, 58 insertions, 11 deletions
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 84a1871a5c1..232ad771b16 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -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{}", diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index a214734db83..fb981f400cd 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 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; }; diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h index 7a8317aa04d..c33711c951c 100644 --- a/src/server/game/Movement/Spline/MoveSplineFlag.h +++ b/src/server/game/Movement/Spline/MoveSplineFlag.h @@ -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 }; diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index 7020519bffa..c9f9338cbc8 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -356,7 +356,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; |