From 60ad9da7b562af0247885fba49ac8d62edfe57ea Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Sun, 10 Nov 2024 21:52:46 -0500 Subject: [PATCH] Core/Movement: Implemented cyclic waypoint movement Port From (https://github.com/TrinityCore/TrinityCore/commit/222a80a6d62410eae6fa46dbdc60309f1728653a) --- .../Constants/Movement/SplineConst.cs | 2 +- .../Movement/Generators/WaypointMovement.cs | 48 ++++++++++++++++--- .../Networking/Packets/MovementPackets.cs | 8 +++- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Source/Framework/Constants/Movement/SplineConst.cs b/Source/Framework/Constants/Movement/SplineConst.cs index 5fe543d26..25547880a 100644 --- a/Source/Framework/Constants/Movement/SplineConst.cs +++ b/Source/Framework/Constants/Movement/SplineConst.cs @@ -53,7 +53,7 @@ namespace Framework.Constants // flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably MaskNoMonsterMove = Done, // Unused, not suported flags - MaskUnused = NoSpline | EnterCycle | Frozen | Unknown_0x100 | Unknown_0x20000 | Unknown_0x40000 + MaskUnused = NoSpline | Frozen | Unknown_0x100 | Unknown_0x20000 | Unknown_0x40000 | Unknown_0x800000 | FadeObject | UnlimitedSpeed | Unknown_0x40000000 | Unknown_0x80000000 } } diff --git a/Source/Game/Movement/Generators/WaypointMovement.cs b/Source/Game/Movement/Generators/WaypointMovement.cs index 1526a2f73..532d0816e 100644 --- a/Source/Game/Movement/Generators/WaypointMovement.cs +++ b/Source/Game/Movement/Generators/WaypointMovement.cs @@ -31,6 +31,7 @@ namespace Game.Movement TimeTracker _moveTimer; TimeTracker _nextMoveTime; List _waypointTransitionSplinePoints = new(); + int _waypointTransitionSplinePointsIndex; bool _isReturningToStart; static TimeSpan SEND_NEXT_POINT_EARLY_DELTA = TimeSpan.FromMilliseconds(1500); @@ -223,7 +224,7 @@ namespace Game.Movement } // 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()) @@ -232,10 +233,10 @@ namespace Game.Movement // handle switching points in continuous segments if (IsExactSplinePath()) { - if (_waypointTransitionSplinePoints.Count > 1 && owner.MoveSpline.CurrentPathIdx() >= _waypointTransitionSplinePoints.First()) + if (_waypointTransitionSplinePointsIndex < _waypointTransitionSplinePoints.Count && owner.MoveSpline.CurrentPathIdx() >= _waypointTransitionSplinePoints[_waypointTransitionSplinePointsIndex]) { OnArrived(owner); - _waypointTransitionSplinePoints.Remove(_waypointTransitionSplinePoints.First()); + ++_waypointTransitionSplinePointsIndex; if (ComputeNextNode()) { CreatureAI ai = owner.GetAI(); @@ -423,18 +424,34 @@ namespace Game.Movement Cypher.Assert(_currentNode < _path.Nodes.Count, $"WaypointMovementGenerator.StartMove: tried to reference a node id ({_currentNode}) which is not included in path ({_path.Id})"); WaypointNode lastWaypointForSegment = _path.Nodes[_currentNode]; + bool isCyclic = IsCyclic(); List points = new(); if (IsExactSplinePath()) - CreateMergedPath(owner, _path, previousNode, _currentNode, _isReturningToStart, false, - points, _waypointTransitionSplinePoints, ref lastWaypointForSegment); + CreateMergedPath(owner, _path, previousNode, _currentNode, _isReturningToStart, false, isCyclic, points, _waypointTransitionSplinePoints, ref lastWaypointForSegment); else CreateSingularPointPath(owner, _path, _currentNode, _generatePath, points, _waypointTransitionSplinePoints); + _waypointTransitionSplinePointsIndex = 0; + RemoveFlag(MovementGeneratorFlags.Transitory | MovementGeneratorFlags.InformEnabled | MovementGeneratorFlags.TimedPaused); owner.AddUnitState(UnitState.RoamingMove); + if (isCyclic) + { + bool isFirstCycle = relaunch || owner.MoveSpline.Finalized() || !owner.MoveSpline.IsCyclic(); + if (!isFirstCycle) + { + for (var i = 0; i < _waypointTransitionSplinePoints.Count; ++i) + --_waypointTransitionSplinePoints[i]; + + // cyclic paths are using identical duration to first cycle with EnterCycle + _moveTimer.Reset(TimeSpan.FromMilliseconds(owner.MoveSpline.Duration())); + return; + } + } + MoveSplineInit init = new(owner); //! If creature is on transport, we assume waypoints set in DB are already transport offsets @@ -485,6 +502,9 @@ namespace Game.Movement if (_speed.HasValue) init.SetVelocity(_speed.Value); + if (isCyclic) + init.SetCyclic(); + if (IsExactSplinePath() && points.Count > 2 && owner.CanFly()) init.SetSmooth(); @@ -549,6 +569,14 @@ namespace Game.Movement return _path.Flags.HasFlag(WaypointPathFlags.ExactSplinePath); } + bool IsCyclic() + { + return !IsFollowingPathBackwardsFromEndToStart() + && IsExactSplinePath() + && _repeating + && _path.ContinuousSegments.Count == 1; + } + public override string GetDebugInfo() { return $"Current Node: {_currentNode}\n{base.GetDebugInfo()}"; @@ -595,7 +623,7 @@ namespace Game.Movement waypointTransitionSplinePoints.Add(points.Count - 1); } - void CreateMergedPath(Unit owner, WaypointPath path, int previousNode, int currentNode, bool isReturningToStart, bool generatePath, List points, List waypointTransitionSplinePoints, ref WaypointNode lastWaypointOnPath) + void CreateMergedPath(Unit owner, WaypointPath path, int previousNode, int currentNode, bool isReturningToStart, bool generatePath, bool isCyclic, List points, List waypointTransitionSplinePoints, ref WaypointNode lastWaypointOnPath) { var segment = new Func>(() => { @@ -654,6 +682,14 @@ namespace Game.Movement } }; + if (isCyclic) + { + // create new cyclic path starting at current node + List cyclicPath = path.Nodes; + fillPath(cyclicPath[currentNode..].Concat(cyclicPath[0..currentNode]).ToList()); + return; + } + if (!isReturningToStart) fillPath(segment); else diff --git a/Source/Game/Networking/Packets/MovementPackets.cs b/Source/Game/Networking/Packets/MovementPackets.cs index b7baa1e07..f323b7616 100644 --- a/Source/Game/Networking/Packets/MovementPackets.cs +++ b/Source/Game/Networking/Packets/MovementPackets.cs @@ -222,7 +222,13 @@ namespace Game.Networking.Packets if (!moveSpline.IsCyclic()) // Destination data.WriteVector3(moveSpline.FinalDestination()); else - data.WriteVector3(Vector3.Zero); + { + var spline = moveSpline.spline; + if (spline.GetPointCount() <= 1) + data.WriteVector3(Vector3.Zero); + else + data.WriteVector3(spline.GetPoint(spline.Last() - 1)); + } bool hasSplineMove = data.WriteBit(!moveSpline.Finalized() && !moveSpline.splineIsFacingOnly); data.FlushBits();