---
--- autor: Giants
--- edit: Ziuta (xXx)
--- new 712-714 line
---

source("dataS/scripts/vehicles/specializations/AnimatedVehicleStartEvent.lua")
source("dataS/scripts/vehicles/specializations/AnimatedVehicleStopEvent.lua")
AnimatedVehicle = {}
function AnimatedVehicle.prerequisitesPresent(specializations)
  return true
end
function AnimatedVehicle:load(xmlFile)
  self.playAnimation = SpecializationUtil.callSpecializationsFunction("playAnimation")
  self.stopAnimation = SpecializationUtil.callSpecializationsFunction("stopAnimation")
  self.getIsAnimationPlaying = AnimatedVehicle.getIsAnimationPlaying
  self.getRealAnimationTime = AnimatedVehicle.getRealAnimationTime
  self.setRealAnimationTime = SpecializationUtil.callSpecializationsFunction("setRealAnimationTime")
  self.getAnimationTime = AnimatedVehicle.getAnimationTime
  self.getAnimationDuration = AnimatedVehicle.getAnimationDuration
  self.setAnimationTime = SpecializationUtil.callSpecializationsFunction("setAnimationTime")
  self.setAnimationStopTime = SpecializationUtil.callSpecializationsFunction("setAnimationStopTime")
  self.setAnimationSpeed = SpecializationUtil.callSpecializationsFunction("setAnimationSpeed")
  self.animations = {}
  local i = 0
  while true do
    do
      local key = string.format("vehicle.animations.animation(%d)", i)
      if not hasXMLProperty(xmlFile, key) then
        break
      end
      local name = getXMLString(xmlFile, key .. "#name")
      if name ~= nil then
        local animation = {}
        animation.name = name
        animation.parts = {}
        animation.currentTime = 0
        animation.currentSpeed = 1
        local partI = 0
        while true do
          do
            local partKey = key .. string.format(".part(%d)", partI)
            if not hasXMLProperty(xmlFile, partKey) then
              break
            end
            local node = Utils.indexToObject(self.components, getXMLString(xmlFile, partKey .. "#node"))
            local startTime = getXMLFloat(xmlFile, partKey .. "#startTime")
            local duration = getXMLFloat(xmlFile, partKey .. "#duration")
            local endTime = getXMLFloat(xmlFile, partKey .. "#endTime")
            local startRot = Utils.getRadiansFromString(getXMLString(xmlFile, partKey .. "#startRot"), 3)
            local endRot = Utils.getRadiansFromString(getXMLString(xmlFile, partKey .. "#endRot"), 3)
            local startTrans = Utils.getVectorNFromString(getXMLString(xmlFile, partKey .. "#startTrans"), 3)
            local endTrans = Utils.getVectorNFromString(getXMLString(xmlFile, partKey .. "#endTrans"), 3)
            local startScale = Utils.getVectorNFromString(getXMLString(xmlFile, partKey .. "#startScale"), 3)
            local endScale = Utils.getVectorNFromString(getXMLString(xmlFile, partKey .. "#endScale"), 3)
            local visibility = getXMLBool(xmlFile, partKey .. "#visibility")
            local componentJointIndex = getXMLInt(xmlFile, partKey .. "#componentJointIndex")
            local componentJoint
            if componentJointIndex ~= nil then
              componentJoint = self.componentJoints[componentJointIndex + 1]
            end
            local startRotLimit = Utils.getRadiansFromString(getXMLString(xmlFile, partKey .. "#startRotLimit"), 3)
            local endRotLimit = Utils.getRadiansFromString(getXMLString(xmlFile, partKey .. "#endRotLimit"), 3)
            local startTransLimit = Utils.getVectorNFromString(getXMLString(xmlFile, partKey .. "#startTransLimit"), 3)
            local endTransLimit = Utils.getVectorNFromString(getXMLString(xmlFile, partKey .. "#endTransLimit"), 3)
            if startTime ~= nil and (duration ~= nil or endTime ~= nil) and (node ~= nil and (endRot ~= nil or endTrans ~= nil or endScale ~= nil or visibility ~= nil) or componentJoint ~= nil and (endRotLimit ~= nil or endTransLimit ~= nil)) then
              if endTime ~= nil then
                duration = endTime - startTime
              end
              local part = {}
              part.node = node
              part.startTime = startTime * 1000
              part.duration = duration * 1000
              if node ~= nil then
                if endRot ~= nil then
                  part.startRot = startRot
                  part.endRot = endRot
                end
                if endTrans ~= nil then
                  part.startTrans = startTrans
                  part.endTrans = endTrans
                end
                if endScale ~= nil then
                  part.startScale = startScale
                  part.endScale = endScale
                end
                part.visibility = visibility
              end
              if self.isServer and componentJoint ~= nil then
                if endRotLimit ~= nil then
                  part.componentJoint = componentJoint
                  part.startRotLimit = startRotLimit
                  part.endRotLimit = endRotLimit
                end
                if endTransLimit ~= nil then
                  part.componentJoint = componentJoint
                  part.startTransLimit = startTransLimit
                  part.endTransLimit = endTransLimit
                end
              end
              table.insert(animation.parts, part)
            end
            partI = partI + 1
          end
        end
        animation.partsReverse = {}
        for _, part in ipairs(animation.parts) do
          table.insert(animation.partsReverse, part)
        end
        table.sort(animation.parts, AnimatedVehicle.animPartSorter)
        table.sort(animation.partsReverse, AnimatedVehicle.animPartSorterReverse)
        AnimatedVehicle.initializeParts(self, animation)
        animation.currentPartIndex = 1
        animation.duration = 0
        for _, part in ipairs(animation.parts) do
          animation.duration = math.max(animation.duration, part.startTime + part.duration)
        end
        self.animations[name] = animation
      end
      i = i + 1
    end
  end
  self.activeAnimations = {}
end
function AnimatedVehicle:initializeParts(animation)
  local numParts = table.getn(animation.parts)
  for i = 1, numParts do
    local part = animation.parts[i]
    if part.endRot ~= nil then
      for j = i + 1, numParts do
        local part2 = animation.parts[j]
        if part.node == part2.node and part2.endRot ~= nil then
          if part.startTime + part.duration > part2.startTime + 0.001 then
            print("Warning: overlapping rotation parts for node " .. getName(part.node) .. " in " .. animation.name .. " " .. self.configFileName)
          end
          part.nextRotPart = part2
          part2.prevRotPart = part
          if part2.startRot == nil then
            part2.startRot = {
              part.endRot[1],
              part.endRot[2],
              part.endRot[3]
            }
          end
          break
        end
      end
    end
    if part.endTrans ~= nil then
      for j = i + 1, numParts do
        local part2 = animation.parts[j]
        if part.node == part2.node and part2.endTrans ~= nil then
          if part.startTime + part.duration > part2.startTime + 0.001 then
            print("Warning: overlapping translation parts for node " .. getName(part.node) .. " in " .. animation.name .. " " .. self.configFileName)
          end
          part.nextTransPart = part2
          part2.prevTransPart = part
          if part2.startTrans == nil then
            part2.startTrans = {
              part.endTrans[1],
              part.endTrans[2],
              part.endTrans[3]
            }
          end
          break
        end
      end
    end
    if part.endScale ~= nil then
      for j = i + 1, numParts do
        local part2 = animation.parts[j]
        if part.node == part2.node and part2.endScale ~= nil then
          if part.startTime + part.duration > part2.startTime + 0.001 then
            print("Warning: overlapping scale parts for node " .. getName(part.node) .. " in " .. animation.name .. " " .. self.configFileName)
          end
          part.nextScalePart = part2
          part2.prevScalePart = part
          if part2.startScale == nil then
            part2.startScale = {
              part.endScale[1],
              part.endScale[2],
              part.endScale[3]
            }
          end
          break
        end
      end
    end
    if self.isServer then
      if part.endRotLimit ~= nil then
        for j = i + 1, numParts do
          local part2 = animation.parts[j]
          if part.componentJoint == part2.componentJoint and part2.endRotLimit ~= nil then
            if part.startTime + part.duration > part2.startTime + 0.001 then
              print("Warning: overlapping joint rot limit parts for component joint " .. getName(part.componentJoint.node) .. " in " .. animation.name .. " " .. self.configFileName)
            end
            part.nextRotLimitPart = part2
            part2.prevRotLimitPart = part
            if part2.startRotLimit == nil then
              part2.startRotLimit = {
                part.endRotLimit[1],
                part.endRotLimit[2],
                part.endRotLimit[3]
              }
            end
            break
          end
        end
      end
      if part.endTransLimit ~= nil then
        for j = i + 1, numParts do
          local part2 = animation.parts[j]
          if part.componentJoint == part2.componentJoint and part2.endTransLimit ~= nil then
            if part.startTime + part.duration > part2.startTime + 0.001 then
              print("Warning: overlapping joint trans limit parts for component joint " .. getName(part.componentJoint.node) .. " in " .. animation.name .. " " .. self.configFileName)
            end
            part.nextTransLimitPart = part2
            part2.prevTransLimitPart = part
            if part2.startTransLimit == nil then
              part2.startTransLimit = {
                part.endTransLimit[1],
                part.endTransLimit[2],
                part.endTransLimit[3]
              }
            end
            break
          end
        end
      end
    end
  end
  for i = 1, numParts do
    local part = animation.parts[i]
    if part.endRot ~= nil and part.startRot == nil then
      local x, y, z = getRotation(part.node)
      part.startRot = {
        x,
        y,
        z
      }
    end
    if part.endTrans ~= nil and part.startTrans == nil then
      local x, y, z = getTranslation(part.node)
      part.startTrans = {
        x,
        y,
        z
      }
    end
    if part.endScale ~= nil and part.startScale == nil then
      local x, y, z = getScale(part.node)
      part.startScale = {
        x,
        y,
        z
      }
    end
    if self.isServer then
      if part.endRotLimit ~= nil and part.startRotLimit == nil then
        local rotLimit = part.componentJoint.rotLimit
        part.startRotLimit = {
          rotLimit[1],
          rotLimit[2],
          rotLimit[3]
        }
      end
      if part.endTransLimit ~= nil and part.startTransLimit == nil then
        local transLimit = part.componentJoint.transLimit
        part.startTransLimit = {
          transLimit[1],
          transLimit[2],
          transLimit[3]
        }
      end
    end
  end
end
function AnimatedVehicle:delete()
end
function AnimatedVehicle:readStream(streamId, connection)
end
function AnimatedVehicle:writeStream(streamId, connection)
end
function AnimatedVehicle:readUpdateStream(streamId, timestamp, connection)
end
function AnimatedVehicle:writeUpdateStream(streamId, connection, dirtyMask)
end
function AnimatedVehicle:mouseEvent(posX, posY, isDown, isUp, button)
end
function AnimatedVehicle:keyEvent(unicode, sym, modifier, isDown)
end
function AnimatedVehicle:update(dt)
  AnimatedVehicle.updateAnimations(self, dt)
end
function AnimatedVehicle:updateTick(dt)
end
function AnimatedVehicle:draw()
end
function AnimatedVehicle:onDetach()
end
function AnimatedVehicle:onLeave()
end
function AnimatedVehicle:onDeactivate()
end
function AnimatedVehicle:onDeactivateSounds()
end
function AnimatedVehicle:playAnimation(name, speed, animTime, noEventSend)
  local animation = self.animations[name]
  if animation ~= nil then
    if speed == nil then
      speed = animation.currentSpeed
    end
    if animTime == nil then
      if self:getIsAnimationPlaying(name) then
        animTime = self:getAnimationTime(name)
      elseif speed > 0 then
        animTime = 0
      else
        animTime = 1
      end
    end
    if noEventSend == nil or noEventSend == false then
      if g_server ~= nil then
        g_server:broadcastEvent(AnimatedVehicleStartEvent:new(self, name, speed, animTime), nil, nil, self)
      else
        g_client:getServerConnection():sendEvent(AnimatedVehicleStartEvent:new(self, name, speed, animTime))
      end
    end
    self.activeAnimations[name] = animation
    animation.currentSpeed = speed
    animation.currentTime = animTime * animation.duration
    AnimatedVehicle.findCurrentPartIndex(animation)
    for _, part in ipairs(animation.parts) do
      part.curRot = nil
      part.speedRot = nil
      part.curTrans = nil
      part.speedTrans = nil
      part.curScale = nil
      part.speedScale = nil
      part.curVisibility = nil
      part.curRotLimit = nil
      part.speedRotLimit = nil
      part.curTransLimit = nil
      part.speedTransLimit = nil
    end
  end
end
function AnimatedVehicle:stopAnimation(name, noEventSend)
  if noEventSend == nil or noEventSend == false then
    if g_server ~= nil then
      g_server:broadcastEvent(AnimatedVehicleStopEvent:new(self, name), nil, nil, self)
    else
      g_client:getServerConnection():sendEvent(AnimatedVehicleStopEvent:new(self, name))
    end
  end
  local animation = self.animations[name]
  if animation ~= nil then
    animation.stopTime = nil
  end
  self.activeAnimations[name] = nil
end
function AnimatedVehicle:getIsAnimationPlaying(name)
  return self.activeAnimations[name] ~= nil
end
function AnimatedVehicle:getRealAnimationTime(name)
  local animation = self.animations[name]
  if animation ~= nil then
    return animation.currentTime
  end
  return 0
end
function AnimatedVehicle:setRealAnimationTime(name, animTime)
  local animation = self.animations[name]
  if animation ~= nil then
    animation.currentTime = animTime
  end
end
function AnimatedVehicle:getAnimationTime(name)
  local animation = self.animations[name]
  if animation ~= nil then
    return animation.currentTime / animation.duration
  end
  return 0
end
function AnimatedVehicle:getAnimationDuration(name)
  local animation = self.animations[name]
  if animation ~= nil then
    return animation.duration
  end
  return 1
end
function AnimatedVehicle:setAnimationSpeed(name, speed)
  local animation = self.animations[name]
  if animation ~= nil then
    local speedReversed = false
    if animation.currentSpeed > 0 ~= (speed > 0) then
      speedReversed = true
    end
    animation.currentSpeed = speed
    if self:getIsAnimationPlaying(name) and speedReversed then
      AnimatedVehicle.findCurrentPartIndex(animation)
      for _, part in ipairs(animation.parts) do
        part.curRot = nil
        part.speedRot = nil
        part.curTrans = nil
        part.speedTrans = nil
        part.curScale = nil
        part.speedScale = nil
        part.curVisibility = nil
        part.curRotLimit = nil
        part.speedRotLimit = nil
        part.curTransLimit = nil
        part.speedTransLimit = nil
      end
    end
  end
end
function AnimatedVehicle:setAnimationStopTime(name, stopTime)
  local animation = self.animations[name]
  if animation ~= nil then
    animation.stopTime = stopTime * animation.duration
  end
end
function AnimatedVehicle.animPartSorter(a, b)
  if a.startTime < b.startTime then
    return true
  elseif a.startTime == b.startTime then
    return a.duration < b.duration
  end
  return false
end
function AnimatedVehicle.animPartSorterReverse(a, b)
  local endTimeA = a.startTime + a.duration
  local endTimeB = b.startTime + b.duration
  if endTimeA > endTimeB then
    return true
  elseif endTimeA == endTimeB then
    return a.startTime > b.startTime
  end
  return false
end
function AnimatedVehicle.getMovedLimitedValue(currentValue, destValue, speed, dt)
  local limitF = math.min
  if destValue < currentValue then
    limitF = math.max
  elseif destValue == currentValue then
    return currentValue
  end
  local ret = limitF(currentValue + speed * dt, destValue)
  return ret
end
function AnimatedVehicle.setMovedLimitedValues3(currentValues, destValues, speeds, dt)
  local hasChanged = false
  for i = 1, 3 do
    local newValue = AnimatedVehicle.getMovedLimitedValue(currentValues[i], destValues[i], speeds[i], dt)
    if currentValues[i] ~= newValue then
      hasChanged = true
      currentValues[i] = newValue
    end
  end
  return hasChanged
end
function AnimatedVehicle.findCurrentPartIndex(animation)
  if animation.currentSpeed > 0 then
    animation.currentPartIndex = 1
    for i, part in ipairs(animation.parts) do
      if part.startTime <= animation.currentTime then
        animation.currentPartIndex = i
        break
      end
    end
  else
    animation.currentPartIndex = 1
    for i, part in ipairs(animation.partsReverse) do
      if part.startTime + part.duration >= animation.currentTime then
        animation.currentPartIndex = i
        break
      end
    end
  end
end
function AnimatedVehicle.getDurationToEndOfPart(part, anim)
  if anim.currentSpeed > 0 then
    return part.startTime + part.duration - anim.currentTime
  else
    return anim.currentTime - part.startTime
  end
end
function AnimatedVehicle.getNextPartIsPlaying(nextPart, prevPart, anim, default)
  if anim.currentSpeed > 0 then
    if nextPart ~= nil then
      return nextPart.startTime > anim.currentTime
    end
  elseif prevPart ~= nil then
    return prevPart.startTime + prevPart.duration < anim.currentTime
  end
  return default
end
function AnimatedVehicle:updateAnimations(dt)
  for name, anim in pairs(self.activeAnimations) do
    anim.currentTime = anim.currentTime + dt * anim.currentSpeed
    local absSpeed = math.abs(anim.currentSpeed)
    local dtToUse = dt * absSpeed
    local stopAnim = false
    if anim.stopTime ~= nil then
      if anim.currentSpeed > 0 then
        if anim.stopTime <= anim.currentTime then
          dtToUse = dtToUse - (anim.currentTime - anim.stopTime)
          anim.currentTime = anim.stopTime
          stopAnim = true
        end
      elseif anim.stopTime >= anim.currentTime then
        dtToUse = dtToUse - (anim.stopTime - anim.currentTime)
        anim.currentTime = anim.stopTime
        stopAnim = true
      end
    end
    local numParts = table.getn(anim.parts)
    local parts = anim.parts
    if anim.currentSpeed < 0 then
      parts = anim.partsReverse
    end
    if dtToUse > 0 then
      local hasChanged = false
      local nothingToChangeYet = false
      for partI = anim.currentPartIndex, numParts do
        local part = parts[partI]
        local durationToEnd = AnimatedVehicle.getDurationToEndOfPart(part, anim)
        if durationToEnd > part.duration then
          nothingToChangeYet = true
          break
        end
        durationToEnd = durationToEnd + dtToUse
        local hasPartChanged = false
        if part.startRot ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextRotPart, part.prevRotPart, anim, true)) then
          local destRot = part.endRot
          if anim.currentSpeed < 0 then
            destRot = part.startRot
          end
          if part.curRot == nil then
            local x, y, z = getRotation(part.node)
            part.curRot = {
              x,
              y,
              z
            }
            local invDuration = 1 / math.max(durationToEnd, 0.001)
            part.speedRot = {
              (destRot[1] - x) * invDuration,
              (destRot[2] - y) * invDuration,
              (destRot[3] - z) * invDuration
            }
          end
          if AnimatedVehicle.setMovedLimitedValues3(part.curRot, destRot, part.speedRot, dtToUse) then
            setRotation(part.node, part.curRot[1], part.curRot[2], part.curRot[3])
            hasPartChanged = true
          end
        end
        if part.startTrans ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextTransPart, part.prevTransPart, anim, true)) then
          local destTrans = part.endTrans
          if anim.currentSpeed < 0 then
            destTrans = part.startTrans
          end
          if part.curTrans == nil then
            local x, y, z = getTranslation(part.node)
            part.curTrans = {
              x,
              y,
              z
            }
            local invDuration = 1 / math.max(durationToEnd, 0.001)
            part.speedTrans = {
              (destTrans[1] - x) * invDuration,
              (destTrans[2] - y) * invDuration,
              (destTrans[3] - z) * invDuration
            }
          end
          if AnimatedVehicle.setMovedLimitedValues3(part.curTrans, destTrans, part.speedTrans, dtToUse) then
            setTranslation(part.node, part.curTrans[1], part.curTrans[2], part.curTrans[3])
            hasPartChanged = true
          end
        end
        if part.startScale ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextScalePart, part.prevScalePart, anim, true)) then
          local destScale = part.endScale
          if anim.currentSpeed < 0 then
            destScale = part.startScale
          end
          if part.curScale == nil then
            local x, y, z = getScale(part.node)
            part.curScale = {
              x,
              y,
              z
            }
            local invDuration = 1 / math.max(durationToEnd, 0.001)
            part.speedScale = {
              (destScale[1] - x) * invDuration,
              (destScale[2] - y) * invDuration,
              (destScale[3] - z) * invDuration
            }
          end
          if AnimatedVehicle.setMovedLimitedValues3(part.curScale, destScale, part.speedScale, dtToUse) then
            setScale(part.node, part.curScale[1], part.curScale[2], part.curScale[3])
            hasPartChanged = true
          end
        end
        if part.visibility ~= nil then
          if part.curVisibility == nil then
            part.curVisibility = getVisibility(part.node)
          end
          if part.visibility ~= part.curVisibility then
            part.curVisibility = part.visibility
            setVisibility(part.node, part.visibility)
            hasPartChanged = true
          end
        end
        if self.isServer then
          if part.startRotLimit ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextRotLimitPart, part.prevRotLimitPart, anim, true)) then
            local destRotLimit = part.endRotLimit
            if anim.currentSpeed < 0 then
              destRotLimit = part.startRotLimit
            end
            if part.curRotLimit == nil then
              local x, y, z = unpack(part.componentJoint.rotLimit)
              part.curRotLimit = {
                x,
                y,
                z
              }
              local invDuration = 1 / math.max(durationToEnd, 0.001)
              part.speedRotLimit = {
                (destRotLimit[1] - x) * invDuration,
                (destRotLimit[2] - y) * invDuration,
                (destRotLimit[3] - z) * invDuration
              }
            end
            for i = 1, 3 do
              local newRotLimit = AnimatedVehicle.getMovedLimitedValue(part.curRotLimit[i], destRotLimit[i], part.speedRotLimit[i], dtToUse)
              if newRotLimit ~= part.curRotLimit[i] then
                part.curRotLimit[i] = newRotLimit
                self:setComponentJointRotLimit(part.componentJoint, i, newRotLimit)
                hasPartChanged = true
              end
            end
          end
          if part.startTransLimit ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextTransLimitPart, part.prevTransLimitPart, anim, true)) then
            local destTransLimit = part.endTransLimit
            if anim.currentSpeed < 0 then
              destTransLimit = part.startTransLimit
            end
            if part.curTransLimit == nil then
              local x, y, z = unpack(part.componentJoint.transLimit)
              part.curTransLimit = {
                x,
                y,
                z
              }
              local invDuration = 1 / math.max(durationToEnd, 0.001)
              part.speedTransLimit = {
                (destTransLimit[1] - x) * invDuration,
                (destTransLimit[2] - y) * invDuration,
                (destTransLimit[3] - z) * invDuration
              }
            end
            for i = 1, 3 do
              local newTransLimit = AnimatedVehicle.getMovedLimitedValue(part.curTransLimit[i], destTransLimit[i], part.speedTransLimit[i], dtToUse)
              if newRotLimit ~= part.curTransLimit[i] then
                part.curTransLimit[i] = newTransLimit
                self:setComponentJointTransLimit(part.componentJoint, i, newTransLimit)
                hasPartChanged = true
              end
            end
          end
        end
        if hasPartChanged then
          if self.setMovingToolDirty ~= nil then
            self:setMovingToolDirty(part.node)
          end
          hasChanged = true
        end
        if partI == anim.currentPartIndex and (anim.currentSpeed > 0 and part.startTime + part.duration < anim.currentTime or anim.currentSpeed <= 0 and part.startTime > anim.currentTime) then
          part.curRot = nil
          part.speedRot = nil
          part.curTrans = nil
          part.speedTrans = nil
          part.curScale = nil
          part.speedScale = nil
          part.curVisibility = nil
          part.curRotLimit = nil
          part.speedRotLimit = nil
          part.curTransLimit = nil
          part.speedTransLimit = nil
          anim.currentPartIndex = anim.currentPartIndex + 1
        end
      end
      if not nothingToChangeYet and not hasChanged and (anim.currentSpeed > 0 and anim.currentPartIndex == numParts or anim.currentSpeed < 0 and anim.currentPartIndex == 1) then
        if anim.currentSpeed > 0 then
          anim.currentTime = anim.duration
        else
          anim.currentTime = 0
        end
        anim.currentPartIndex = 0
      end
    end
    if stopAnim or numParts < anim.currentPartIndex or anim.currentPartIndex < 1 then
      anim.currentTime = math.min(math.max(anim.currentTime, 0), anim.duration)
      anim.stopTime = nil
      self.activeAnimations[name] = nil
    end
  end
end
------------- new -------------
function AnimatedVehicle:validateAttacherJoint(implement, jointDesc, dt)
    return true
end