public override void Initialize(Unit owner)
        {
            RemoveFlag(MovementGeneratorFlags.InitializationPending | MovementGeneratorFlags.Deactivated);
            AddFlag(MovementGeneratorFlags.Initialized);

            if (_chainSize == 0)
            {
                Log.outError(LogFilter.Movement, $"SplineChainMovementGenerator::Initialize: couldn't initialize generator, referenced spline is empty! ({owner.GetGUID()})");
                return;
            }

            if (_nextIndex >= _chainSize)
            {
                Log.outWarn(LogFilter.Movement, $"SplineChainMovementGenerator::Initialize: couldn't initialize generator, _nextIndex is >= _chainSize ({owner.GetGUID()})");
                _msToNext = 0;
                return;
            }

            if (_nextFirstWP != 0) // this is a resumed movegen that has to start with a partial spline
            {
                if (HasFlag(MovementGeneratorFlags.Finalized))
                {
                    return;
                }

                SplineChainLink thisLink = _chain[_nextIndex];
                if (_nextFirstWP >= thisLink.Points.Count)
                {
                    Log.outError(LogFilter.Movement, $"SplineChainMovementGenerator::Initialize: attempted to resume spline chain from invalid resume state, _nextFirstWP >= path size (_nextIndex: {_nextIndex}, _nextFirstWP: {_nextFirstWP}). ({owner.GetGUID()})");
                    _nextFirstWP = (byte)(thisLink.Points.Count - 1);
                }

                owner.AddUnitState(UnitState.RoamingMove);
                Span <Vector3> partial = thisLink.Points.ToArray();
                SendPathSpline(owner, thisLink.Velocity, partial[(_nextFirstWP - 1)..]);
 public override void Initialize(Unit me)
 {
     if (_chainSize != 0)
     {
         if (_nextFirstWP != 0) // this is a resumed movegen that has to start with a partial spline
         {
             if (finished)
             {
                 return;
             }
             SplineChainLink thisLink = _chain[_nextIndex];
             if (_nextFirstWP >= thisLink.Points.Count)
             {
                 Log.outError(LogFilter.Movement, "{0}: Attempted to resume spline chain from invalid resume state ({1}, {2}).", me.GetGUID().ToString(), _nextIndex, _nextFirstWP);
                 _nextFirstWP = (byte)(thisLink.Points.Count - 1);
             }
             Span <Vector3> span = thisLink.Points.ToArray();
             SendPathSpline(me, span.Slice(_nextFirstWP - 1));
             Log.outDebug(LogFilter.Movement, "{0}: Resumed spline chain generator from resume state.", me.GetGUID().ToString());
             ++_nextIndex;
             if (_nextIndex >= _chainSize)
             {
                 _msToNext = 0;
             }
             else if (_msToNext == 0)
             {
                 _msToNext = 1;
             }
             _nextFirstWP = 0;
         }
         else
         {
             _msToNext = Math.Max(_chain[_nextIndex].TimeToNext, 1u);
             SendSplineFor(me, _nextIndex, _msToNext);
             ++_nextIndex;
             if (_nextIndex >= _chainSize)
             {
                 _msToNext = 0;
             }
         }
     }
     else
     {
         Log.outError(LogFilter.Movement, "SplineChainMovementGenerator.Initialize - empty spline chain passed for {0}.", me.GetGUID().ToString());
     }
 }
        void SendSplineFor(Unit me, int index, uint toNext)
        {
            Cypher.Assert(index < _chainSize);
            Log.outDebug(LogFilter.Movement, "{0}: Sending spline for {1}.", me.GetGUID().ToString(), index);

            SplineChainLink thisLink       = _chain[index];
            uint            actualDuration = SendPathSpline(me, new Span <Vector3>(thisLink.Points.ToArray()));

            if (actualDuration != thisLink.ExpectedDuration)
            {
                Log.outDebug(LogFilter.Movement, "{0}: Sent spline for {1}, duration is {2} ms. Expected was {3} ms (delta {4} ms). Adjusting.", me.GetGUID().ToString(), index, actualDuration, thisLink.ExpectedDuration, actualDuration - thisLink.ExpectedDuration);
                toNext = (uint)(actualDuration / thisLink.ExpectedDuration * toNext);
            }
            else
            {
                Log.outDebug(LogFilter.Movement, "{0}: Sent spline for {1}, duration is {2} ms.", me.GetGUID().ToString(), index, actualDuration);
            }
        }
 public override void Initialize(Unit me)
 {
     if (_chainSize != 0)
     {
         if (_nextFirstWP != 0) // this is a resumed movegen that has to start with a partial spline
         {
             if (finished)
             {
                 return;
             }
             SplineChainLink thisLink = _chain[_nextIndex];
             if (_nextFirstWP >= thisLink.Points.Count)
             {
                 Log.outError(LogFilter.Movement, "{0}: Attempted to resume spline chain from invalid resume state ({1}, {2}).", me.GetGUID().ToString(), _nextIndex, _nextFirstWP);
                 _nextFirstWP = (byte)(thisLink.Points.Count - 1);
             }
             Span <Vector3> span = thisLink.Points.ToArray();
             SendPathSpline(me, span[(_nextFirstWP - 1)..]);