def assembleDrivetrain(appearance, isPlayerVehicle):
    vehicleFilter = appearance.filter
    typeDescriptor = appearance.typeDescriptor
    PLAYER_UPDATE_PERIOD = 0.1
    NPC_UPDATE_PERIOD = 0.25
    engineState = appearance.createComponent(Vehicular.DetailedEngineState)
    engineState.vehicleSpeedLink = DataLinks.createFloatLink(vehicleFilter, 'averageSpeed')
    engineState.rotationSpeedLink = DataLinks.createFloatLink(vehicleFilter, 'averageRotationSpeed')
    engineState.vehicleMatrixLink = appearance.compoundModel.root
    speed_limits_0 = typeDescriptor.physics['speedLimits'][0]
    speed_limits_1 = typeDescriptor.physics['speedLimits'][1]
    rpm_min = typeDescriptor.engine.rpm_min
    rpm_max = typeDescriptor.engine.rpm_max
    rotation_speed_limit = typeDescriptor.physics['rotationSpeedLimit']
    max_climb_angle = math.acos(typeDescriptor.physics['minPlaneNormalY'])
    engineState.setVehicleParams(speed_limits_0, speed_limits_1, rotation_speed_limit, max_climb_angle, rpm_min, rpm_max, isPlayerVehicle)
    wheeledVehicle = False
    if typeDescriptor.chassis.generalWheelsAnimatorConfig is not None:
        wheeledVehicle = typeDescriptor.chassis.generalWheelsAnimatorConfig.isWheeledVehicle()
    if wheeledVehicle and isPlayerVehicle:
        gearShiftMap = (((1e-05, rpm_min * 1.2, rpm_max * 0.98),
          (0.15 * speed_limits_0, rpm_min * 1.7, rpm_max * 0.98),
          (0.5 * speed_limits_0, rpm_min * 2.2, rpm_max * 0.98),
          (0.7 * speed_limits_0, rpm_max * 0.7, rpm_max * 0.9)), ((0.01, rpm_min * 1.2, rpm_max * 0.98),))
        gearbox = appearance.createComponent(Vehicular.GearBox, speed_limits_0, speed_limits_1, rpm_min, rpm_max, gearShiftMap)
        gearbox.engineModeLink = DataLinks.createIntLink(engineState, 'mode')
        gearbox.vehicleSpeedLink = DataLinks.createFloatLink(vehicleFilter, 'averageSpeed')
        gearbox.flyingLink = DataLinks.createBoolLink(appearance.flyingInfoProvider, 'isFlying')
    else:
        gearbox = None
    if isPlayerVehicle:
        if gearbox is not None:
            engineState.physicRPMLink = lambda : gearbox.rpm
            engineState.physicGearLink = lambda : gearbox.gear
        elif not IS_EDITOR:
            p = BigWorld.player()
            engineState.physicRPMLink = lambda : WoT.unpackAuxVehiclePhysicsData(p.ownVehicleAuxPhysicsData)[5]
            engineState.physicGearLink = lambda : BigWorld.player().ownVehicleGear
    else:
        engineState.physicRPMLink = None
        engineState.physicGearLink = None
    engineState.updatePeriod = PLAYER_UPDATE_PERIOD if isPlayerVehicle else NPC_UPDATE_PERIOD
    return (engineState, gearbox)