bool SplineChainMovementGenerator::Update(Unit* owner, uint32 diff)
{
    if (!owner || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED))
        return false;

    // _msToNext being zero here means we're on the final spline
    if (!_msToNext)
    {
        if (owner->movespline->Finalized())
        {
            AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED);
            return false;
        }
        return true;
    }

    if (_msToNext <= diff)
    {
        // Send next spline
        TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::Update: sending spline on index %u (%u ms late). (%s)", _nextIndex, diff - _msToNext, owner->GetGUID().ToString().c_str());
        _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u);
        SendSplineFor(owner, _nextIndex, _msToNext);
        ++_nextIndex;
        if (_nextIndex >= _chainSize)
        {
            // We have reached the final spline, once it finalizes we should also finalize the movegen (start checking on next update)
            _msToNext = 0;
            return true;
        }
    }
    else
        _msToNext -= diff;

    return true;
}
bool SplineChainMovementGenerator::Update(Unit* me, uint32 diff)
{
    if (finished)
        return false;

    // _msToNext being zero here means we're on the final spline
    if (!_msToNext)
    {
        finished = me->movespline->Finalized();
        return !finished;
    }

    if (_msToNext <= diff)
    {
        // Send next spline
        TC_LOG_DEBUG("movement.splinechain", "%s: Should send spline %u (%u ms late).", me->GetGUID().ToString().c_str(), _nextIndex, diff - _msToNext);
        _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u);
        SendSplineFor(me, _nextIndex, _msToNext);
        ++_nextIndex;
        if (_nextIndex >= _chainSize)
        {
            // We have reached the final spline, once it finalizes we should also finalize the movegen (start checking on next update)
            _msToNext = 0;
            return true;
        }
    }
    else
        _msToNext -= diff;
    return true;
}
void SplineChainMovementGenerator::Initialize(Unit* owner)
{
    RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING | MOVEMENTGENERATOR_FLAG_DEACTIVATED);
    AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED);

    if (!_chainSize)
    {
        TC_LOG_ERROR("movement", "SplineChainMovementGenerator::Initialize: couldn't initialize generator, referenced spline is empty! (%s)", owner->GetGUID().ToString().c_str());
        return;
    }

    if (_nextFirstWP) // this is a resumed movegen that has to start with a partial spline
    {
        if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED))
            return;

        SplineChainLink const& thisLink = _chain[_nextIndex];
        if (_nextFirstWP >= thisLink.Points.size())
        {
            TC_LOG_ERROR("movement.splinechain", "SplineChainMovementGenerator::Initialize: attempted to resume spline chain from invalid resume state, _nextFirstWP >= path size (_nextIndex: %u, _nextFirstWP: %u). (%s)", _nextIndex, _nextFirstWP, owner->GetGUID().ToString().c_str());
            _nextFirstWP = thisLink.Points.size() - 1;
        }

        owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
        Movement::PointsArray partial(thisLink.Points.begin() + (_nextFirstWP-1), thisLink.Points.end());
        SendPathSpline(owner, partial);

        TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::Initialize: resumed spline chain generator from resume state. (%s)", owner->GetGUID().ToString().c_str());

        ++_nextIndex;
        if (_nextIndex >= _chainSize)
            _msToNext = 0;
        else if (!_msToNext)
            _msToNext = 1;
        _nextFirstWP = 0;
    }
    else
    {
        _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u);
        SendSplineFor(owner, _nextIndex, _msToNext);

        ++_nextIndex;
        if (_nextIndex >= _chainSize)
            _msToNext = 0;
    }
}
void SplineChainMovementGenerator::Initialize(Unit* me)
{
    if (_chainSize)
    {
        if (_nextFirstWP) // this is a resumed movegen that has to start with a partial spline
        {
            if (finished)
                return;
            SplineChainLink const& thisLink = _chain[_nextIndex];
            if (_nextFirstWP >= thisLink.Points.size())
            {
                TC_LOG_ERROR("movement.splinechain", "%s: Attempted to resume spline chain from invalid resume state (%u, %u).", me->GetGUID().ToString().c_str(), _nextIndex, _nextFirstWP);
                _nextFirstWP = thisLink.Points.size()-1;
            }
            Movement::PointsArray partial(thisLink.Points.begin() + (_nextFirstWP-1), thisLink.Points.end());
            SendPathSpline(me, partial);
            TC_LOG_DEBUG("movement.splinechain", "%s: Resumed spline chain generator from resume state.", me->GetGUID().ToString().c_str());
            ++_nextIndex;
            if (!_msToNext)
                _msToNext = 1;
            _nextFirstWP = 0;
        }
        else
        {
            _msToNext = std::max(_chain[_nextIndex].TimeToNext, 1u);
            SendSplineFor(me, _nextIndex, _msToNext);
            ++_nextIndex;
            if (_nextIndex >= _chainSize)
                _msToNext = 0;
        }
    }
    else
    {
        TC_LOG_ERROR("movement", "SplineChainMovementGenerator::Initialize - empty spline chain passed for %s.", me->GetGUID().ToString().c_str());
    }
}