@SubscribeEvent
  public void onEntityTick(MinecartUpdateEvent event) {
    EntityMinecart minecart = event.minecart;
    if (!canUpdateCart(minecart)) return;
    Vec3 cartPoint = new Vec3(minecart.posX, minecart.posY, minecart.posZ);

    List<BehaviourWrapper[]> wrappers = new ArrayList<>();
    for (BlockPos pos :
        BlockPos.getAllInBox(
            new BlockPos(cartPoint).add(-2, -2, -2), new BlockPos(cartPoint).add(2, 2, 2))) {
      IBlockState state = minecart.worldObj.getBlockState(pos);
      wrappers.add(TrackPathProvider.INSTANCE.getTracksAsArray(minecart.worldObj, pos, state));
    }
    double angDiff = Integer.MAX_VALUE;
    double posDiff = 2;
    BehaviourWrapper best = null;
    RayTraceTrackPath bestTrace = null;
    boolean reverse = false;
    for (BehaviourWrapper[] wrapperArray : wrappers) {
      for (BehaviourWrapper w : wrapperArray) {
        RayTraceTrackPath rayTrace =
            w.getPath().rayTrace(cartPoint.addVector(0, -0.5, 0), new Vec3(0, 1, 0));
        if (rayTrace == null) continue;
        if (rayTrace.distance > posDiff) continue;
        boolean rev = false;

        Vec3 cartAngle = new Vec3(minecart.motionX, minecart.motionY, minecart.motionZ).normalize();
        Vec3 pathAngle = w.getPath().direction(rayTrace.interp).normalize();
        if (cartAngle.distanceTo(pathAngle)
            > cartAngle.distanceTo(pathAngle.subtractReverse(new Vec3(0, 0, 0)))) {
          pathAngle = pathAngle.subtractReverse(new Vec3(0, 0, 0));
          rev = true;
        }

        double diff = cartAngle.distanceTo(pathAngle);
        if (diff > angDiff) continue;

        best = w;
        posDiff = rayTrace.distance;
        angDiff = rayTrace.distance;
        bestTrace = rayTrace;
        reverse = rev;
      }
    }
    if (best != null && bestTrace != null) {
      Vec3 pathDir = best.getPath().direction(bestTrace.interp).normalize();
      if (reverse) pathDir = pathDir.subtractReverse(new Vec3(0, 0, 0));
      Vec3 cartAngle = new Vec3(minecart.motionX, minecart.motionY, minecart.motionZ);
      double speed = cartAngle.lengthVector();
      speed = Math.min(speed, 0.2);
      minecart.motionX = pathDir.xCoord * speed;
      minecart.motionY = pathDir.yCoord * speed;
      minecart.motionZ = pathDir.zCoord * speed;

      Vec3 pathPos = bestTrace.closestPoint;
      minecart.posX = pathPos.xCoord + minecart.motionX;
      minecart.posY = pathPos.yCoord + minecart.motionY;
      minecart.posZ = pathPos.zCoord + minecart.motionZ;
    }
  }