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::SendSplineFor(Unit* owner, uint32 index, uint32& duration)
{
    ASSERT(index < _chainSize, "SplineChainMovementGenerator::SendSplineFor: referenced index (%u) higher than path size (%u)!", index, _chainSize);
    TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::SendSplineFor: sending spline on index: %u. (%s)", index, owner->GetGUID().ToString().c_str());

    SplineChainLink const& thisLink = _chain[index];
    uint32 actualDuration = SendPathSpline(owner, thisLink.Points);
    if (actualDuration != thisLink.ExpectedDuration)
    {
        TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::SendSplineFor: sent spline on index: %u, duration: %u ms. Expected duration: %u ms (delta %d ms). Adjusting. (%s)", index, actualDuration, thisLink.ExpectedDuration, int32(actualDuration) - int32(thisLink.ExpectedDuration), owner->GetGUID().ToString().c_str());
        duration = uint32(double(actualDuration) / double(thisLink.ExpectedDuration) * duration);
    }
    else
    {
        TC_LOG_DEBUG("movement.splinechain", "SplineChainMovementGenerator::SendSplineFor: sent spline on index %u, duration: %u ms. (%s)", index, actualDuration, owner->GetGUID().ToString().c_str());
    }
}
void SplineChainMovementGenerator::SendSplineFor(Unit* me, uint32 index, uint32& toNext)
{
    ASSERT(index < _chainSize);
    TC_LOG_DEBUG("movement.splinechain", "%s: Sending spline for %u.", me->GetGUID().ToString().c_str(), index);

    SplineChainLink const& thisLink = _chain[index];
    uint32 actualDuration = SendPathSpline(me, thisLink.Points);
    if (actualDuration != thisLink.ExpectedDuration)
    {
        TC_LOG_DEBUG("movement.splinechain", "%s: Sent spline for %u, duration is %u ms. Expected was %u ms (delta %d ms). Adjusting.", me->GetGUID().ToString().c_str(), index, actualDuration, thisLink.ExpectedDuration, int32(actualDuration) - int32(thisLink.ExpectedDuration));
        toNext = uint32(double(actualDuration)/double(thisLink.ExpectedDuration) * toNext);
    }
    else
    {
        TC_LOG_DEBUG("movement.splinechain", "%s: Sent spline for %u, duration is %u ms.", me->GetGUID().ToString().c_str(), index, actualDuration);
    }
}
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());
    }
}